轉帖|其它|編輯:郝浩|2010-12-01 13:49:13.000|閱讀 635 次
概述:在設計用戶控件的時候(不管是winform還是webform),對于一般的簡單屬性(string,int,bool……基元類型)系統會為我們自動提供相應的類型轉換。本文主要介紹用戶控件中復雜屬性的設計時支持
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在設計用戶控件的時候(不管是winform還是webform),對于一般的簡單屬性(string,int,bool……基元類型)系統會為我們自動提供相應的類型轉換。舉個例子:我們在用戶控件中定義一個Age屬性
public int Age
{
get;
set;
}
這時我們打開設計器,就會看到
這個屬性了。我們可以隨便為其設置int類型的值。但是當我們試著填寫一個string類型的字符時,系統就會彈出一個"屬性無效"窗口,在這個過程中我們就可以看出系統已經為Age做了類型轉換,而且這個轉換失敗了,因為類型不匹配。
現在讓我們再寫一個復雜點的屬性Person。先創建一個Person類,它里面包含了name和age屬性:
public class Person
{
private string strName;
private int intAge;
public string StrName
{
get { return strName; }
set { strName = value; }
}
public int IntAge
{
get { return intAge; }
set { intAge = value; }
}
}
然后在用戶控件中,我們新建一個person的屬性:
private Person person;
public Person Person
{
get { return person; }
set { person = value; }
}
打開設計器窗體后我們可以看到Person屬性是灰色的
為什么會這樣呢?答案很簡單,系統不知道如何去顯示這個屬性。但總得顯示點兒什么吧?于是無可奈何下顯示了person類的類型名。這與我們所期望的形如Location樣式的可差遠了
到底差在哪里呢?類型轉換器!當我們在Person里面填寫"zhangsan,21"的時候,類型轉換器就能自動將這兩個屬性值對應到strName,intAge上面去,這就是類型轉換器的作用。那么下面我們就來實現一個person的類型轉換器。
實現類型轉換器
首先新建一個新類PersonConverter,用于提供person類型轉換的能力,所有的注釋我都寫在代碼里面了,大家一看就明白:
public class PersonConverter:TypeConverter
{
//指示我們設置的內容能否轉換
//因為我們輸入的是"zhangsan,12"的字符串形式,所以這里接受字符串類型的轉換
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
//這個方法指示了最后的這個復雜屬性是以什么形式表現出來的。
//如果destinationType == typeof(string)的話,最后person顯示的就是"zhangsan,21"的形式
//如果destinationType == typeof(InstanceDescriptor)的話,person顯示的就是"WindowsFormsControlLibrary1.Person"類名的形式。
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
if (destinationType == typeof(InstanceDescriptor))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
//這個方法實現了我們輸入的字符串如何被轉化為person類型
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
String[] v = ((String)value).Split(',');
if (v.GetLength(0) != 2)
{
throw new ArgumentException("Invalid parameter format");
}
Person csf = new Person { Name = Convert.ToString(v[0]), Age = Convert.ToInt32(v[1]) };
return csf;
}
return base.ConvertFrom(context, culture, value);
}
//這個則是實現了具體如何顯示person這個屬性的方法
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(String))
{
Person scope = (Person)value;
String result = scope.Name.ToString() + "," + scope.Age.ToString();
return result;
}
if (destinationType == typeof(InstanceDescriptor))
{
ConstructorInfo ci = typeof(Person).GetConstructor(new Type[] { typeof(string), typeof(Int32) });
Person scope = (Person)value;
return new InstanceDescriptor(ci, new object[] { scope.Name, scope.Age });
}
return base.ConvertTo(context, culture, value, destinationType);
}
//以下兩個方法提供子屬性單獨設置的能力。
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
return TypeDescriptor.GetProperties(typeof(Person), attributes);
}
}
然后在用戶控件的person屬性上加上這么一句,指定了person的轉換器:
[TypeConverter(typeof(PersonConverter))]
public Person Person
{
get;
set;
}
我們現在再來看看person的設計時的樣子,這樣就和我們需求的一樣了。
這里再教大家一個偷懶的方法,就是實現轉換器的時候不必重寫最上面的那四個方法,直接重寫"提供子屬性單獨設置的能力"的兩個方法就是了。只不過這樣person屬性顯示的效果如下:
就是person顯示的內容變了,子屬性還是提供設置。對于要求不高的屬性也夠了。
實現模態屬性編輯器
前面我們實現了形如Location屬性的設計時屬性設置支持,但我們有時需要的可能不只是這么復雜的屬性設置。比如BackgroundImage這個屬性,當我們設置它的時候,系統會彈出一個界面出來讓我們選擇圖片:
使用這種方式無疑增加了我們選擇圖片的方便度。那這種形式的設置該如何實現呢?
首先我們新建一個窗體,這個窗體就是將來需要顯示給用戶設置屬性的(比如上圖的"選擇資源"窗體)。我們還是以person類為例:
該窗體的后臺代碼如下:
private Person _person;
public PersonWindow(Person person)
{
InitializeComponent();
Person = person;
textBox1.Text = person.StrName;
textBox2.Text = person.IntAge.ToString();
}
public Person Person
{
get { return _person; }
set { _person = value; }
}
/// <summary>
/// 確認按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
Person.StrName = textBox1.Text;
Person.IntAge = int.Parse(textBox2.Text);
}
這里要注意的一點就是confirm按鈕的DialogResult要設置為DialogResult.OK,cancel按鈕的DialogResult要設置為DialogResult.Cancel。至于為什么要這么做大家往后看就知道了。
然后我們再建立一個class PersonModalEditor:System.Drawing.Design.UITypeEditor類,其代碼如下:
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
//指示以什么樣的形式打開編輯窗體
return UITypeEditorEditStyle.Modal;
}
//屬性編輯方法,當我們單擊屬性窗口中的屬性按鈕時會執行這個方法。
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
{
//獲取服務對象,這個對象專門為winform編輯器提供一些功能
IWindowsFormsEditorService service =
(IWindowsFormsEditorService) provider.GetService(typeof (IWindowsFormsEditorService));
if (service==null)
{
return null;
}
Person p = new Person();
CategoryWindow form = new CategoryWindow(p);
//這里知道為什么要設置confirm按鈕的DialogResult屬性的原因了吧。
if (service.ShowDialog(form) == System.Windows.Forms.DialogResult.OK)
{
return p;
}
return value; //系統會根據這個返回值在person屬性里面進行填充
}
最后我們在用戶控件的person屬性上加上這個一句話:
[Editor(typeof(CategoryModalEditor), typeof(UITypeEditor))]
public Person Person
{
get { return person; }
set { person = value; }
}
這句話指定了系統如何打開person的屬性編輯器。我們看看效果圖:
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:博客轉載