PropertyGrid使用總結2 TypeConverter


類型轉換的作用,是實現PropertyGrid輸入的多個文本信息,能夠與對象進行有效的轉化,比如我們具有如下一個對象:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
 
namespace AlbertControlExample.Controls 
{ 
/// <summary>
/// 定義一個新控件
/// </summary>
public class AlbertControlDef : Control 
{ 
public OffsetDef offsetDef 
{ 
 
get; set; 
} = new OffsetDef(0,0); 
public AlbertControlDef() 
{ 
} 
 
protected override void OnPaint(PaintEventArgs e) 
{ 
base.OnPaint(e); 
} 
} 
 
/// <summary>
/// 定義一個左邊偏移
/// </summary>
public class OffsetDef{ 
 
public OffsetDef(int left, int top) 
{ 
this.Left = left; 
this.Top = top; 
} 
 
public double Left { get; set; } 
public double Top { get; set; } 
} 
} 

我們看一下顯示當前的控件,會發現OffsetDef並不會顯示屬性,且無法編輯,如圖:

這是由於系統並無法解析OffsetDef對象,意思無法將它轉化為可以描述的文本集合,就不能對當前對象進行描述,那我們就需要利用TypeConverter對象,其可以定義如下:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
 
namespace AlbertControlExample.Controls 
{ 
/// <summary>
/// 定義一個新控件
/// </summary>
public class AlbertControlDef : Control 
{ 
[TypeConverter(typeof(OffsetConverterDef))] 
public OffsetDef offsetDef 
{ 
get; set; 
} = new OffsetDef(100,100); 
public AlbertControlDef() 
{ 
} 
 
protected override void OnPaint(PaintEventArgs e) 
{ 
base.OnPaint(e); 
} 
} 
 
/// <summary>
/// 定義一個左邊偏移
/// </summary>
public class OffsetDef{ 
 
public OffsetDef(int left, int top) 
{ 
this.Left = left; 
this.Top = top; 
} 
 
public double Left { get; set; } 
public double Top { get; set; } 
} 
 
public class OffsetConverterDef : TypeConverter { 
 
/// <summary>
/// 是否支持屬性顯示
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool GetPropertiesSupported(ITypeDescriptorContext context) 
{ 
return true; 
} 
 
/// <summary>
/// 返回屬性文本的集合定義
/// </summary>
/// <param name="context"></param>
/// <param name="value"></param>
/// <param name="attributes"></param>
/// <returns></returns>
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
{ 
var properties= TypeDescriptor.GetProperties(value); 
return properties; 
} 
} 
} 

通過返回屬性集合,系統會默認顯示屬性到窗體,其顯示結果如下:

TypeDescriptor肯定不止這么簡單,其有幾個重要的函數,可以實現對象和輸入框之間的互相轉換,下面分別說明集合函數的功能和作用

/// <summary>
/// 能否將對象轉換為字符串
/// </summary>
/// <param name="context"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
{ 
return true; 
} 
 
/// <summary>
/// 主要把對象轉化為指定的字符串
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
{ 
if (value.GetType() == typeof(OffsetDef)) 
{ 
OffsetDef offsetDef = value as OffsetDef; 
return string.Format("{0},{1}",offsetDef.Left, offsetDef.Top); 
 
} 
return base.ConvertTo(context, culture, value, destinationType); 
} 

其顯示會如下:

當前定義是將對象轉化為字符串對象,並且顯示在當前對象對應的文本框之中。以上界面,我們通過修改100,100這個文本框是無法修改的,它只能轉換過來,假如我們想可以編輯他,並且自動轉換為對象,可以實現如下幾個函數:

/// <summary>
/// 是否能從文本轉化為對象
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType"></param>
/// <returns></returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
{ 
return true; 
} 
 
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
{ 
if (value.GetType() == typeof(string)) { 
string objDec = value.ToString(); 
 
string[] vsp = objDec.Split(','); 
 
if (vsp.Length == 2) { 
 
OffsetDef offsetDef = new OffsetDef(int.Parse(vsp[0]),int.Parse(vsp[1])); 
return offsetDef; 
} 
 
} 
return base.ConvertFrom(context, culture, value); 
 
 
} 

通過以上的定義,我們發現,現在修改100,100這個文本框的內容,對象的屬性定義會自動改變,那是因為只要修改對象所對應的文本框,就會調用ConvertFrom函數,將當前文本框的內容自動轉化為對象,但是不能輸入錯誤的值,比如輸入一個無法轉換為int的字符串,那么就會報錯。其結果顯示如下:

但是其發現另外一個問題,我們修改100,100為100,200是否,那么對應的left和top的值會自動變化,但是我們修改Left/top的值的時候,並沒有影響到offsetDef的值,那是因為修改left\top不會觸發ConvertFrom函數,所以以上的轉化就會出問題,那我們怎么解決這個問題呢,則需要實現TypeDescriptor另外兩個函數:

/// <summary>
/// 是否能重新創建對象,默認是不創建,當前是需要創建的,所以我們直接返回true
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) 
{ 
return true; 
} 
 
/// <summary>
/// 返回創建的實例對象,這個函數的調用,只要當前屬性列表發生變化,當前函數都會啟動調用,也會返回當前所有的屬性列表
/// </summary>
/// <param name="context"></param>
/// <param name="propertyValues"></param>
/// <returns></returns>
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) 
{ 
if (propertyValues.Count == 2) { 
 
OffsetDef def = new OffsetDef(int.Parse(propertyValues["Left"].ToString()), int.Parse(propertyValues["Top"].ToString())); 
return def; 
} 
return base.CreateInstance(context, propertyValues); 
} 

通過以上兩個函數,你會發現,修改任何屬性對應的文本,那么這個對象就會重新定義,對象也會跟着改變。這個對象不僅僅有這些功能,其還有幾個非常重要的函數。

public override bool GetStandardValuesSupported(ITypeDescriptorContext context) 
{ 
return true; 
} 
 
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) 
{ 
StandardValuesCollection standardValues = new StandardValuesCollection(new string[]{ "100,200","200,300","400,500"}); 
return standardValues; 
} 

 

通過以上函數,可以對當前的對象指定一個標准的值,供用戶下拉選擇,通過以上的代碼,則可以實現如下功能:

同時還有其他幾個函數,這里就不一一說明,通過TypeConverter的定義,我們可以實現屬性文本列表和對象的互相轉換,實現對象的可配置。當前對象還有一個很重要的特性沒有說明,就是attributes和CultureInfo,ITypeDescriptorContext三個對象:

  1. attributes對象當然是對每個Property屬性上的attribute獲取和進行訪問的列表
  2. CultureInfo 主要用於實現控件的國際化的定義
  3. ITypeDescriptorContext 主要是當前類型標識的上下文信息,當前類型定義並沒有指定TypeDescriptor對象,所以當前對象為空,我們在接下來的章節,會介紹此對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM