天天看點

翻譯: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 {  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中,它的樣子:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    這一做法有哪些優勢?

1.将設計時代碼與運作時代碼解耦有助于創造更好的代碼。 (分離的問題,POCO,單一的責任等)

2.基于工具修改設計時屬性。這種做法允許支援不同的設計時屬性,而這些屬性基于它們運作的工具。

3.設計時變更無須重新編譯運作時元件。

4.不是運作時組裝的author可以添加設計時屬性。

5.進階的設計時支援,并不需要我們使用GUIDs注冊Visual Studio軟體包。

參考架構

   這裡有一些步驟. 從本質上講,我們要建立以下結構:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    一點都不亂( 譯者注:我看有點亂,呵呵),是吧?簡單地說,這僅僅是參考模型。

    我們将建立3個新項目。

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

 *. Design.dll -将包含設計時屬性,這些屬性用于Visual Studio WPF/Silverlight設計器和Expression Blend。

 *. VisualStudio.design.dll -将包含設計時的功能,僅用于Visual Studio。

 *. Expression.design.dll -将包含設計時的功能,僅用于Expression blend。

   這種命名約定是強制性的。

   第一步是增加項目引用,我們會在該項目中添加設計時支援用于設計時元件:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   添加對共享設計時dll的引用:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   并添加Blend design-time 引用:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

步驟:

1. 添加一個Silverlight 類庫,該類庫會包含我們的控件. 我們将它命名為:SilverlightControls.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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 特性.如果喜歡,我們可以手工添加引用到普通類庫項目中。  

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

4. 在“SilverlightControls.Design” 項目中添加對“SilverlightControls” 項目的引用,  以及Microsoft design time 元件和

Silverlight System.Windows.dll.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   (Silverlight 2 引用路徑– 預設位于 c:"Program Files"Microsoft SDKs"Silverlight"v2.0"Reference Assemblies)

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   這是我們引用的元件: 

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

5. 建立visual studio 設計時DLL.

   因為要添加的設計時用于“SilverlightControls” 是以這裡命名為:“SilverlightControls.VisualStudio.Design”.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

6. 在項目“SilverlightControls.VisualStudio.Design” 中添加對“SilverlightControls”的引用, 以及

Microsoft design time assemblies 和 Silverlight System.Windows.dll.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    這裡我們添加的引用:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

7. 建立expression blend 設計時 DLL.

   因為要添加的設計時用于“SilverlightControls” 是以這裡命名為“SilverlightControls.Expression.Design”.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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

design time assemblies 和 Blend specific dlls。

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   這裡我們添加的引用:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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中到處使用。

   好,這就是我們目前的項目結構:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   注:我們在每個項目中都已有了一個metadata 類.

   10. 安裝設計時檔案拷貝。

       設計時DLL檔案須與運作時DLL檔案放在相同的目錄下.  

       我喜歡自動完成相關的*design.dll 檔案拷貝. 你可以手工完成這一操作。

    我使用的自動方式是添加一條 post-build action 到每個設計時項目中.

    右擊我們的項目檔案 –> “屬性” –> “生成事件”. 粘帖下面内容到Post Build Events:

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

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    在所有的三個設計時項目中重複這一步驟.

建立我們的測試項目

1. 我們使用BLEND建立一個新的項目來使用我們的DLL. 我們會使用該項目來預覽我們的設計時改進。  

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   這時發生了什麼?

   我們有了兩個設計時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看一下這些描述。

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

DisplayNameAttribute (shared)

    顯示名稱屬性用于顯示類型成員的(friendlier)名稱.

    AddMemberAttributes(typeof(myControl),"MyStringProperty",

        new DescriptionAttribute("I am a property"),

        new DisplayNameAttribute("My String Property"));

    下面是其在 Blend中的顯示:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

CategoryAttribute (shared)

    每個屬性都有一個預設分類. Blend 為我們的控件定義如下分類:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    預設情況下,我們的屬性添加到了“Miscellaneous” 分類. 如果想重新定義它,我們可讓它在别處。

    我們可能想讓我們的屬性添加到已有的分類中,比如“Common Properties”.

AddMemberAttributes( typeof (myControl), " MyStringProperty " ,

     new  DescriptionAttribute( " I am a property " ),

     new  DisplayNameAttribute( " My String Property " ),

     new  CategoryAttribute( " Common Properties " ));

    在Blend中,我們看到它被移動到了那個分類下:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    我們可能想去建立我們自己在分類,該分類我們稱之為“My Category”.

AddMemberAttributes( typeof (myControl), " MyStringProperty " ,

     new  DescriptionAttribute( " I am a property " ),

     new  DisplayNameAttribute( " My String Property " ),

     new  CategoryAttribute( " My Category " ));

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    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’中有兩個屬性:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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中不在有該屬性了:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    我們能夠使用 browsable 屬性隐藏一些繼承的屬性以及我們自定義的屬性.

EditorBrowsableAttribute (Blend)

    我僅在Blend 設計時項目中标記了這個屬性, 但這是出于我對Visual Studio Silverlight 設計器的猜測.

這可能在VS的一些流行特征中支援, 但我建議在使用之前先考慮它。Editor Browsable 進階狀态可以讓你在

Blend 中的一個分類下隐藏一些屬性,除非使用者喜歡看到這些。基本上,隐藏一下較少使用的屬性可以讓分類

顯示更加清楚。

    讓我們打開expression blend metadata 項目中的中繼資料檔案并添加下面設計時:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

  AddMemberAttributes( typeof  (myControl),  " MyIntProperty " ,

             new  EditorBrowsableAttribute(EditorBrowsableState.Advanced));

    這是Blend 顯示的分類:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    我們會在該分類上看到一個小的“隐藏”箭頭:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    如果點選它, 會展開并顯示該分類下的所有進階屬性:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   如果使用者離開控件然後在選中它時,該分類顯示将再次關閉:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   那我們在這裡假設直到你需要時我們在顯示它.

   在Silverlight Framework 屬性裡在什麼地方應用該屬性呢? 很多地方.

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

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   然後我點選它:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   我們明白了為什麼要在同一分類下避免顯示太多的屬性.

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 );  

}

   這是該屬性的預設設計時:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   我們通過建立一個簡單的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應用它:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   我們得到了一系列可供選擇的值(以代碼方式).

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

     AddMemberAttributes( typeof (myControl),  " MyObjectProperty " ,

         new  CategoryAttribute( " My Category " ),

         new  TypeConverterAttribute( typeof (BooleanConverter)));

   這是它在 Blend的效果:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   某些TypeConverters 甚至提供了可視工具化的提示,用來設定目前屬性.

   下面就是一個不錯的例子,ExpandleTypeConverter:

    AddMemberAttributes( typeof (myControl),  " MyObjectProperty " ,

         new  CategoryAttribute( " My Category " ),

         new  TypeConverterAttribute( typeof (ExpandableObjectConverter)));

   這是它在 Blend的效果:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   然後點選“new” 按鈕會彈出一個“對象”對話框:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

