編寫CodeSmith自定義屬性的編輯器(Writing Custom Property Editors)
當你開始編寫自定義的CodeSmith模板時,很可能對於使用它的strings或integers屬性很滿意,但有時你會發現需要創建一個不同類型的屬性,可能是一個自定義的類型或者是.NET framework中但是在屬性面板中沒有提供的類型。在模板中去作這些很簡單,但是怎樣指定一個類型在運行模板時顯示在屬性面板中呢?例如創建了一個Person類並且具有很多不同的屬性,但是卻沒有辦法讓用戶去組裝這個類……除非創建一個自定義屬性編輯器。 屬性面板提供了方法去編寫自定義的屬性編輯器,當用戶在面板上選擇一個屬性時可以激發相應的方法,同時也可以通過編寫代碼實現提示用戶輸入一個必要的值。下面我們舉個例子,創建一個接受組建的屬性並且是用影射循環貫串所有的類,是所有的類都可以使用它和它的方法,去創建一個NUnit測試基礎。(這句翻譯的不好,原文:As an example we are going to build a template which accepts an assembly as a property and then using reflection loops through all of the classes, and the methods of those classes, to build NUnit test stubs.) 首先,我們來關注一下模板的組件屬性,暫且不看自定義編寫的代碼。模板的第一部分是一些聲明定義和屬性。將屬性放在腳本標籤中代替使用屬性聲明,在下一部分將看到這樣做的必要。
2
3<%@ Import NameSpace="System.Reflection"%>
4
5<script runat="template">
6
7private Assembly assembly;
8
9public Assembly AssemblyToLoad
10{
11get{return assembly;}
12set{assembly = value;}
13}
14
15</script>
然後我們爲組建assembly中的每一個類創建一個類,爲每一個類創建他的方法。然後直接將模板的輸出內容放入Visual Studio.NET,然後在編寫組件的單元測試時使用嚮導。
2using NUnit.Framework;
3
4<%
5foreach(Type T in AssemblyToLoad.GetTypes())
6{
7if(T.IsClass)
8{
9%>
10
11 [TestFixture]
12publicclass<%=T.Name%>Tests
13{
14<%
15 MethodInfo[] methods = T.GetMethods ( BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static );
16foreach(MethodInfo M in methods)
17{
18%>
19
20 [Test]
21publicvoid<%=M.Name%>Test
22{
23//TODO Write this test
24 }
25<%
26 }
27
28%>}<%
29 }
30 }
31%>
這個模板僅僅可以編譯通過,但是由於我們編寫顯示了一個類型屬性面板並不知道如何去操作它,所以我們沒有辦法自定義指定組件在加載時想要加載的組件。
我們需要創建一個UITypeEditor,這是一個建立屬性面板是用的特殊屬性的類。UITypeEditor需要創建在一個和模板分離的組件中,我們是用Visual Studio創建這個類。
/Files/Bear-Study-Hard/AssemblyHelper.zip
首先我們需要創建一個繼承UITypeEditor的類。
2{
3public AssemblyFilePicker(): base()
4{
5 }
6}
關於UITypeEditor的說明請大家參看M?xml:namespace>
然後我們需要重載UITypeEditor類的兩個不同的方法。第一個需要重載點的方法是GetEditStyle,這個方法是告訴屬性面板對於當前類型是用什麼類型的編輯器,在這個例子中我們設置編輯類型爲Modal。這樣大家可以在該屬性格子的右邊看到一個小按鈕,它將引發一個對話框等模式的對話(trigger a modal dialog)。這是我們的GetEditStyle方法:
2{
3return UITypeEditorEditStyle.Modal;
4}
其中的Modal爲顯示一個省略號按鈕。
需要重載的另一個方法是EditValue方法,當用戶電擊屬性時會調用這個方法。按照我們需要加載的組件類型需要創建一個打開文件對話框(open file dialog)然後捕獲這個對話框,在屬性格子中返回對話框的結果。
2{
3
4if (provider !=null)
5{
首先我們要從當前的服務和控件中得到一個參考,有了控件的參考我們可以通過它轉到ShowDialog方法。(原文:First we need to get a reference to the current service and control, we need the reference to the control so we can pass it to the ShowDialog method.)
2Control editorControl = editorService as Control;
3
4if (editorControl !=null)
5{
然後我們創建一個openFileDialog類並填入適合的屬性。
2
3openFileDialog.CheckFileExists =true;
4openFileDialog.DefaultExt =".dll";
5openFileDialog.Multiselect =false;
6openFileDialog.Title ="Select an Assembly:";
7openFileDialog.Filter ="Assembly Files | *.dll";
然後我們通過控件的參考(reference)將對話框顯示給用戶。
下一步我們檢查用戶是否點擊了OK按鈕,如果點擊了,通過文件選擇對話框選擇文件後使用LoadForm方法加載這個組件,最後返回這個值。
2{
3Assembly assembly = Assembly.LoadFrom( openFileDialog.FileName ) ;
4 value = assembly;
5 }
6else
7{
8 value =null;
9 }
10 }
11}
12
13return value;
14}
這個值將被放在屬性面板中並可以被模板讀取,但是需要注意,在我們作這個之前要將組件import引入到模板中,並在模板中用一對屬性聲明。
加載這個模板我們僅需將這個組件assembly與模板放在同一目錄下,然後再模板中加入下面兩行代碼。
2<%@ Import NameSpace="AssemblyHelper" %>
然後我們要在組建屬性中添加Editor屬性,並且指定爲UITypeEditor編輯器。
2public Assembly AssemblyToLoad
3{
4get{return assembly;}
5set{assembly = value;}
6}
當屬性面板讀取到這些屬性時,它將使用我們自定義的UITypeEditor編輯器並允許用戶從打開文件對話框中選擇一個組件。
http://www.cnblogs.com/Bear-Study-Hard/archive/2005/12/26/304701.html