Silverlight工具包的设计时功能的实现
介绍
这是我的Silverlight设计时功能系列的第二个职位。 Silverlight工具包的设计后的第一时间功能显示设计时功能的Silverlight工具包控制。 这篇文章解释它是如何实现的。 希望这篇文章可以帮助解释我们的源代码,演示了如何实现Silverlight的设计时功能,并提供了一个框架和源代码,读者可以直接在自己的项目使用。
概观
下载“Silverlight工具包-二进制文件,样本,文档,单元测试和源” 2008年12月发布 ,在Visual Studio中打开SourceSilverlight.Controls.sln,有12个设计项目,设计方案文件夹,三下,我们将看到每个控制大会。
采取控制示例项目,设计项目有三个:
- 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源目录下,我们会看到象下面这样的画面:
- 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混合引用。
- 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项目或整个解决方案,我们可以看到:
- 所有项目建成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文件作为嵌入的资源的链接:
-
- 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”字符串属性的名称。
- 您可以使用回电模式(以上ViewboxMetada.cs)或直接模式。 大概是更有效的回调模型。
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的):
这个想法最初提出的由贾法尔侯赛因 (看到他的博客后, 在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工具包的设计时功能 ,控制设计时间的经验是非常重要的。 它不仅提高屈尊时间功能使用这些控件的开发人员的经验和生产力,而且还提高了最终用户的经验,因为越来越多的应用,给用户更灵活地定制用户界面,如改变拖放控件的布局, ,或改变控件的设置,就像一个设计师,但它在运行时。








最新评论