自訂類別的結繫問題
C# Winform提供很多方便的控件(Control)可讓開發人員拉出想要的介面,再使用資料結繫將介面與資料連結,就可以很輕鬆的做出一支視窗程式。
如果結繫得是.Net內建的物件(如Point、Size…等),就可以正常運作,但結繫方面如果是自定義的物件,就會遇到下面的狀況。
自訂類別
舉個例子,下面的類別Item裡面有各種ID資料,並放在Person內。
class Person
{
public int Age { get; set; } = 0;
public string Name { get; set; } = "Name";
public Item Item { get; set; } = new Item();
}
class Item
{
public int ID1 { get; set; } = 0;
public int ID2 { get; set; } = 0;
public int ID3 { get; set; } = 0;
public Item() { }
public Item(int id1, int id2, int id3)
{
ID1 = id1; ID2 = id2; ID3 = id3;
}
}
當結繫Person到DataGridView上就會發現,物件顯示資訊只會是類別名稱,不是自己想要的內容。下面有兩種方法可以解決。
方法一、覆寫 ToString()
此方法只能用於唯讀。
可以透過覆寫ToString()
就能顯示資料,如下圖可以正常顯示0:0:0,但會遇到個小問題。
public override string ToString()
{
return $"{ID1}:{ID2}:{ID3}";
}
如果想要在DataGridView上編輯資料將Item改為0:0:11
會引發錯誤,“從System.String”至”XXX.Item”的轉換無效”。
因為表單不能將0:0:11
轉換成Item的結構,於是需要實作TypeConverter給Item,讓手動輸入的資料可以轉換成類別。
方法二、實作 TypeConverter
*TypeConverter 類別定義
會提供轉換實值型別為其他型別,以及存取標準值和子屬性的統一方式。
TypeConverter是.Net用來提供給物件轉換使用,介面上看的到的輸入方式(Point, Size…etc)其實.Net內部都有實作對應的轉換器。
實作方式如下,需要建立類別ItemTypeConverter
並繼承TypeConverter
,如果按照官方建議需要實作覆寫下面四個方法:
- CanConvertFrom(ITypeDescriptorContext, Type)
- CanConvertTo(ITypeDescriptorContext, Type)
- ConvertFrom(ITypeDescriptorContext, CultureInfo, Object)
- ConvertTo(ITypeDescriptorContext, CultureInfo, Object, Type)
但因為這篇只有用在介面結繫,結繫的顯示目標只有string,就沒有覆寫CanConvertTo()
方法。
如果要讓DataGridView可以編輯自訂類別Item,也就是要實作CanConvertFrom()
、ConvertFrom()
讓程式知道如何從輸入的字串轉換成對應的實例。
反之,ConvertTo()
用來將物件轉換成對應的字串來顯示。在本篇與ToString()
的作用類似。
class ItemTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string s)
{
try
{
var items = s.Split(':');
return new Item(int.Parse(items[0]), int.Parse(items[1]), int.Parse(items[2]));
}
catch (Exception)
{
throw;
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
var item = value as Item;
return $"{item.ID1}:{item.ID2}:{item.ID3}";
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
最後在Item上加上TypeConverter的Attritube即可。
[TypeConverter(typeof(ItemTypeConverter))]
class Item
{
...略
}
現在簡單的小程式已經可以編輯Item的項目了,只要照著自訂的格式輸入程式就換進行轉換。
結語
實作TypeConverter做為類別之間的轉換器,自己常用來顯示自訂的資料項目,尤其是一些系統設定參數,可以讓介面看起來比較直觀,也符合物件導向的概念。
目前TypeConverter小弟只用了其中四個方法,其他還能更特殊更深入的應用,如果未來有遇到會在分享上來。
發佈留言