PropertyOrderAttribute (Shared)

    Property order 屬性可以讓我們定義已存在的屬性在某分類下的排序位置.

    我們通過定義三個屬性來加以說明, 為此我打算将MyIntProperty挪到 advanced 區域外. (在blend 設計時的中繼資料檔案)

    AddMemberAttributes( typeof  (myControl),  " MyIntProperty " ,

           new  EditorBrowsableAttribute(EditorBrowsableState.Advanced));

    在取消 MyIntProperty隐藏之後, 下面是我們預設的屬性排序:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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

    首先“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的效果:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    我有點想看一下這個PropertyOrder 類了. 讓我們仔細看一下它的 static 成員.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    好的, 現在我想讓MyIntProperty 顯示在最後.

    AddMemberAttributes( typeof (myControl),  " MyIntProperty " ,

         new  CategoryAttribute( " My Category " ),

         new  PropertyOrderAttribute(PropertyOrder.Late));

    我們看到在Blend中該屬性目前是最後一項了:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    那如果我們将 MyObjectProperty 與“My String Property” 同時定義在PropertyOrder.Early?

     AddMemberAttributes( typeof (myControl),  " MyObjectProperty " ,

         new  CategoryAttribute( " My Category " ),

         new  TypeConverterAttribute( typeof (ExpandableObjectConverter)),

         new  PropertyOrderAttribute(PropertyOrder.Early));

    它們會首先會 property order 排序,然後是基于字母排序:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    因為“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”之後:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    注意:PropertyOrder.CreateBefore/After 方法會傳回一個PropertyOrder, 我們可以依據我們的喜好手工進行排序。

    ( 注:作者在此處又結束了一篇,下面是接下來的内容)

NumberRangeAttribute, NumberIncrementAttribute, NumberFormatAttribute (Blend)

    在Expression DLLs中這些屬性很重要, 是以它們被用在了 Blend(當然項目)中.

    讓我們看一個我們在什麼屬性上聲明使用了它們: Opacity

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    首先我們注意在此處有一個比例數值. Opacity 被顯示為百分比格式.

    接着我們看到有一個辨別符‘%’跟在該數值後. 現在我們通過滑鼠滾輪加/減目前數值.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    如果我們 drag 滑鼠并按 SHIFT 鍵會看到遞增機關被加的更大:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    或drag 滑鼠并按CTRL + SHIFT  鍵會看到遞增機關被加的更小:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   (通過上面的示範)我們能看出兩件事:

