【翻译】SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)
嗨伙計們,
???? 只要有人談到開發(fā)者與設計師在 Silverlight/WPF上協同工作時,他們就會談論“設計,開發(fā)工作流程”這個
問題。即使您是您自己的設計師,這工作也始終是永遠存在于當你在“設計師”和“開發(fā)”之間切換“帽子”的過程中。
???? 我是一個使用工具創(chuàng)建用戶界面的支持者。 我的生活讓我不能理解為什么有人會選擇非產能(non-productive)
和手寫XAML的事情。
???? 你能找出的一個情況就是當你使用(Expression Blend & Visual Studio WPF/Silverlight Designer)這類工
具進行工作時,如果使用正確,這些工具會對提高生產力起到巨大的推動作用。然而,這篇帖子不是關于如何使用
這類工具,而是關于如何幫助那些使用您的控件作為工具進行設計的人。本文是關于開發(fā)者著手去讓設計師有更容
易的(設計)體驗并減少摩擦。
???? 控件提供商和開發(fā)者通常都想給自己的控件以更好的體驗。然而,在這個問題上其缺乏大量的信息。我決定用
本文糾正這種情況。
?? 本文也與那些在項目中有設計師一起工作的開發(fā)者有關。我建立的解決方案可在這里下載,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?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中,它的樣子:
?
??? 這一做法有哪些優(yōu)勢?
1.將設計時代碼與運行時代碼解耦有助于創(chuàng)造更好的代碼。?(分離的問題,POCO,單一的責任等)
2.基于工具修改設計時屬性。這種做法允許支持不同的設計時屬性,而這些屬性基于它們運行的工具。
3.設計時變更無須重新編譯運行時組件。
4.不是運行時組裝的author可以添加設計時屬性。
5.高級的設計時支持,并不需要我們使用GUIDs注冊Visual?Studio軟件包。
參考架構
?? 這里有一些步驟. 從本質上講,我們要建立以下結構:
??? 一點都不亂(譯者注:我看有點亂,呵呵),是吧?簡單地說,這僅僅是參考模型。
??? 我們將創(chuàng)建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?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. 創(chuàng)建共享運行時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. 創(chuàng)建visual studio 設計時DLL.
?? 因為要添加的設計時用于“SilverlightControls” 所以這里命名為:“SilverlightControls.VisualStudio.Design”.
6. 在項目“SilverlightControls.VisualStudio.Design” 中添加對“SilverlightControls”的引用, 以及
Microsoft design time assemblies 和 Silverlight System.Windows.dll.
?
?
?
? ? 這里我們添加的引用:
7. 創(chuàng)建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 僅被創(chuàng)建一次,并且提
供了簡單的訪問方法,這些方法我們會在本DEMO中到處使用。
?? 好,這就是我們當前的項目結構:
??
?? 注:我們在每個項目中都已有了一個metadata 類.
?
?? 10. 安裝設計時文件拷貝。
?????? 設計時DLL文件須與運行時DLL文件放在相同的目錄下. ?
?????? 我喜歡自動完成相關的*design.dll 文件拷貝. 你可以手工完成這一操作。
??? 我使用的自動方式是添加一條 post-build action 到每個設計時項目中.
??? 右擊我們的項目文件 –> “屬性” –> “生成事件”. 粘帖下面內容到Post Build Events:
???
copy?"$(TargetPath)"?"$(SolutionDir)"SilverlightControls"Bin"Debug"
??? 在所有的三個設計時項目中重復這一步驟.
?? ?
創(chuàng)建我們的測試項目
?
1. 我們使用BLEND創(chuàng)建一個新的項目來使用我們的DLL. 我們會使用該項目來預覽我們的設計時改進。 ?2. 添加對“SilverlightControls.dll”的引用.
?
?
?? 這時發(fā)生了什么?
?? 我們有了兩個設計時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 設計器
?
?? 現在我們有了這個基本架構,接下來就開始用一下吧.
?? (注:原文作者在這里好像就做了一個章節(jié),下面是后續(xù)的文章內容:屬性講解)
?
?
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中,我們看到它被移動到了那個分類下:
??? 我們可能想去創(chuàng)建我們自己在分類,該分類我們稱之為“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 屬性允許我們隱藏一些屬性,這些屬發(fā)現在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 高級狀態(tài)可以讓你在
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);??
}
?? 這是該屬性的默認設計時:
?? 我們通過創(chuàng)建一個簡單的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 區(qū)域外. (在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, Large 和 normal
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(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 :
?
?
?? 然后drag 并按下SHIFT 鍵:
???
?? 這是MyIntProperty實際初始值:
?? 我們得到了我們想要的: 取值范圍在0-100, 顯示比率, 格式以及increments.
?? (注:原文作者在此又結束了一章)
ToolboxBrowsableAttribute (Shared)
?
??? 我們將幾個控件編譯在一起然后在Visual studio Silverlight 工具欄中添加它們或放在Blend庫中.
??? 如果我們打算隱藏這些控件中的一個時, 我們可以使用ToolboxBrowsableAttribute . 一個不錯的
例子就是ComboBox 是可見的,但ComboBoxItem 被隱藏, 日期可見但DayButton 不可見等等.
??? 在Visual Studio 2008 SP1, Blend 2 SP1這兩個工具中,該屬性僅是設計時屬性.
??? 下面我們創(chuàng)建另一個控件.
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。 唯一重要的就是通過設計工具確保字符值以或數值被綁定到.
??? 下面我們添加了一些靜態(tài)類來訪問我們的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的靜態(tài)屬性.
??? 現在讓我們看一個感興趣的地方, 我們會創(chuàng)建一個顯示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, 但也可根據用戶操作彈出或占用一些區(qū)域(顯示).
?
Dialog property editor – 一個具有觸發(fā)對話框按鈕的Inline property editor.
?
Expended Property Editor
??? 正如上面所見, 一個expended property editor 就是一個inline editor,其基于用戶操作來占用更大的屏幕區(qū)域.
??? 讓我們看看如何創(chuàng)建它.
??? 我們著手在EditorResources.xaml文件中創(chuàng)建另一個 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類中創(chuàng)建這兩個強類型(命名)的屬性:
public?static?DataTemplate?SimpleTextBox
{
????get
????{
????????return?dictionary["SimpleTextBox"]?as?DataTemplate;
????}
}
public?static?DataTemplate?HelloWorldListBox
{
????get
????{
????????return?dictionary["HelloWorldListBox"]?as?DataTemplate;
????}
}
???? 最后,我們創(chuàng)建一個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來創(chuàng)建一個對話框 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” 按鈕就是基于觸發(fā)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/
??? ?
轉載于:https://www.cnblogs.com/daizhj/archive/2008/12/11/1342175.html
總結
以上是生活随笔為你收集整理的【翻译】SILVERLIGHT设计时扩展(注:内容超长,请用IE浏览)的全部內容,希望文章能夠幫你解決所遇到的問題。