65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET 2.0 中的设计时架构 - 第一部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (14投票s)

2009 年 5 月 13 日

CPOL

4分钟阅读

viewsIcon

51245

downloadIcon

1188

DesignSurface、IToolboxService 和 INameCreationService。

引言

在使用 Visual Studio .NET 时,我们很少会想到它之所以成为 WYSIWYG 编辑器背后的一些东西。我希望通过这个系列文章,能够让大家掌握 Microsoft .NET 2.0 提供的丰富功能,使我们能够创建自己的布局设计器。

CodeProject 上还有另一篇关于 DesignSurface 扩展的文章,可以在这里找到。

layout1.jpg

背景

我最近有机会为一个 Windows 应用程序开发一个布局编辑器。概念很简单,就是有一个 GUI 工具来创建窗体布局,并将其保存为 XML 格式以便进一步处理。有趣的部分是如何在我编写自己的编辑器时获得 VS.NET 那样的功能和友好性。Microsoft .NET 框架拯救了我!否则,我将不得不从头开始编写所有内容。我计划每周发布一篇文章,所以请耐心等待下一篇。

Microsoft .NET 和设计器支持

Microsoft .NET 提供了 System.Design.dll 程序集。该程序集包含一些重要的类,使用户能够编写自己的布局设计器。在本系列中,我们将逐一讨论这些类,同时不断为我们的布局设计器添加更多功能。

DesignSurface 类

现在,让我们来谈谈 DesignSurface 类。这是你的布局设计器的基本容器。正如我们需要一个表面来设计自己的窗体一样,DesignSurface 类使用户能够拥有自己的容器。下面是 DesignSurface 的定义(从元数据中提取)

public class DesignSurface : IDisposable, IServiceProvider
{
    public DesignSurface();
    public DesignSurface(IServiceProvider parentProvider);
    public DesignSurface(Type rootComponentType);
    public DesignSurface(IServiceProvider parentProvider, Type rootComponentType);
    .
    .
    .
    .
    .

有关此类的更多信息,请参阅MSDN 文档

下面是一个实例化 DesignSurface 类的简短代码片段。这段代码创建一个表面并将其添加到示例应用程序的主窗体上。

namespace L1
{
    public partial class DemoForm : Form
    {
        private DesignSurface m_designSurface;
        
        public DemoForm()
        {
            InitializeComponent();

            // Initialize our demo appliaction
            m_designSurface = new DesignSurface(typeof(Form));
        }

        private void DemoForm_Load(object sender, EventArgs e)
        {
            // Add the design surface
            Control designView = m_designSurface.View as Control;
            designView.Dock = DockStyle.Fill;
            this.Controls.Add(designView);
        }
    }
}

代码

// Initialize our demo appliaction
m_designSurface = new DesignSurface(typeof(Form));

通过创建基本组件(即 Form)来添加 DesignSurface。所以,在这里,我们正在我们的应用程序中设计一个窗体。

DesignSurface 提供的服务

我们得到了一个用于设计组件的表面,并且为了访问该表面的控件,我们需要有服务。这些服务用于帮助我们访问表面上的各个组件、获取事件和其他信息,例如有关所选组件的信息等等。这些服务有两种类型:可替换和不可替换。

可替换服务

我们可以将这些服务称为可替换服务,因为我们可以插入自己的实现并用自己的组件替换它们。以下是可用的可替换服务。要替换这些服务,我们必须对 DesignSurface 类进行子类化,因为它在构造函数中会添加默认服务。这些服务可以通过 ServiceContainer 属性访问,并且可以通过重写它并添加我们自己的实现来替换。

  • IExtenderProviderService
  • IExtenderListService
  • ITypeDescriptorFilterService
  • ISelectionService
  • IReferenceService
  • DesignSurface
  • DesignerOptionService

不可替换服务

这些服务不能被替换,并且是默认提供的。以下是列表

  • IComponentChangeService
  • IDesignerHost
  • IContainer
  • IServiceContainer

IDesignerHost 服务

对于我们的小演示应用程序,我们将使用此服务。IDesignerHost 服务用于访问/管理设计表面上可用的组件。这是不可替换的服务,要获取对默认实现的引用,我们必须调用设计表面的 GetService() 方法。下面是代码片段

// Initialize our demo appliaction
m_designSurface = new DesignSurface(typeof(Form));
IDesignerHost designerHost = 
  m_designSurface.GetService(typeof(IDesignerHost)) as IDesignerHost;
Form templateForm = designerHost.RootComponent as Form;
// Set the default properties of our base template form
templateForm.Text = "Demo Form";

这段代码创建了一个 DesignSurface,并通过获取对 IDesignerHost 的引用,我们能够访问表面上可用的组件。在这里,我们有 RootComponent,它是一个 Form。拥有对根组件的引用,我们可以修改其属性,在这里,我们将 Text 属性设置为“Demo Form”。

注册您自己的服务 - IServiceContainer

顾名思义,服务容器是注册了服务的容器。IServiceContainer 接口提供了添加/修改/删除已注册服务的机制。为了在设计模板上绘制控件,我们必须重写一项服务,那就是工具箱。要注册我们自己的工具箱实现,我们需要对服务容器的引用,并且可以使用 DesignSurfaceGetService() 方法来检索它。

//Get the service container
IServiceContainer serviceContainer = 
    m_designSurface.GetService(typeof(IServiceContainer)) as IServiceContainer;

在模板窗体上添加控件 - IToolboxServiceToolboxService

我们已经有了窗体,现在可以注册新服务了。现在我们将看看如何在此窗体上添加组件。为了方便使用,.NET 框架提供了一个接口:IToolboxService 接口。为了方便开发,.NET 框架有一个 ToolboxService 抽象类,其中包含重要方法的实现。现在,我们将创建自己的名为 DemoToolboxService 的工具箱服务。它或多或少是一个哑类,用于工具箱的基本实现。我们需要它来让我们的一个小应用程序工作,并将在我的第二篇文章中详细讨论。

namespace L1
{
    class DemoToolboxService : ToolboxService
    {
        // Categories
        CategoryNameCollection m_categoryNameCollection;

        protected override CategoryNameCollection CategoryNames
        {
            get
            {
                if (m_categoryNameCollection == null)
                    m_categoryNameCollection = 
                      new CategoryNameCollection(new string[] { "Controls" });

                return m_categoryNameCollection;
            }
        }

        protected override System.Collections.IList 
                  GetItemContainers(string categoryName)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        protected override System.Collections.IList GetItemContainers()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        protected override void Refresh()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        protected override string SelectedCategory
        {
            get
            {
                return "Controls";
            }
            set
            {
                // Need not to set any thing right now
            }
        }

        protected override ToolboxItemContainer SelectedItemContainer
        {
            get
            {
                return new ToolboxItemContainer(new ToolboxItem(typeof(Button)));
            }
            set
            {
                // Need not to set any thing right now
            }
        }
    }
}

DemoToolboxService 中,我们只有一个类别的控件,那就是“控件”。用户无法选择任何内容,并且只能绘制按钮,因为工具箱尚未实现。

错误!

使用此应用程序时,你注意到什么了吗??按钮上的名称在哪里?我们如何提供它?尝试找出答案!或者等到下一篇文章。

© . All rights reserved.