翻译:SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)

翻译:SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览),第1张

概述原文链接: Silverlight Design Time Extensibility --By Justin Angel (Microsoft Silverlight Toolkit Program Manager) 嗨伙计们,      只要有人谈到开发者与设计师在 Silverlight/WPF上协同工作时,他们就会谈论“设计,开发工作流程”这个 问题。即使您是您自己的设计师,这工作也始终是 原文链接: Silverlight Design Time Extensibility --By Justin Angel (Microsoft Silverlight Toolkit Program Manager)

嗨伙计们,

     只要有人谈到开发者与设计师在 Silverlight/WPF上协同工作时,他们就会谈论“设计,开发工作流程”这个
问题。即使您是您自己的设计师,这工作也始终是永远存在于当你在“设计师”和“开发”之间切换“帽子”的过程中。

     我是一个使用工具创建用户界面的支持者。 我的生活让我不能理解为什么有人会选择非产能(non-productive)
和手写XAML的事情。

     你能找出的一个情况就是当你使用(Expression Blend & Visual Studio WPF/Silverlight Designer)这类工
具进行工作时,如果使用正确,这些工具会对提高生产力起到巨大的推动作用。然而,这篇帖子不是关于如何使用
这类工具,而是关于如何帮助那些使用您的控件作为工具进行设计的人。本文是关于开发者着手去让设计师有更容
易的(设计)体验并减少摩擦。

     控件提供商和开发者通常都想给自己的控件以更好的体验。然而,在这个问题上其缺乏大量的信息。我决定用
本文纠正这种情况。

   本文也与那些在项目中有设计师一起工作的开发者有关。我建立的解决方案可在这里下载,SilverlightControls.zip  



介绍:

   首先,我们会考虑在设计时的AssemblIEs工作。

   考虑下面这个类:

public   class  myControl : Control
{
    
public   string  MyStringProperty {  get set ;  }
}


   现在,考虑下面这个设计时属性的类:

[Description( " I am a control " )]
public   class  myControl : Control
{
    [Description(
" I am a property " )]
    
public   string  MyStringProperty {  get set ;  }
}


    在设计时assemblIEs 工作的方式就是将设计时属性与实际的类进行分离。之后我们的类会是这个样子:

public   class  myControl : Control
{
    
public   string  MyStringProperty {  get set ;  }
}


   并且在我们的设计时组装过程时,代码相当于:

AddCallback( typeof (myControl), builder  =>
     builder.AddCustomAttributes(
new  DescriptionAttribute( " I am a control 2 " )));


AddCallback(
typeof (myControl), builder  =>
    builder.AddCustomAttributes(
" MyStringProperty " new  DescriptionAttribute( " I am a property " )));



    在没有研究太多API的情况下,可以看到第一行会显示“myControl has the following DescriptionAttribute”,
第二行显示:“myControl.MyStringProperty has this DescriptionAttribute”.



   我们从运行时代码中分离出设计时代码. 下面让我们看一下在BLEND中,它的样子:

 





    这一做法有哪些优势?

1.将设计时代码与运行时代码解耦有助于创造更好的代码。 (分离的问题,POCO,单一的责任等)

2.基于工具修改设计时属性。这种做法允许支持不同的设计时属性,而这些属性基于它们运行的工具。

3.设计时变更无须重新编译运行时组件。

4.不是运行时组装的author可以添加设计时属性。

5.高级的设计时支持,并不需要我们使用GUIDs注册Visual Studio软件包。



参考架构

   这里有一些步骤. 从本质上讲,我们要建立以下结构:




    一点都不乱( 译者注:我看有点乱,呵呵),是吧?简单地说,这仅仅是参考模型。

    我们将创建3个新项目。




 *. Design.dll -将包含设计时属性,这些属性用于Visual Studio WPF/Silverlight设计器和Expression Blend。

 *. VisualStudio.design.dll -将包含设计时的功能,仅用于Visual Studio。

 *. Expression.design.dll -将包含设计时的功能,仅用于Expression blend。


   这种命名约定是强制性的。


   第一步是增加项目引用,我们会在该项目中添加设计时支持用于设计时组件:

  





   添加对共享设计时dll的引用:

  




   并添加Blend design-time 引用:


  




