存档

2008年存档

Silverlight工具包的设计时功能的实现

12月28日,2008年 4评论

介绍

这是我的Silverlight设计时功能系列的第二个职位。 Silverlight工具包的设计后的第一时间功能显示设计时功能的Silverlight工具包控制。 这篇文章解释它是如何实现的。 希望这篇文章可以帮助解释我们的源代码,演示了如何实现Silverlight的设计时功能,并提供了一​​个框架和源代码,读者可以直接在自己的项目使用。

概观

下载“Silverlight工具包-二进制文件,样本,文档,单元测试和源” 2008年12月发布 ,在Visual Studio中打开SourceSilverlight.Controls.sln,有12个设计项目,设计方案文件夹,三下,我们将看到每个控制大会。

Silverlight.Controls.sln在Visual Studio中

采取控制示例项目,设计项目有三个:

  • Controls.Design:的构建Windows.Controls.Design.dll,其中包含设计时功能的Visual Studio和Expression Blend共享。
  • Controls.Expression.Design:的构建Windows.Controls.Expression.Design.dll,其中包含了Expression Blend中的设计时功能。
  • Controls.VisualStudio.Design:的构建Windows.Controls.VisualStudio.Design.dll,其中包含Visual Studio设计时功能。

还有一个Design.Common,包含两个文件的:Extensions.cs和MetadataBase.cs,这是所有设计项目共享文件夹。

我们强烈建议您阅读贾斯汀天使的博客后Silverlight设计时的可扩展性 :提供良好的背景/概述Silverlight设计时的可扩展性,是基于以下实施信息。

项目

全部12个设计项目,遵循相同的执行模式,所以我只会使用Control.Design项目解释他们所有。

加载到Visual Studio中的第一次Silverlight.Controls.sln源目录下,我们会看到象下面这样的画面:

Silverlight.Controls.Design.csproj在Visual Studio中

  • Controls.Design有一个控制项目的项目依赖。 这种依赖性确保控制项目建成第一,Controls.Design有一个控制项目建成Microsoft.Windows.Controls大会的职权。 大会总是一个设计时参考运行时组件,它提供了设计时功能。
  • Controls.Design的引用Microsoft.Windows.Design&Microsoft.Windows.Design.Extensibility集会,这两者是根据目录%DevEnvDir的的%PublicAssemblies(C:计划FilesMicrosoft Visual Studio中我的笔记本电脑上的9.0Common7IDEPublicAssemblies)。 设计时间大会常引用这两个组件,它提供了设计者的可扩展性框架。 大会总是一个设计时参考系统组装,其中包含System.ComponentModel命名空间,其中许多元数据属性(类似的CategoryAttribute,DescriptionAttribute)定义。
  • Controls.Design参考System.Windows大会。 我们可以看到在Controls.Design.csproj参考:

    <reference Include="System.Windows, Version=2.0.5.0,Culture=neutral, PublicKeyToken=7cec85d7bea7798e, processorArchitecture=MSIL">
    <SpecificVersion>假</ SpecificVersion>
    <HintPath> .. BinariesSystem.Windows.dll </ HintPath>
    <Private>假</私人>
    </参考>

    请注意:

    • Control.Design是一个Windows类库项目,而不是一个Silverlight项目;产生Microsoft.Windows.Controls.Design.dll是NET程序集内部设计师如Visual Studio或Expression Blend中,而不是内部运行一个Silverlight大会在桌面上运行。一个浏览器,甚至,虽然Microsoft.Windows.Controls.Design.dll是设计时间为Silverlight运行时组件Microsoft.Windows.Controls.dll大会。
    • 引用System.Windows大会实际上是一个Silverlight程序集(版本2.0.5.0)。 System.Windows大会不得Silverlight控件的所有设计项目的需要。 主要是因为我们需要的GetMemberName <T>这里(表达功能<T,物件> expr的)在Extension.cs的方法的,我们将讨论后更后。 。NET和Silverlight的参考组合创建各种有趣的问题,我们很快会看到。

      下面ILDASM截图显示NET和Silverlight组件Microsoft.Windows.Controls.Design.dll混合引用。
      ILDASM Microsoft.Windows.Controls.Design.dll Microsoft.Windows.Controls.Design集清单

      • VER 2:0:21024:1838是Silverlight工具包2008年12月发布的版本号。
      • VER 3:5:0:0是版本号。NET框架3.5。
      • VER 2:0:0:0是为Silverlight 2.0的版本号。
    • 当您第一次加载到Visual Studio Controls.Design项目,有一个“引用的组件”System.Windows“无法找到”警告旁边System.Windows大会在项目窗口,并在错误列表“窗口中引用过。 这是,因为Controls.Design NET项目,而不是Silverlight的,我们不知道在哪里安装Silverlight(它是在C:。FilesMicrosoft Silverlight2.0.31005.0计划在我的笔记本电脑,在C:程序文件(x86 )微软Silverlight2.0.31005.0)的我的桌面上。 解决的办法是有一个预生成事件命令的.. CopySystemWindows.bat复制System.Windows.dll中从Silverlight的安装方向......二进制。 所以一旦你已经建立了项目,警告将消失,因为我们很快就会看到。
  • 在上面的Visual Studio截图,是另一个警告符号旁边到寡妇项目文件Microsoft.Windows.Controls.XML,当你加载到Visual Studio首次Controls.Design项目。 此文件相关控制建设项目产生的,因为在控制项目的属性 - > Build选项卡,选项“XML文档文件”进行检查,并有“...... Binar的路径
    iesMicrosoft.Windows.Controls.XML“。如果建立Controls.Design项目,警告将消失,因为我们很快就会看到。
  • Controls.Design项目有Metadata.cs的文件,并链接到Extension.cs和在Design.Common夹MetadataBase.cs。 全部12个设计项目,有这三个文件。 我们将在后面详细讨论。

