CodeSmith基礎(八)

 編寫CodeSmith自定義屬性的編輯器(Writing Custom Property Editors) 

        當你開始編寫自定義的CodeSmith模板時,很可能對於使用它的stringsintegers屬性很滿意,但有時你會發現需要創建一個不同類型的屬性,可能是一個自定義的類型或者是.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.

        首先,我們來關注一下模板的組件屬性,暫且不看自定義編寫的代碼。模板的第一部分是一些聲明定義和屬性。將屬性放在腳本標籤中代替使用屬性聲明,在下一部分將看到這樣做的必要。

 1<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Builds a class for each class in the assembly, and a test stub for every method."%>
 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,然後在編寫組件的單元測試時使用嚮導。

 1using System;
 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的類。

1publicclass AssemblyFilePicker : UITypeEditor
2{
3public AssemblyFilePicker(): base()
4{
5      }

6}

 

        關於UITypeEditor的說明請大家參看M?xml:namespace>SDNVisual Studio.NET自帶幫助中的說明,其中有詳細的例子。

        然後我們需要重載UITypeEditor類的兩個不同的方法。第一個需要重載點的方法是GetEditStyle,這個方法是告訴屬性面板對於當前類型是用什麼類型的編輯器,在這個例子中我們設置編輯類型爲Modal。這樣大家可以在該屬性格子的右邊看到一個小按鈕,它將引發一個對話框等模式的對話(trigger a modal dialog)。這是我們的GetEditStyle方法:

1publicoverride UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 
2{
3return UITypeEditorEditStyle.Modal;
4}

        其中的Modal爲顯示一個省略號按鈕。 

 

        需要重載的另一個方法是EditValue方法,當用戶電擊屬性時會調用這個方法。按照我們需要加載的組件類型需要創建一個打開文件對話框(open file dialog)然後捕獲這個對話框,在屬性格子中返回對話框的結果。

1publicoverrideobject EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
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.)  

 

1IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
2Control editorControl = editorService as Control;
3
4if (editorControl !=null
5{

 

        然後我們創建一個openFileDialog類並填入適合的屬性。 

 

1OpenFileDialog openFileDialog =new OpenFileDialog();                         
2
3openFileDialog.CheckFileExists =true;
4openFileDialog.DefaultExt =".dll";
5openFileDialog.Multiselect =false;
6openFileDialog.Title ="Select an Assembly:";
7openFileDialog.Filter ="Assembly Files | *.dll";

        然後我們通過控件的參考(reference)將對話框顯示給用戶。

1DialogResult result = openFileDialog.ShowDialog(editorControl);

        下一步我們檢查用戶是否點擊了OK按鈕,如果點擊了,通過文件選擇對話框選擇文件後使用LoadForm方法加載這個組件,最後返回這個值。

 1if (result == DialogResult.OK)
 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與模板放在同一目錄下,然後再模板中加入下面兩行代碼。

1<%@ Assembly Name="AssemblyHelper" %>
2<%@ Import NameSpace="AssemblyHelper" %>

        然後我們要在組建屬性中添加Editor屬性,並且指定爲UITypeEditor編輯器。  

 

1[Editor(typeof(AssemblyHelper.AssemblyFilePicker), typeof(System.Drawing.Design.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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章