步骤:

1. 添加一个Silverlight 类库,该类库会包含我们的控件. 我们将它命名为:SilverlightControls.



2. 添回一个myControl 类.
 

public   class  myControl : Control
{
    
public   string  MyStringProperty
    {

        
get  {  return  GetValue(MyStringPropertyProperty)  as   string ; }

        
set  { SetValue(MyStringPropertyProperty, value); }
    }


    
public   static   Readonly  DependencyProperty MyStringPropertyProperty  =
        DependencyProperty.Register(
" MyStringProperty " , typeof ( string ),  typeof (myControl),  null );   
}


3. 创建共享运行时DLL. 因为控件被命名为“SilverlightControls” ,所以这里命名为“SilverlightControls.Design”.
这里选择类型为“WPF Custom Control library” 因为稍后会使用一些WPF 特性.如果喜欢,我们可以手工添加引用到普通类库项目中。  




4. 在“SilverlightControls.Design” 项目中添加对“SilverlightControls” 项目的引用,  以及Microsoft design time 组件和
Silverlight System.windows.dll.






   (Silverlight 2 引用路径– 默认位于 c:"Program files"Microsoft SDKs"Silverlight"v2.0"Reference AssemblIEs)




   这是我们引用的组件: 
 




5. 创建visual studio 设计时DLL.
   因为要添加的设计时用于“SilverlightControls” 所以这里命名为:“SilverlightControls.VisualStudio.Design”.




6. 在项目“SilverlightControls.VisualStudio.Design” 中添加对“SilverlightControls”的引用,以及
Microsoft design time assemblIEs 和 Silverlight System.windows.dll.

 

 


 

    这里我们添加的引用:




7. 创建Expression blend 设计时 DLL.
   因为要添加的设计时用于“SilverlightControls” 所以这里命名为“SilverlightControls.Expression.Design”.


 

8. 在项目“SilverlightControls.Expression.Design” 中添加对“SilverlightControls” 的引用,Microsoft

design time assemblIEs 和 Blend specific dlls。

 

 



   这里我们添加的引用:




9. 我们需要在三个运行时组件项目中分别添加一个类,该类实现了IReigsterMetadata 接口.

   我在这三个项目中使用下面模版.

public   class  MetadataRegistration : IRegisterMetadata
{
    
private   static  Attributetable _customAttributes;

    
private   static   bool  _initialized;


    
public   voID  Register()
    {
        
if  ( ! _initialized)
        {
            MetadataStore.AddAttributetable(CustomAttributes);

            _initialized 
=   true ;
        }
    }


    
public   static  Attributetable CustomAttributes
    {
        
get
        {
            
if  (_customAttributes  ==   null )
            {
                _customAttributes 
=   new  CustomMetadataBuilder().Createtable();
            }

            
return  _customAttributes;
        }
    }

 

    
private   class  CustomMetadataBuilder : AttributetableBuilder
    {
        
public  DeveloperMetadataBuilder()
        {
            
//  Todo: Add Design time code here!
        }


        
private   voID  AddTypeAttributes(Type type,  params  Attribute[] attribs)
        {
            
base .AddCallback(type, builder  =>  builder.AddCustomAttributes(attribs));
        }
 

        
private   voID  AddMemberAttributes(Type type,  string  membername, builder  =>  builder.AddCustomAttributes(membername, attribs));
        }
    }
}




    我不想深入研究这个类做了什么,以及IRegisterMetadata 和 AttributetableBuilder 是什么,您可以到
MSDN 上去查找. 我只想说,它们是extensibility framework 中的类,通过它们,我们可以对我们的类添加设
计时支持。并且,我也不打算深入分析我的 template 做了什么. 起码它确保 Metadata 仅被创建一次,并且提
供了简单的访问方法,这些方法我们会在本DEMO中到处使用。

   好,这就是我们当前的项目结构:

  



   注:我们在每个项目中都已有了一个Metadata 类.

 

   10. 安装设计时文件拷贝。
       设计时DLL文件须与运行时DLL文件放在相同的目录下.  
       我喜欢自动完成相关的*design.dll 文件拷贝. 你可以手工完成这一 *** 作。

    我使用的自动方式是添加一条 post-build action 到每个设计时项目中.

    右击我们的项目文件 –> “属性” –> “生成事件”. 粘帖下面内容到Post Build Events:

   
copy  " $(TargetPath) "   " $(SolutionDir) " SilverlightControls " Bin " DeBUG "




    在所有的三个设计时项目中重复这一步骤.

    

创建我们的测试项目

 

1. 我们使用BLEND创建一个新的项目来使用我们的DLL. 我们会使用该项目来预览我们的设计时改进。  





2. 添加对“SilverlightControls.dll”的引用.
 

 



 




   这时发生了什么?

   我们有了两个设计时dll约束. 因为这两个约束会被工具自动加载到tools:

   Design time DLLs 文件与 runtime DLL在一起.
   Design time DLLs 遵守命名协定.
   
<Runtimename>.Design.dll – 共享设计时
<Runtimename>.Expression.Design.dll – 用于Expression blend 设计时
<Runtimename?.VisualStudio.Design.dll – 用于Visual studio wpf/silverlight 设计器
 

   现在我们有了这个基本架构,接下来就开始用一下吧.


   ( 注:原文作者在这里好像就做了一个章节,下面是后续的文章内容:属性讲解

 

 

DescriptionAttribute (Shared)

   Description 是一个让我们在设计时工具中显示类似智能说明的方法.  该属性用于在类和属性之间进行工作。

   当我们说某个属性是“Shared” 时,它意味着工作在两个工具之间并且须放在共享设计时 dll中.
   尽管当前 Visual studio 有只读的设计时界面,一旦其获得一个可以编辑的设计界面,这些都会在两个工具间被支持.

   那就让我们在SilverlightControls.Design.MetadataRegistration类型中DescriptionAttribute.
            public  CustomMetadataBuilder()
            {

                AddTypeAttributes(
typeof (myControl),
                    
new  DescriptionAttribute( " I am a control " ));
 

                AddMemberAttributes(
typeof (myControl), " MyStringProperty " ,
                    
new  DescriptionAttribute( " I am a property " ));
            }


    现在编译我们的应用并在Expression Blend看一下这些描述。









displayNameattribute (shared)

    显示名称属性用于显示类型成员的(frIEndlIEr)名称.

    AddMemberAttributes(typeof(myControl),"MyStringProperty",
        new DescriptionAttribute("I am a property"),
        new displayNameattribute("My String Property"));




    下面是其在 Blend中的显示:




categoryAttribute (shared)

    每个属性都有一个默认分类. Blend 为我们的控件定义如下分类:




    默认情况下,我们的属性添加到了“Miscellaneous” 分类. 如果想重新定义它,我们可让它在别处。

    我们可能想让我们的属性添加到已有的分类中,比如“Common PropertIEs”.

AddMemberAttributes( typeof (myControl),
    
new  DescriptionAttribute( " I am a property " ),
    
new  displayNameattribute( " My String Property " ),
    
new  categoryAttribute( " Common PropertIEs " ));

 

    在Blend中,我们看到它被移动到了那个分类下:




    我们可能想去创建我们自己在分类,该分类我们称之为“My category”.

AddMemberAttributes( typeof (myControl),
    
new  categoryAttribute( " My category " ));




    Blend 甚至可以在一个相同的自定义分类中进行属性分组(group propertIEs).

    让我们在控件中添加一个新的Integer 类型属性:

public   class  myControl : Control
{
    
public   string  MyStringProperty
    {
        
get  {  return  GetValue(MyStringPropertyProperty)  as   string ; }

        
set  { SetValue(MyStringPropertyProperty, value); }
    }

    
public   static   Readonly  DependencyProperty MyStringPropertyProperty  =
        DependencyProperty.Register(
" MyStringProperty " null );

 

    
public   int  MyIntProperty
    {
        
get  {  return  ( int )GetValue(MyIntPropertyProperty) ; }
        
set  { SetValue(MyIntPropertyProperty, value); }
    }

    
public   static   Readonly  DependencyProperty MyIntPropertyProperty  =
        DependencyProperty.Register(
" MyIntProperty " typeof ( int ),  null );   

}



    我们将它添加到我们自定义的分类中.

    AddMemberAttributes( typeof (myControl),
        
new  DescriptionAttribute( " I am a property " ),
        
new  displayNameattribute( " My String Property " ),
        
new  categoryAttribute( " My category " )); 

    AddMemberAttributes(
typeof (myControl),  " MyIntProperty " ,
        
new  categoryAttribute( " My category " ));

    我们会看到在‘My category’中有两个属性:




browsableAttribute (shared)

    browsable 属性允许我们隐藏一些属性,这些属发现在Blend’的数据面板(Data pane)或Visual
Studio的属性窗口中不再有效.

    AddMemberAttributes( typeof (myControl),
        
new  categoryAttribute( " My category " ),
        browsableAttribute.No);



    当我们在 Blend运行当前应用时,会看到在Data Pane中不在有该属性了:




    我们能够使用 browsable 属性隐藏一些继承的属性以及我们自定义的属性.



EditorbrowsableAttribute (Blend)

    我仅在Blend 设计时项目中标记了这个属性,但这是出于我对Visual Studio Silverlight 设计器的猜测.
这可能在VS的一些流行特征中支持,但我建议在使用之前先考虑它。Editor browsable 高级状态可以让你在
Blend 中的一个分类下隐藏一些属性,除非用户喜欢看到这些。基本上,隐藏一下较少使用的属性可以让分类
显示更加清楚。

    让我们打开Expression blend Metadata 项目中的元数据文件并添加下面设计时:
 



 
  AddMemberAttributes( typeof  (myControl),
            
new  EditorbrowsableAttribute(EditorbrowsableState.Advanced));


    这是Blend 显示的分类:




    我们会在该分类上看到一个小的“隐藏”箭头:



    如果点击它,会展开并显示该分类下的所有高级属性:




   如果用户离开控件然后在选中它时,该分类显示将再次关闭:




   那我们在这里假设直到你需要时我们在显示它.

   在Silverlight Framework 属性里在什么地方应用该属性呢? 很多地方.

   下面是在Silverlight的“Layout” 分类中:



 
   然后我点击它:



   我们明白了为什么要在同一分类下避免显示太多的属性.


TypeConverterattribute (Shared)

    指定用作此属性所绑定到的对象的转换器的类型。

    起初,它被用在从UI到后台模型的值转换 *** 作. 它在Blend 2 SP1 在现在还无法使用.
如果能使用就好了,因为它有一些不错的东西.

    在Blend TypeConverters能做的一件事是支持标准值,我们会在 *** 作中看到.

    在我们的类似对象“MyObject”添加另一个属性:



public   class  myControl : Control
{
    
public   string  MyStringProperty
    {
        …
    }

    
public   int  MyIntProperty
    {
        …
    }

    
public   object  MyObjectProperty
    {
        
get  {  return  ( object )GetValue(MyObjectPropertyProperty); }

        
set  { SetValue(MyObjectPropertyProperty, value); }
    }

    
public   static   Readonly  DependencyProperty MyObjectPropertyProperty  =
        DependencyProperty.Register(
" MyObjectProperty " typeof ( object ),  null );  

}


   这是该属性的默认设计时:



   我们通过创建一个简单的TypeConverter开始:
 

public   class  myTypeConverter : TypeConverter
{
    
public   overrIDe   bool  GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        
return   true ;
    }

    
public   overrIDe  TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        
return   new  StandardValuesCollection( new   string [] {  " Hello "  , " World " " foo " " bar " });
    }
}



   该类型converter 的工作就是对任何使用该converter的属性写入相应的(可能)值(以代码方式).

   下面在共享设计时Metadata中,我们加入了对该 TypeConverter的引用:
  