1. 有三種 increments/decrements 方式– Small, Large 和 normal

2. 存在0-100的數值範圍

   這兩種情況我們之前都看到了,其就是基于這些屬性實作的.

   讓我們看一下這些屬性的構造方法:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

NumberRangeAttribute 屬性可以讓我們指定最小 & 最大值的範圍.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

NumberIncrementAttribute 屬性可以讓我們指定small, default 和large 遞增類型.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

NumberFormatAttribute 屬性可以讓我們指寫顯示内容的格式, 數字精度,顯示比率等.

   在我們的blend metadata 檔案中, 為MyIntProperty 添加下列屬性:

   将數值範圍限制在1-100之間, 指定increments 為0.5, 1 和 5, 顯示比率為 x10 以及格式為 “X%”.

   我們将範圍限制在1-100:

  AddMemberAttributes( typeof (myControl),  " MyIntProperty " ,

                     new  NumberRangesAttribute( null ,  1 ,  100 ,  null ,  null ));

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

  AddMemberAttributes( typeof (myControl),  " MyIntProperty " ,

                     new  NumberRangesAttribute( null ,  1 ,  100 ,  null ,  null ),

                     new  NumberIncrementsAttribute( 0.5 ,  1 ,  5 ));

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

 AddMemberAttributes( typeof (myControl),  " MyIntProperty " ,

                     new  NumberRangesAttribute( null ,  1 ,  100 ,  null ,  null ),

                     new  NumberIncrementsAttribute( 0.5 ,  1 ,  5 ),

                     new  NumberFormatAttribute( " 0'%' " ,  null ,  10 ));

   運作這個例子并采用普通 dragging :

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   然後drag 并按下SHIFT 鍵:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   這是MyIntProperty實際初始值:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   我們得到了我們想要的: 取值範圍在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中看到一個新的控件:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    在Visual studio 裡,我們打開 “Choose Items” 對話框, 找到“SIlverlightControls.dll” 并點選.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    現在,我們着手在這些對話框中隐藏myOtherControl。 我們在共享設計時中繼資料項目中添加 ToolboxBrowsableAttribute。

AddTypeAttributes( typeof (myOtherControl),

         new  ToolboxBrowsableAttribute( false ));

    之後編輯并重新開機 blend, 我們看到在Blend 的Asset Gallery中不再出現該控件了:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    然後在Visual studio 的“Choose Items” 對話框中也沒再顯示myOtherControl:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

Inline Editors (Shared)

     Editors 是一個在Visual Studio 屬性視窗和 Blend Data Pane中的定制元素.

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

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

     我們在custom project 項目中定義我們的editors 以避免Silverlight dlls 的二義性引用(ambiguous references).

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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

    我們添加一些必要的設計時引用.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    也要確定在 “SilverlightControls.Design.dll” 中對“SilverlightControls.Design.Editors.dll”的引用.

    我們着手在Editors項目中添加一個ResourceDictionary,将其命名為“EditorDictionary”.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    在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裡的效果:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    然後,我們選取“Green”.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    在UI和XAML之間來回進行驅動的是ComboBox 到 StringValue的綁定.

    我想從這個練習中得到的不應該是“rainbow colored ComboBoxes不錯” 或“要将任何元素都做為一個inline editor”.

    現在我們看到editor 的樣子以及它是如何工作的, 我們應該熟悉3種類型的屬性 editors.

    Inline Property Editor :下面的“單行并有屬性名稱和編輯框” 樣式.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    Extended Property Editor:有内部的editor, 但也可根據使用者操作彈出或占用一些區域(顯示).

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

Dialog property editor – 一個具有觸發對話框按鈕的Inline property editor.

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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 中的效果:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   點選該按鈕之後 ,我們就得到了這個ExtendedEditorTemplate 彈出框:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   我們點選另一個按鈕會看到ExtendedEditorTemplate 在data pane裡占用了更多的空間:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   選擇這個清單項中的任一個值都會造成Textbox 和後面屬性的更新:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

   并再點選按鈕時會關閉該extended editor:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

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 中運作時:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

     然後在該對話模中修改值也将會造成Textbox 和後面屬性值的變化:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

    盡管Dialog property editors 與extended property editors有相似的API, 但卻有一個主要不同– 它支援事務

(transactions).

    您看到的“OK” 和“Cancel” 按鈕就是基于觸發CommitTransaction 或 AbortTransaction 命名而定義的.

那麼, 如果我們在選擇“World”之後點選 cancel,該屬性會回複到它的原始值“foo”:

翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)
翻譯:SILVERLIGHT設計時擴充(注:内容超長,請用IE浏覽)

     希望您從這個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/

繼續閱讀