存档

2008年12月存档

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是像Visual Studio或Expression Blend中,而不是运行在一个Silverlight大会内部设计师的桌面上运行的NET程序集。浏览器,即使Microsoft.Windows.Controls.Design.dll设计时间为Silverlight运行时大会Microsoft.Windows.Controls.dll大会。
    • 引用System.Windows大会实际上是一个Silverlight大会(版本2.0.5.0)。 System.Windows大会可能并不需要Silverlight控件的所有设计项目。 我们需要,主要是因为GetMemberName <T> 这里(表达式<FUNC <T,对象>>表达式 )在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:Program Files 文件( X86 微软Silverlight2.0.31005.0)我的桌面上。 解决的办法是有一个预生成事件命令.. CopySystemWindows.bat副本System.Windows.dll从Silverlight安装方向..二进制文件。 所以一旦你已经建立了项目,警告将消失,因为我们很快就会看到。
  • ,在上面的Visual Studio截图,是在项目寡妇文件Microsoft.Windows.Controls.XML旁边另一个警告标志,当你Controls.Design项目首次加载到Visual Studio。 此文件相关控制建设项目产生的,因为控制项目的属性 - >“构建”标签上,“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(FALSE)));
  • 要注册一个控件类的其他自定义属性,添加XxxMetadata.cs的文件项目,如稍后讨论ViewboxMetadata.cs。

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

MetadataBase.cs:

 / /版权所有(C)微软公司。/ /此源是受微软公共许可协议(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>自定义属性表</返回> 受保护的虚拟 AttributeTable BuildAttributeTable(){AttributeTableBuilder建设者=  AttributeTableBuilder(); AddDescriptions(建设者); AddAttributes(建设者); AddTables(建设者); 返回 builder.CreateTable();} / / / <summary> / / /查找在大会/ / /所有AttributeTableBuilder子类,并添加自己的属性集属性表。/ / / </摘要> / / / <param name="builder">集属性表器</ PARAM> [SuppressMessage(“Microsoft.Design”,“CA1031:DoNotCatchGeneralExceptionTypes”,理由=“!设计时DLL不应该失败”)]。 私有静态无效 AddTables(AttributeTableBuilder建设者){Debug.Assert的(建设者=! 被称为  ,“AddTables空参数!”);大会ASM = Assembly.GetExecutingAssembly(); 的foreach(Tasm.GetTypes()){IF(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">集属性表生成器</ PARAM> [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 (xdoc.Descendants XElement的成员 (“成员”)){{ 字符串名称=( 字符串 )member.Attribute(“名称”); BOOL isType = name.StartsWith(“T”,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 = 字串加入(“”,desc.Split( 新的char [] {'','T','N'},StringSplitOptions.RemoveEmptyEntries));(isType){builder.AddCallback(T,B => b.AddCustomAttributes(  DescriptionAttribute(DESC)));} { 字符串 PROPNAME = name.Substring(lastDot + 1);的PropertyInfo PI = t.GetProperty(PROPNAME); MethodInfo的MI;(PI = NULL&&(MI = pi.GetSetMethod())= NULL&&mi.IsPublic!! builder.AddCallback(){T,B => b.AddCustomAttributes(PROPNAME,  DescriptionAttribute(DESC)));}}}}} 赶上 (例外五){Debug.Assert的( 假的字符串格式(CultureInfo.InvariantCulture。 “AddDescriptions方法中的异常:{0}”,E));}}} / / / <summary> / / /提供一个地方,而无需创建一个AttributeTableBuilder子类/ / / </摘要> / / /添加自定义属性。 <param name="builder">集属性表生成器</ PARAM> 受保护的虚拟无效 AddAttributes(AttributeTableBuilder建设者){}}} 

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

AddDescriptions

所有运行时的装配项目“XML文档文件”选项选中,像“.. BinariesMicrosoft.Windows.Controls.XML”的路径,在项目 - >属性 - >“构建”标签上,输出部分。 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 >通过对象的值是否是一个有效的拉伸枚举值。</ 摘要 > < 参数 名称 =“O”>“对象类型的值进行检查。</ PARAM> <返回>真,如果o是一个有效的拉伸枚举值,假O / W。</> </会员> < 成员 名=“P:Microsoft.Windows.Controls.Viewbox.Child”> < 摘要 >获取或设置一个Viewbox的一个子元素</摘要> < /> </ 成员 > </ DOC> 

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

  • “T:Microsoft.Windows.Controls.Viewbox”:“电话:”这是一个类型,类型的全名;
  • “F:Microsoft.Windows.Controls.Viewbox.ChildElementName”:“F:”表示这是一个领域,由该领域的完全合格的名称;
  • “男:Microsoft.Windows.Controls.Viewbox.IsValidStretchValue(继承)”:“男:”这是一个方法,方法的完全合格的的名称和参数;
  • “P:Microsoft.Windows.Controls.Viewbox.Child”:“P:”这是一个财产,财产的全名;

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(DESC))); 
AddAttributes

AddAttributes通常在Metadata.cs文件覆盖的控制类,应该不会出现在设计师的工具箱添加一个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(FALSE)));
 } 
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 => x.BorderThickness), 新BrowsableAttribute(FALSE));
                     )); b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.BorderBrush), 新BrowsableAttribute(FALSE));
                     )); b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.Background), 新BrowsableAttribute(FALSE));
                     )); b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.Foreground), 新BrowsableAttribute(FALSE));

                     b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(X => x.Child), 的CategoryAttribute(Properties.Resources.CommonProperties));
                     b.AddCustomAttributes(Extensions.GetMemberName <Viewbox>(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)微软公司。/ /此源是受微软公共许可协议(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> / / / / / /工具注册设计时元数据/ / / </摘要>市民无效注册(){ 如果 {MetadataStore.AddAttributeTable BuildAttributeTable(())(_initialized!); _initialized = TRUE;}} / / / <summary> / / /提供一个地方,不创建一个AttributeTableBuilder子类添加自定义属性/ /。 / </摘要> / / / <param name="builder">大会属性表制造商。</ PARAM>保护覆盖无效AddAttributes(AttributeTableBuilder建设者){}} } 