建立Controls.Design项目或整个解决方案,我们可以看到:

建立Silverlight.Control.sln输出

  • 所有项目建成0个错误,0警告罚款。
  • 下System.Windows参考和Microsoft.Windows.Controls.XML的文件的警告标志消失。
  • 代码生成过程的分析需要较长的时间,它会产生两个警告。 第一个,CA0060,是另一个混​​合NET和Silverlight引用和代码在Extension.cs问题。 你可以得到摆脱警告从Silverlight安装目录复制System.dll中和System.Core.dll的SourceBinaries目录,再建设。

MetadataBase.cs

的MetadataBase.cs,连同Metadata.cs的实施框架设计时元数据注册:

  • DescriptionAttributes自动生成公共控件类(即FrameworkElement的子类),并从他们的“/ / / <summary>”在源代码的XML文档注释的公共属性。 (良好的注释补薪! :-)
  • 从一个设计师要隐藏一个控件类,象下面这样添加一行到AddAttributes项目的Metadata.cs文件的方法:
    builder.AddCallback(typeof运算(TreeViewItem项),B => b.AddCustomAttributes的(的新ToolboxBrowsableAttribute(假)));
  • 登记为控制类的其他自定义属性,添加一个XxxMetadata.cs文件的项目,如稍后讨论ViewboxMetadata.cs。

如果你喜欢的框架,你可以直接在自己的项目中使用MetadataBase.cs和Metadata.cs, 微软公共许可证包含在我们所有的源文件的开头。

MetadataBase.cs:

 / / /(C)版权所有Microsoft公司/ /此源是受微软公共许可协议(MS-PL)/ /详情请参阅http://go.microsoft.com/fwlink/?LinkID=131993。 /所有其他权利  MetadataRegistrationBase { /// <summary> /// Build design time metadata attribute table. /// </summary> /// <returns>Custom attribute table.</returns> protected virtual AttributeTable BuildAttributeTable() { AttributeTableBuilder builder = new AttributeTableBuilder(); AddDescriptions(builder); AddAttributes(builder); AddTables(builder); return builder.CreateTable(); } /// <summary> /// Find all AttributeTableBuilder subclasses in the assembly /// and add their attributes to the assembly attribute table. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> [SuppressMessage( "Microsoft.Design" , "CA1031:DoNotCatchGeneralExceptionTypes" , Justification = "Design time dll should not fail!" )] private static void AddTables(AttributeTableBuilder builder) { Debug.Assert(builder != null , "AddTables is called with null parameter!" ); Assembly asm = Assembly.GetExecutingAssembly(); foreach (Type t in asm.GetTypes()) { if (t.IsSubclassOf( typeof (AttributeTableBuilder))) { try { AttributeTableBuilder atb = (AttributeTableBuilder)Activator.CreateInstance(t); builder.AddTable(atb.CreateTable()); } catch (Exception e) { Debug.Assert( false , string .Format(CultureInfo.InvariantCulture, "Exception in AddTables method: {0}" , e)); } } } } /// <summary> /// Gets or sets the case sensitive resource name of the embedded XML file. /// </summary> protected string XmlResourceName { get; set; } /// <summary> /// Gets or sets the assembly FullName for types' assembly-qualified names. /// </summary> protected string AssemblyFullName { get; set; } /// <summary> /// Create description attribute from run time assembly xml file. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> [SuppressMessage( "Microsoft.Design" , "CA1031:DoNotCatchGeneralExceptionTypes" , Justification = "Design time dll should not fail." )] private void AddDescriptions(AttributeTableBuilder builder) { Debug.Assert(builder != null , "AddDescriptions is called with null parameter!" ); if ( string .IsNullOrEmpty(XmlResourceName) || string .IsNullOrEmpty(AssemblyFullName)) { return ; } XDocument xdoc = XDocument.Load( new StreamReader( Assembly.GetExecutingAssembly().GetManifestResourceStream(XmlResourceName))); if (xdoc == null ) { return ; } foreach (XElement member in xdoc.Descendants( "member" )) { try { string name = ( string )member.Attribute( "name" ); bool isType = name.StartsWith( "T:" , StringComparison.OrdinalIgnoreCase); if (isType || name.StartsWith( "P:" , StringComparison.OrdinalIgnoreCase)) { int lastDot = name.Length; string typeName; if (isType) { typeName = name.Substring(2); } else { lastDot = name.LastIndexOf( '.' ); typeName = name.Substring(2, lastDot - 2); } typeName += AssemblyFullName; Type t = Type.GetType(typeName); if (t != null && t.IsPublic && t.IsClass && t.IsSubclassOf( typeof (FrameworkElement))) { string desc = member.Descendants( "summary" ).FirstOrDefault().Value; desc = desc.Trim(); desc = string .Join( " " , desc.Split( new char [] { ' ' , 't' , 'n' }, StringSplitOptions.RemoveEmptyEntries)); if (isType) { builder.AddCallback(t, b => b.AddCustomAttributes( new DescriptionAttribute(desc))); } else { string propName = name.Substring(lastDot + 1); PropertyInfo pi = t.GetProperty(propName); MethodInfo mi; if (pi != null && (mi = pi.GetSetMethod()) != null && mi.IsPublic) { builder.AddCallback(t, b => b.AddCustomAttributes(propName, new DescriptionAttribute(desc))); } } } } } catch (Exception e) { Debug.Assert( false , string .Format(CultureInfo.InvariantCulture, "Exception in AddDescriptions method: {0}" , e)); } } } /// <summary> /// Provide a place to add custom attributes without creating a AttributeTableBuilder subclass. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> protected virtual void AddAttributes(AttributeTableBuilder builder) { } } } {/ / / <summary> / / / MetadataRegistration的类/ / / </摘要> 公开的类 MetadataRegistrationBase {/ / / / /建筑设计时元数据属性表/ / / </摘要> / / / / <summary> <returns>自定义属性表</>建设者AttributeTableBuilder 保护虚拟 AttributeTable的BuildAttributeTable(){= AttributeTableBuilder  (); AddDescriptions(建设者); AddAttributes(建设者); AddTables(建设者);的回报 builder.CreateTable();} / / / <summary> / / /大会/ / /查找所有AttributeTableBuilder子类,并添加自己的属性集属性表。/ / / </摘要> / / / <param name="builder">集属性表建设者</参数> [SuppressMessage(“Microsoft.Design”,“CA1031:DoNotCatchGeneralExceptionTypes”,理由=“设计时DLL不应该失败”)] 私有静态无效 AddTables(AttributeTableBuilder建设者){Debug.Assert的(建设者=!  “,AddTables被称为空参数!”);大会ASM = Assembly.GetExecutingAssembly(); 的foreach(T型asm.GetTypes()){ 如果(t.IsSubclassOf(typeof运算 (AttributeTableBuilder))){{AttributeTableBuilder ATB =(AttributeTableBuilder)的Activator.CreateInstance(T); builder.AddTable(atb.CreateTable());} 赶上 (例外五){Debug.Assert的( 假的字符串格式(CultureInfo.InvariantCulture,“在AddTables方法异常。 {0}“,e)条);}}}} / / / <summary> / / /获取或设置嵌入式XML文件的情况下,敏感的资源名称/ / / </摘要> 保护字符串 XmlResourceName的{获取;设置;} / / / <summary> / / /获取或设置类型的程序集限定名大会的FullName / / / </摘要> 保护字符串 AssemblyFullName的{获取;;} / / / <summary> / / /创建运行时组件的XML文件描述属性/ / / </摘要> / / / <param name="builder">的装配属性表生成器</参数> [SuppressMessage(“Microsoft.Design”,“CA1031。: DoNotCatchGeneralExceptionTypes“,理由=”设计时DLL不应该失败“) 私人无效 AddDescriptions(AttributeTableBuilder建设者){Debug.Assert的(建设者= NULL,:”AddDescriptions被称为“空参数 );!(字符串 IsNullOrEmpty( XmlResourceName)| |的字符串 IsNullOrEmpty(AssemblyFullName)){;}的XDocument xdoc = XDocument.Load( 新的StreamReader(Assembly.GetExecutingAssembly()。GetManifestResourceStream(XmlResourceName)));(xdoc == NULL){ 返回 ;} 的foreach (XElement的xdoc.Descendants成员(“成员”)){{ 字符串名称=( 字符串 )member.Attribute的(“名称”); 布尔 isType = name.StartsWith(“C:”,StringComparison.OrdinalIgnoreCase);( isType | | name.StartsWith( “P”,StringComparison.OrdinalIgnoreCase)){INT lastDot = name.Length 字符串 typeName的;(isType){typeName的name.Substring(2);} 否则 {lastDot = name.LastIndexOf ('。');的typeName = name.Substring(2 lastDot - 2);} typeName的= AssemblyFullName;类型T = Type.GetType(typeName的), 如果 (T = NULL && t.IsPublic && t.IsClass && t.IsSubclassOf(typeof运算 (FrameworkElement的))){desc字符串 = member.Descendants(“摘要”)FirstOrDefault()的价值;。DESC = desc.Trim();递减=加入字符串 (“”,desc.Split( 新的char [] {','T','N'},StringSplitOptions.RemoveEmptyEntries));(isType){builder.AddCallback(T,B => b.AddCustomAttributes的(  DescriptionAttribute(降序)));} 其他 { 字符串 PROPNAME = name.Substring(lastDot + 1);的PropertyInfo PI = t.GetProperty(PROPNAME)的MethodInfo公里;!(PI = NULL &&(MI = pi.GetSetMethod())= NULL && mi.IsPublic )builder.AddCallback(T,B => b.AddCustomAttributes的(PROPNAME,  DescriptionAttribute(降序)));}}} 赶上 (例外五){Debug.Assert的( 假的字符串格式(CultureInfo.InvariantCulture,。 “异常AddDescriptions方法:{0}”,E));}}} / / /的<summary> / / /提供一个地方,而无需创建一个AttributeTableBuilder子类添加自定义属性/ / / </摘要> / / / <param name="builder">集属性表建设者。</ PARAM> 受保护的虚拟无效 AddAttributes(AttributeTableBuilder建设者){}}} 

MetadataBase.cs实现的MetadataRegistrationBase的类。 让我们来讨论它的一些关键的方法:

AddDescriptions

所有运行时组件项目“XML文档文件”选项选中,和一个像“...... BinariesMicrosoft.Windows.Controls.XML”的道路,在项目 - >属性 - > Build标签,输出部分。 csproj文件,你也可以找到类似下面的设置。

 > ..BinariesMicrosoft.Windows.Controls.Design.XML </ DocumentationFile > <DocumentationFile> .. BinariesMicrosoft.Windows.Controls.Design.XML </ DocumentationFile> 

下面是一个显示生成的文档的XML文件看起来像什么的Microsoft.Windows.Controls.XML摘录:

内容装饰,可以延伸和扩展一个孩子以填充可用  Viewbox的默认的儿童元素  > < param name ="o" > The object typed value to be checked. </ param > < returns > True if o is a valid Stretch enum value, false o/w. </ returns > </ member > < member name ="P:Microsoft.Windows.Controls.Viewbox.Child" > < summary > Gets or sets the single child element of a Viewbox. </ summary > </ member > </ members > </ doc >通过对象的值是否是一个有效的拉伸枚举值。</ 摘要 > <PARAM NAME =“O”>“对象类型的值进行检查。</ 参数 > < 返回 >如果o是一个有效的拉伸枚举值,假O / W </> </ 会员 > < 成员  的“P:Microsoft.Windows.Controls.Viewbox.Child”> < 摘要 >。获取或设置一个Viewbox的一个子元素</ 摘要 > < / 会员 > </ 会员 > </ DOC> 

每个<member>元素的name属性的模式如下:

  • “电话:Microsoft.Windows.Controls.Viewbox”:“C:”表示这是一个类型,类型的全名;
  • “:Microsoft.Windows.Controls.Viewbox.ChildElementName”:“:”表示这是一个字段,字段的完全限定名称;
  • “男:Microsoft.Windows.Controls.Viewbox.IsValidStretchValue(System.Object的)”:“男:”这是一个方法,该方法是完全合格的名称和参数;
  • 的“P:Microsoft.Windows.Controls.Viewbox.Child”:“病人:”这是一个物业,由物业的全名;

Control.Design项目Microsoft.Windows.Controls.XML文件作为嵌入的资源的链接:

  • 作为嵌入式资源Microsoft.Windows.Controls.XML
  • Controls.Design.csproj:

      Include ="..BinariesMicrosoft.Windows.Controls.XML" /> <EmbeddedResource 包括 =“...... BinariesMicrosoft.Windows.Controls.XML”/> 

AddDescriptions方法分析嵌入式XML文件和生成的公共控件类和公共属性的DescriptionAttribute:

  MetadataBase.cs:134:builder.AddCallback(T,B => b.AddCustomAttributes“(  DescriptionAttribute(DESC)));
 MetadataBase.cs:143:builder.AddCallback(T,B => b.AddCustomAttributes(PROPNAME,  DescriptionAttribute(降序))); 
AddAttributes

AddAttributes是通常在Metadata.cs文件重写以添加1 ToolboxBrowsableAttribute(假)自定义属性,控制类,不应该出现在设计师的工具箱:

  • 如果控件类应该隐藏所有设计师,添加ToolboxBrowsableAttribute(假)自定义属性的Xxx.Design项目;
  • 如果它应该被隐藏从Visual Studio中,添加自定义属性Xxx.VisualStudio.Design项目;
  • 如果它应该被隐藏Expression Blend中,添加自定义属性Xxx.Expression.Design项目;

下面是AddAttributes实施Controls.VisualStudio.Design项目Metadata.cs:

  / / / <summary>
 / / /提供一个地方,而无需创建一个AttributeTableBuilder子类添加自定义属性。
 / / / </摘要>
 / / / <param name="builder">集属性表建设者。</ PARAM>
 保障的覆盖的无效 AddAttributes(AttributeTableBuilder建设者)
 {
     ToolboxBrowsableAttribute( false ))); builder.AddCallback(typeof运算 (TreeViewItem项),B => b.AddCustomAttributes的(的 ToolboxBrowsableAttribute(  )));
 } 
AddTables

添加属性比其他类型的(假)ToolboxBrowsableAttribute,添加一个像ViewboxMetadata.cs XxxMetadata.cs的文件如下相应的设计项目:

ViewboxMetadata.cs:

  / /版权所有(C)Microsoft Corporation版权所有。
 / /这个源是受微软公共许可协议(MS-PL)。
 / /详细信息,请参阅http://go.microsoft.com/fwlink/?LinkID=131993。
 / /保留所有其他权利。

 使用 System.ComponentModel;
 使用 Microsoft.Windows.Controls.Design.Common;
 使用 Microsoft.Windows.Design.Metadata;

 命名空间 Microsoft.Windows.Controls.Design
 {
     / / / <summary>
     / / /要注册Viewbox的设计时元数据。
     / / / </摘要>
     内部类 ViewboxMetadata:AttributeTableBuilder
     {
         / / / <summary>
         / / /要注册Viewbox的设计时元数据。
         / / / </摘要>
         :公共 ViewboxMetadata()
             基地 ()
         {
             AddCallback(
                 typeof运算 (Viewbox的),
                 B =>
                 {
                     )); b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(=> x.BorderThickness的),  BrowsableAttribute(  ));
                     )); b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.BorderBrush),  BrowsableAttribute(  ));
                     )); b.AddCustomAttributes(<Viewbox> Extensions.GetMemberName(X => x.Background),  BrowsableAttribute(  ));
                     )); b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.Foreground),  BrowsableAttribute(  ));

                     (Extensions.GetMemberName <Viewbox> b.AddCustomAttributes(X => x.Child)的, 的CategoryAttribute(Properties.Resources.CommonProperties));
                     b.AddCustomAttributes(<Viewbox> Extensions.GetMemberName(X => x.Stretch)的, 的CategoryAttribute(Properties.Resources.CommonProperties));
                     b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.StretchDirection), 的CategoryAttribute(Properties.Resources.CommonProperties));
                 });
         }
     }
 } 
  • 建议遵循命名约定。 Viewbox的例子,文件名是ViewboxMetadata.cs,和类的名称是ViewboxMetadata。
  • 必须继承从AttributeTableBuilder,元数据类。
  • 您可以添加自定义属性的元数据类的构造:
    • 您可以使用回电模式(以上ViewboxMetada.cs)或直接模式。 大概是更有效的回调模型。
      • 直销模式的例子:

        AddCustomAttributes(

        typeof运算(Viewbox的),/ /类型

        “的BorderThickness”,/ /属性名

        新的属性[] {新BrowsableAttribute(假)}); / /自定义属性数组

    • 提供属性名参数AddCustomAttribute呼叫,您可以使用在ViewboxMetadata.cs的方法Extensions.GetMemberName()(稍后将讨论更多关于它后)得到属性的名称,类型安全的方式,或提供直接像在上述直销模式的实施“的BorderThickness”字符串属性的名称。

AddTables(AttributeTableBuilder建设者)方法:

  • 列举了在执行大会的所有子类AttributeTableBuilder
  • 创建一个每个发现AttributeTableBuilder子类的实例:

    AttributeTableBuilder,ATB =(AttributeTableBuilder)Activator.CreateInstance(T);

  • 添加到建筑工地发现类的属性表:

    builder.AddTable(atb.CreateTable());

metadata.cs

metadata.cs实现MetadataRegistration类,它继承从在MetadataBase.cs实施MetadataRegistrationBase类。 它还实现了IRegisterMetadata接口。

metadata.cs:

 / / /(C)版权所有Microsoft公司/ /此源是受微软公共许可协议(MS-PL)/ /详情请参阅http://go.microsoft.com/fwlink/?LinkID=131993。 /所有其他权利  MetadataRegistration : MetadataRegistrationBase, IRegisterMetadata { /// <summary> /// Design time metadata registration class. /// </summary> public MetadataRegistration() : base () { AssemblyName asmName = typeof (Viewbox).Assembly.GetName(); XmlResourceName = asmName.Name + ".Design." + asmName.Name + ".XML" ; // "Microsoft.Windows.Controls.Design.Microsoft.Windows.Controls.XML" AssemblyFullName = ", " + asmName.FullName; } /// <summary> /// Borrowed from System.Windows.Controls.Toolbox.Design.MetadataRegistration: /// use a static flag to ensure metadata is registered only one. /// </summary> private static bool _initialized; /// <summary> /// Called by tools to register design time metadata. /// </summary> public void Register() { if (!_initialized) { MetadataStore.AddAttributeTable(BuildAttributeTable()); _initialized = true ; } } /// <summary> /// Provide a place to add custom attributes without creating a AttributeTableBuilder subclass. /// </summary> /// <param name="builder">The assembly attribute table builder.</param> protected override void AddAttributes(AttributeTableBuilder builder) { } } } {/ / / <summary> / / / MetadataRegistration的类/ / / </摘要> 公共类 MetadataRegistration:。MetadataRegistrationBase,IRegisterMetadata {/ / / <summary> / / /设计时元数据登记类/ / / </摘要> 公共 MetadataRegistration()。 基地 (){AssemblyName的asmName = typeof运算 (Viewbox的)Assembly.GetName(); XmlResourceName = asmName.Name“设计”asmName.Name“。XML的”/ /“Microsoft.Windows的。Controls.Design.Microsoft.Windows.Controls.XML“AssemblyFullName =”,“+ asmName.FullName;} / / / <summary> / / /借用,从System.Windows.Controls.Toolbox.Design.MetadataRegistration:/ / /使用一个静态的标志,以确保元数据注册只有一个/ / / </摘要> 私有静态布尔 _initialized; <summary> / / / / / /工具注册设计时元数据/ / / </摘要> 公众  无效注册(){{BuildAttributeTable MetadataStore.AddAttributeTable(())(_initialized!); _initialized的= TRUE;}} / / /的<summary> / / /提供一个地方,而无需创建一个AttributeTableBuilder子类添加自定义属性/ / / </摘要> / / / <param name="builder">的装配属性表建设者。</ PARAM> 保护重写的无效 AddAttributes(AttributeTableBuilder建设者){}}} 

让我们来讨论它的一些主要方法:

MetadataRegistration

此构造函数初始化两个关键领域:

  • XmlResourceName:资源名称的嵌入文档的XML文件,由MetadataRegistrationBase.AddDescriptions使用方法。
  • AssemblyFullName:设计时间组件是运行时组装的全名。

如果您使用Metadata.cs在自己的设计项目,您需要更换自己的类型Viewbox的。

注册

这是唯一的方法IRegisterMetadata接口。 它增加了自定义的属性表,建立从AddDescripions,AddAttributes AddTables上述方法,以设计师的元数据存储:

MetadataStore.AddAttributeTable(BuildAttributeTable());

extensions.cs

这个文件包含了用于编译时检查类型成员的名称和IntelliSense实施扩展的方法GetMemberName <T>(表达<FUNC <T,物件> expr的):

GetMemberName扩展方法

这个想法最初提出的由贾法尔侯赛因 (看到他的博客后, 在C#3.0中的符号 ),然后通过改进贾斯汀天使 这是一个伟大的伎俩,以避免错别字,但其缺点是,它在Silverlight引用和组件的拉入,否则纯。NET程序集。 下面是完整的源代码:

extensions.cs:

 System; using System.Linq.Expressions; namespace Microsoft.Windows.Controls.Design.Common { /// <summary> /// This set of internal extension methods provide general solutions and /// utilities in a small enough number to not warrant a dedicated extension /// methods class. /// </summary> internal static class Extensions { /// <summary> /// Helper method to get member name with compile time verification to avoid typo. /// </summary> /// <typeparam name="T">The containing class of the member whose name is retrieved.</typeparam> /// <param name="expr">The lambda expression usually in the form of o => o.member.</param> /// <returns>The name of the property.</returns> public static string GetMemberName<T>(Expression<Func<T, object >> expr) { Expression body = ((LambdaExpression)expr).Body; MemberExpression memberExpression = body as MemberExpression; if (memberExpression == null ) { memberExpression = (MemberExpression)((UnaryExpression)body).Operand; } return memberExpression.Member.Name; } } } / / /(C)版权所有Microsoft公司/ /此源是受微软公共许可协议(MS-PL)/ /详情请参阅http://go.microsoft.com/fwlink/?LinkID=131993。 /保留所有其他权利的 使用系统; 使用 System.Linq.Expressions 命名空间 Microsoft.Windows.Controls.Design.Common {/ / / <summary> / / /这一套内部的扩展方法提供全面的解决方案/ / /公用事业在一个足够小的数目,不值得一个专门的扩展/ / /方法/ / / </摘要> 内部静态类扩展{/ / /的<summary> / / /辅助方法来获取编译时间验证的成员名称,以避免类。错字。/ / / </摘要> / / / <typeparam name="T">包含类的成员,其名称检索。</ typeparam> / / / <param name="expr"> lambda表达式通常Ø=> o.member。,</ PARAM> / / / <returns>属性的名称。</> 公共静态的字符串 GetMemberName <T>表达<FUNC <T, 对象 > expr的形式 {表达身体=((LambdaExpression)expr的)身体; MemberExpression memberExpression =身体 MemberExpression; 如果 (memberExpression == NULL){memberExpression =(MemberExpression)((UnaryExpression)机身)操作数;} 返回 memberExpression.Member.Name; }} 

结论

12月2008年发布Silverlight工具包这篇文章中描述的设计时功能的执行情况,并介绍了执行Silverlight控件的设计时功能的简单框架。 你可以模拟实施,并在自己的项目中重用的框架。 框架仍是很原始,只支持元数据注册,因为这是现在所有混合支持。 我会考虑改进的框架和Silverlight工具包的设计时功能,如添加自定义的内联/扩展/对话编辑,设计时的数据,设计时只行为等。

正如我在以前的职位表示Silverlight工具包的设计时功能 ,控制设计时间的经验是非常重要的。 它不仅提高屈尊时间功能使用这些控件的开发人员的经验和生产力,而且还提高了最终用户的经验,因为越来越多的应用,给用户更灵活地定制用户界面,如改变拖放控件的布局, ,或改变控件的设置,就像一个设计师,但它在运行时。