AddMemberAttributes( typeof (myControl),  " MyObjectProperty " ,
        
new  TypeConverterattribute( typeof (myTypeConverter)));

 

 

   然后我们在 Blend应用它:





   我们得到了一系列可供选择的值(以代码方式).


   同样,我们可以使用内置式的TypeConverters,比如 Boolean Converter:

     AddMemberAttributes( typeof (myControl),
        
new  TypeConverterattribute( typeof (BooleanConverter)));

   这是它在 Blend的效果:




   某些TypeConverters 甚至提供了可视工具化的提示,用来设置当前属性.
   下面就是一个不错的例子,ExpandleTypeConverter:

    AddMemberAttributes( typeof (myControl),
        
new  TypeConverterattribute( typeof (ExpandableObjectConverter)));

   这是它在 Blend的效果:



   然后点击“new” 按钮会d出一个“对象”对话框:






PropertyOrderAttribute (Shared)

    Property order 属性可以让我们定义已存在的属性在某分类下的排序位置.

    我们通过定义三个属性来加以说明,为此我打算将MyIntProperty挪到 advanced 区域外. (在blend 设计时的元数据文件)

    AddMemberAttributes( typeof  (myControl),
          
new  EditorbrowsableAttribute(EditorbrowsableState.Advanced));

    在取消 MyIntProperty隐藏之后,下面是我们默认的属性排序:





    它是基于字母排序方式的.

    首先“MyIntProperty”,第二“MyObjectProperty” ,然后第三 “My String Property”.

    现在我们想让 MyStringProperty 排在第一的位置.

    AddMemberAttributes( typeof (myControl),  " MyStringProperty " ,
        
new  PropertyOrderAttribute(PropertyOrder.Early));

    这是它在 Blend的效果:




    我有点想看一下这个PropertyOrder 类了. 让我们仔细看一下它的 static 成员.



    好的,现在我想让MyIntProperty 显示在最后.

    AddMemberAttributes( typeof (myControl),
        
new  PropertyOrderAttribute(PropertyOrder.Late));

    我们看到在Blend中该属性目前是最后一项了:




    那如果我们将 MyObjectProperty 与“My String Property” 同时定义在PropertyOrder.Early?
     AddMemberAttributes( typeof (myControl),
        
new  TypeConverterattribute( typeof (ExpandableObjectConverter)),
        
new  PropertyOrderAttribute(PropertyOrder.Early));

    它们会首先会 property order 排序,然后是基于字母排序:



    因为“MyObjectProperty” 与“My String Property” 都有相同的property order,它们会在内部通过字母进行排序.

    现在,基于练习的原因,我会让当前的Property Ordering 相同并在内部对这些属性进行手工排序.
我们尝试将“My String Property” 移到“MyObjectProperty”之前.
     AddMemberAttributes( typeof (myControl),
        
new  PropertyOrderAttribute(PropertyOrder.CreateAfter(PropertyOrder.Early)));

    然后我们会看到MyObjectProperty 排到了“My String property”之后:





    注意:PropertyOrder.CreateBefore/After 方法会返回一个PropertyOrder,我们可以依据我们的喜好手工进行排序。

    ( 注:作者在此处又结束了一篇,下面是接下来的内容


NumberRangeAttribute,NumberIncrementAttribute,NumberFormatAttribute (Blend)

    在Expression DLLs中这些属性很重要,因此它们被用在了 Blend(当然项目)中.

    让我们看一个我们在什么属性上声明使用了它们: Opacity

   




    首先我们注意在此处有一个比例数值. Opacity 被显示为百分比格式.

    接着我们看到有一个标识符‘%’跟在该数值后. 现在我们通过鼠标滚轮加/减当前数值.

   






    如果我们 drag 鼠标并按 SHIFT 键会看到递增单位被加的更大:

   


 

    或drag 鼠标并按CTRL + SHIFT  键会看到递增单位被加的更小:

   




   (通过上面的演示)我们能看出两件事:

1. 有三种 increments/decrements 方式– Small,Largenormal

2. 存在0-100的数值范围

   这两种情况我们之前都看到了,其就是基于这些属性实现的.

   让我们看一下这些属性的构造方法:




NumberRangeAttribute 属性可以让我们指定最小 & 最大值的范围.



NumberIncrementAttribute 属性可以让我们指定small,default 和large 递增类型.





NumberFormatAttribute 属性可以让我们指写显示内容的格式,数字精度,显示比率等.

   在我们的blend Metadata 文件中,为MyIntProperty 添加下列属性:

   将数值范围限制在1-100之间,指定increments 为0.5,1 和 5,显示比率为 x10 以及格式为 “X%”.

   我们将范围限制在1-100:

  AddMemberAttributes( typeof (myControl),
                    
new  NumberRangesAttribute( null 1 100 null null ));



   分别添加 0.5,1 和 5 increments 用于small,default 和 large increments:

  AddMemberAttributes( typeof (myControl),  null ),
                    
new  NumberIncrementsAttribute( 0.5 5 ));


   最后添加‘X%’格式用于显示10的比率.


 AddMemberAttributes( typeof (myControl),  5 ),
                    