让我们来讨论它的一些关键方法:

MetadataRegistration

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

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

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

注册

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

MetadataStore.AddAttributeTable(BuildAttributeTable());

Extensions.cs

此文件包含的扩展方法GetMemberName <T>(表达式<FUNC <T,对象>> expr的),用来得到一个编译时检查和IntelliSense类型的成员的名称的实施:

GetMemberName扩展方法

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

Extensions.cs:

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

 使用系统;
 使用 System.Linq.Expressions;

 命名空间 Microsoft.Windows.Controls.Design.Common
 {
     / / / <summary>
     / / /这一套内部扩展方法提供一般的解决方案,
     / / /公用事业在一个足够小的数目不值得一个专门的扩展
     / / /方法的类。
     / / / </摘要>
     内部静态类的扩展
     {
         / / / <summary>
         / / / Helper方法得到编译时验证,以避免错字成员的名称。
         / / / </摘要>
         / / / <typeparam name="T">包含类的成员,其名称检索。</ typeparam>
         / / / <param name="expr"> lambda表达式通常在邻的形式=> o.member </ PARAM >
         / / / <returns>属性的名称。</返回>
         >> expr) 公共静态字符串 GetMemberName <T>(表达式<FUNC <T, 对象 >> expr的)
         {
            表达身体=((LambdaExpression)expr的)机构;
             MemberExpression memberExpression = MemberExpression 身体;
             ) 如果 (memberExpression == NULL)
             {
                 memberExpression =(MemberExpression)((UnaryExpression)身体)的操作数。
             }
             返回 memberExpression.Member.Name;
         }
     }
 } 

结论

这篇文章中介绍了2008年12月发布Silverlight工具包的设计时功能的实施,并出台了实施Silverlight控件的设计时功能的简单的框架。 您可以实施模型,并在自己的项目中重用的框架。 该框架仍是非常原始,只支持元数据注册,因为这是现在所有混合支持。 我会研究改善的框架和Silverlight工具包的设计时功能,如添加自定义的内联/扩展/对话框编辑器,设计时的数据,设计时只行为等。

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