zoukankan      html  css  js  c++  java
  • 【翻译】SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)

    原文链接: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 { getset;  }
    }


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

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


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

    public class myControl : Control
    {
        
    public string MyStringProperty { getset;  }
    }


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

    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, params Attribute[] attribs)
            {
                
    base.AddCallback(type, 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),"MyStringProperty",
        
    new DescriptionAttribute("I am a property"),
        
    new DisplayNameAttribute("My String Property"),
        
    new CategoryAttribute("Common Properties"));

     

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




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

    AddMemberAttributes(typeof(myControl),"MyStringProperty",
        
    new DescriptionAttribute("I am a property"),
        
    new DisplayNameAttribute("My String Property"),
        
    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",typeof(string), typeof(myControl), null);

     

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

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

    }



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

       
    AddMemberAttributes(typeof(myControl),"MyStringProperty",
            
    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),"MyStringProperty",
            
    new DescriptionAttribute("I am a property"),
            
    new DisplayNameAttribute("My String Property"),
            
    new CategoryAttribute("My Category")); 

        AddMemberAttributes(
    typeof(myControl), "MyIntProperty",
            
    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), "MyIntProperty",
                
    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), typeof(myControl), 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 CategoryAttribute("My Category"),
            
    new TypeConverterAttribute(typeof(myTypeConverter)));

       然后我们在 Blend应用它:





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


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

     
       AddMemberAttributes(typeof(myControl), "MyObjectProperty",
            
    new CategoryAttribute("My Category"),
            
    new TypeConverterAttribute(typeof(BooleanConverter)));


       这是它在 Blend的效果:




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

        AddMemberAttributes(typeof(myControl), "MyObjectProperty",
            
    new CategoryAttribute("My Category"),
            
    new TypeConverterAttribute(typeof(ExpandableObjectConverter)));


       这是它在 Blend的效果:



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






    PropertyOrderAttribute (Shared)

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

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

     
      AddMemberAttributes(typeof (myControl), "MyIntProperty",
              
    new EditorBrowsableAttribute(EditorBrowsableState.Advanced));


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





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

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

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

        AddMemberAttributes(typeof(myControl), "MyStringProperty",
            
    new DescriptionAttribute("I am a property"),
            
    new DisplayNameAttribute("My String Property"),
            
    new CategoryAttribute("My Category"),
            
    new PropertyOrderAttribute(PropertyOrder.Early));


        这是它在 Blend的效果:




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


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

     
      AddMemberAttributes(typeof(myControl), "MyIntProperty",
            
    new CategoryAttribute("My Category"),
            
    new PropertyOrderAttribute(PropertyOrder.Late));


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




        那如果我们将 MyObjectProperty 与“My String Property” 同时定义在PropertyOrder.Early?
     
       AddMemberAttributes(typeof(myControl), "MyObjectProperty",
            
    new CategoryAttribute("My Category"),
            
    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), "MyObjectProperty",
            
    new CategoryAttribute("My Category"),
            
    new TypeConverterAttribute(typeof(ExpandableObjectConverter)),
            
    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), "MyIntProperty",
                        
    new NumberRangesAttribute(null1100nullnull));



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

     
    AddMemberAttributes(typeof(myControl), "MyIntProperty",
                        
    new NumberRangesAttribute(null1100nullnull),
                        
    new NumberIncrementsAttribute(0.515));


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


     AddMemberAttributes(typeof(myControl), "MyIntProperty",
                        
    new NumberRangesAttribute(null1100nullnull),
                        
    new NumberIncrementsAttribute(0.515),
                        
    new NumberFormatAttribute("0'%'"null10));


       运行这个例子并采用普通 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” 并点击.








        现在,我们着手在这些对话框中隐藏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), "MyStringProperty",
            
    new DescriptionAttribute("I am a property"),
            
    new DisplayNameAttribute("My String Property"),
            
    new CategoryAttribute("My Category"),
            
    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, 但也可根据用户操作弹出或占用一些区域(显示).

     






    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), "MyStringProperty",
            
    new DescriptionAttribute("I am a property"),
            
    new DisplayNameAttribute("My String Property"),
            
    new CategoryAttribute("My Category"),
            
    new PropertyOrderAttribute(PropertyOrder.Early),
            PropertyValueEditor.CreateEditorAttribute(
    typeof(CustomExtendedEditor)));


       这是在 Blend 中的效果:

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




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



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


        


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




    Dialog Property Editor

        除了用 Extended template 显示 inline editor, 我们可能打算用弹出对话框方式来显示(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), "MyStringProperty",
            
    new DescriptionAttribute("I am a property"),
            
    new DisplayNameAttribute("My String Property"),
            
    new CategoryAttribute("My Category"),
            
    new PropertyOrderAttribute(PropertyOrder.Early),
            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/


         
  • 相关阅读:
    POJ2976 Dropping tests 01分数规划
    POJ 2728 Desert King 01分数规划,最优比率生成树
    codeforces 675E Trains and Statistic 线段树+贪心统计
    codeforces 675D Tree Construction set
    UVA 11235Frequent values(RMQ)
    FZU 2105Digits Count(线段树 + 成段更新)
    HDU 4006The kth great number(K大数 +小顶堆)
    UVA 624CD(01背包输出 + 输出路径)
    HDU 1796How many integers can you find(容斥原理)
    HDU 1817Necklace of Beads(置换+Polya计数)
  • 原文地址:https://www.cnblogs.com/daizhj/p/1342175.html
Copyright © 2011-2022 走看看