new  NumberFormatAttribute( " 0'%' " 10 ));


   运行这个例子并采用普通 dragging :
 

 




   然后drag 并按下SHIFT 键:

   



   这是MyIntProperty实际初始值:



   我们得到了我们想要的: 取值范围在0-100,显示比率,格式以及increments.

   ( 注:原文作者在此又结束了一章


ToolBoxbrowsableAttribute (Shared)
 
    我们将几个控件编译在一起然后在Visual studio Silverlight 工具栏中添加它们或放在Blend库中.

    如果我们打算隐藏这些控件中的一个时,我们可以使用ToolBoxbrowsableAttribute . 一个不错的
例子就是ComboBox 是可见的,但ComboBoxItem 被隐藏,日期可见但Daybutton 不可见等等.

    在Visual Studio 2008 SP1,Blend 2 SP1这两个工具中,该属性仅是设计时属性.

    下面我们创建另一个控件.

public   class  myOtherControl : Control
{
}



    在Blend 里,我们会在asset gallery中看到一个新的控件:




    在Visual studio 里,我们打开 “Choose Items” 对话框,找到“SIlverlightControls.dll” 并点击.





@H_403_2343@




    现在,我们着手在这些对话框中隐藏myOtherControl。 我们在共享设计时元数据项目中添加 ToolBoxbrowsableAttribute。

AddTypeAttributes( typeof (myOtherControl),
        
new  ToolBoxbrowsableAttribute( false ));


    之后编辑并重启 blend,我们看到在Blend 的Asset gallery中不再出现该控件了:




    然后在Visual studio 的“Choose Items” 对话框中也没再显示myOtherControl:







Inline Editors (Shared)

     Editors 是一个在Visual Studio 属性窗口和 Blend Data Pane中的定制元素.

     下面是一些已知的editors 例子:
 









     我们在custom project 项目中定义我们的editors 以避免Silverlight dlls 的二义性引用(ambiguous references).




    Naming convention and the very existence of this project are optional.

    我们添加一些必要的设计时引用.



    也要确保在 “SilverlightControls.Design.dll” 中对“SilverlightControls.Design.Editors.dll”的引用.

 

    我们着手在Editors项目中添加一个ResourceDictionary,将其命名为“EditorDictionary”.



    在EditorResources.xaml 里添加如下的DataTemplate:

< ResourceDictionary xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation "

   xmlns:x
= " http://schemas.microsoft.com/winfx/2006/xaml " >

    
< DataTemplate x:Key = " colorsComboBox " >

        
< ComboBox Text = " {Binding StringValue} "  IsEditable = " True " >

            
< ComboBoxItem Background = " Red " > Red </ ComboBoxItem >

            
< ComboBoxItem Background = " Blue " > Blue </ ComboBoxItem >

            
< ComboBoxItem Background = " Green " > Green </ ComboBoxItem >

            
< ComboBoxItem Background = " Yellow " > Yellow </ ComboBoxItem >

            
< ComboBoxItem Background = " Black " > Black </ ComboBoxItem >

        
</ ComboBox >

    
</ DataTemplate >

</ ResourceDictionary >


    我们得到了一个包括一些ComboBoxItems的 ComboBox。 唯一重要的就是通过设计工具确保字符值以或数值被绑定到.

    下面我们添加了一些静态类来访问我们的Resource dictionary.

public   static   class  EditorDictionary
{
    
private   static  ResourceDictionary dictionary  =  (ResourceDictionary)Application.LoadComponent( new  Uri( " SilverlightControls.Design.Editos;component/EditorDictionary.xaml " , UriKind.relative));

    
public   static  DataTemplate colorsComboBox
    {
        
get
        {
            
return  dictionary[ " colorsComboBox " as  DataTemplate;
        }
    }
}



    这个类要做的就是加载Resource dictionary 并包含一个返回我们 DateTemplate的静态属性.

    现在让我们看一个感兴趣的地方,我们会创建一个显示DataTemplate的自定义inline editor.

public   class  CustomInlineEditor : PropertyValueEditor
{
    
public  CustomInlineEditor()
    {
        
this .InlineEditorTemplate  =  EditorDictionary.colorsComboBox;
    }
}


    非常直接. PropertyValueEditor 一个有趣的地方 - 这个(我们用于设置DataTemplate)InlineEditorTemplate取自resource dictionary.

    最后必须要说的是MyControl.MyStringProperty 有一个自定底 inline editor.

    AddMemberAttributes( typeof (myControl),
        
new  PropertyOrderAttribute(PropertyOrder.Early),
        PropertyValueEditor.CreateEditorAttribute(
typeof (CustomInlineEditor)));
 
    在Blend里的效果:




    然后,我们选取“Green”.


   





    在UI和XAML之间来回进行驱动的是ComboBox 到 StringValue的绑定.

    我想从这个练习中得到的不应该是“rainbow colored ComboBoxes不错” 或“要将任何元素都做为一个inline editor”.


    现在我们看到editor 的样子以及它是如何工作的,我们应该熟悉3种类型的属性 editors.

    Inline Property Editor :下面的“单行并有属性名称和编辑框” 样式.
 


 



    Extended Property Editor:有内部的editor,但也可根据用户 *** 作d出或占用一些区域(显示).

 








Dialog property editor – 一个具有触发对话框按钮的Inline property editor.

 







Expended Property Editor

    正如上面所见,一个expended property editor 就是一个inline editor,其基于用户 *** 作来占用更大的屏幕区域.
    让我们看看如何创建它.
    我们着手在EditorResources.xaml文件中创建另一个 DataTemplate(InlineValueEditorTemplate):

     < DataTemplate x:Key = " SimpleTextBox " >

        
< StackPanel OrIEntation = " Horizontal " >

            
< TextBox Text = " {Binding StringValue} "   />

            
< PropertyEditing:EditModeSwitchbutton  />

        
</ StackPanel >

    
</ DataTemplate >

   我们看到仅有一个绑定StringValue的TextBox。我们在前面的inline property editor中已看到过.

      有趣的是这里有一个“EditModeSwitchbutton”. 它内置一个extensibility 按钮,它可展开/收缩extended template
视图.这个按钮的作用就是链接到 extensibility 的PropertyValueEditorCommands,该命令负责显示或隐藏extended视图.

   现在我们有了InlineValueEditorTemplate,下面添加另外一个 DataTemplate(ExtendedValIEEditorTemplate):
  
< DataTemplate  x:Key ="HelloWorldListBox" >

        
< ListBox  SelectedItem =" {Binding StringValue} " >

            
< ListBox.ItemsSource >

                
< x:Array  Type =" {x:Type System:String} " >

                    
< System:String > Hello </ System:String >

                    
< System:String > World </ System:String >

                    
< System:String > foo </ System:String >

                    
< System:String > bar </ System:String >

                
</ x:Array >

            
</ ListBox.ItemsSource >

            
< ListBox.ItemTemplate >

                
< DataTemplate >

                    
< TextBlock  Text =" {Binding} "   />

                
</ DataTemplate >

            
</ ListBox.ItemTemplate >

        
</ ListBox >

    
</ DataTemplate >

    尽管这个DataTemplate 看着有点意思,然而实际上并不是这样. 它仅是一组在ListBox中作为 TextBlock显示出来的字符串.
唯一有趣的是它是我们将这个ListBox 的SelectedItem 绑定到 StringValue.

    下面,我们会在EditorDictionary类中创建这两个强类型(命名)的属性:

public   static  DataTemplate SimpleTextBox
{
    
get
    {
        
return  dictionary[ " SimpleTextBox " as  DataTemplate;
    }
}

public   static  DataTemplate HelloWorldListBox
{
    
get
    {
        
return  dictionary[ " HelloWorldListBox " as  DataTemplate;
    }
}

     最后,我们创建一个ExtendedValuepropertyeditor 来使用我们上面的两个新的 DataTemplates:

public   class  CustomExtendedEditor : ExtendedPropertyValueEditor
{
    
public  CustomExtendedEditor()
    {
        
this .InlineEditorTemplate  =  EditorDictionary.SimpleTextBox;
        
this .ExtendedEditorTemplate  =  EditorDictionary.HelloWorldListBox;
    }
}


 

    还有要把CustomExtendedEditor绑定到我们的 MyStringProperty 上:

    AddMemberAttributes( typeof (myControl),
        PropertyValueEditor.CreateEditorAttribute(
typeof (CustomExtendedEditor)));

   这是在 Blend 中的效果:


   
   点击该按钮之后 ,我们就得到了这个ExtendedEditorTemplate d出框:




   我们点击另一个按钮会看到ExtendedEditorTemplate 在data pane里占用了更多的空间:



   选择这个列表项中的任一个值都会造成TextBox 和后面属性的更新:


    




   并再点击按钮时会关闭该extended editor:




Dialog Property Editor

    除了用 Extended template 显示 inline editor,我们可能打算用d出对话框方式来显示(inline editor).

我们使用已存在的resource dictionary来创建一个对话框 editor 。

     public   class  CustomDialogEditor : DialogPropertyValueEditor
    {
        
public  CustomDialogEditor()
        {

            
this .InlineEditorTemplate  =  EditorDictionary.SimpleTextBox;

            
this .DialogEditorTemplate  =  EditorDictionary.HelloWorldListBox;
        }
    }


    我们需要将custom dialog editor 绑定到MyStringProperty上:

    AddMemberAttributes( typeof (myControl),
        PropertyValueEditor.CreateEditorAttribute(
typeof (CustomDialogEditor)));

 

     当在 Blend 中运行时:




    
     然后在该对话模中修改值也将会造成TextBox 和后面属性值的变化:






    尽管Dialog property editors 与extended property editors有相似的API,但却有一个主要不同– 它支持事务

(transactions).


    您看到的“OK” 和“Cancel” 按钮就是基于触发CommitTransaction 或 AbortTransaction 命名而定义的.

那么,如果我们在选择“World”之后点击 cancel,该属性会回复到它的原始值“foo”:





     希望您从这个tutorial中学到一些知识,  它包括许多 knocks 和 crannIEs,但这应该让您明确您自己要采用的方式,

                                                                                                       -- Justin Angel

                                                                              Microsoft Silverlight Toolkit Program Manager



     


     译者: 能看到这里的都不是凡人,起码你有时间一路阅读下来


     好了,今天的内容就到这里。

 

     原文链接:http://www.cnblogs.com/daizhj/archive/2008/11/27/1342175.html

     作者: daizhj,代震军

     Tags: silverlight,blend,wpf,design-time,run-time,interface,Extensibility,设计时,运行时,扩展

     网址: http://daizhj.cnblogs.com/

      总结

以上是内存溢出为你收集整理的翻译:SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)全部内容,希望文章能够帮你解决翻译:SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1052398.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)