属性(Property)的性质(Attribute)介绍
屬性(property)作為c#語言中一個重要的組成部分,尤其是在我們自己編寫組件的時候顯得更加重要。我相信大家一定對其有一定的了解。但是大家是否注意到了一個非常關鍵得細節問題呢?那就是在大家使用任何得組件的時候都需要通過屬性瀏覽器給每一屬性賦值,而且更加友好的是對于每種不同類型屬性都會自己的形式。比如:數字類型、字符串類型是默認簡單的輸入的形式,而如Font、Color類型的屬性則可以對話框或下拉列表框的形式。不知道大家是否知道這些是如何編寫的?其實這些功能都是通過屬性(Property)的(Attribute)來實現的,下面我就這個問題和大家一起學習,不過在閱讀本文之前要求大家對屬性(Property)有一定的了解,好下面我們言歸正傳。
實際上Property和Attribute翻譯成中文都是屬性的意思,但是在英文中卻有著微小的差別。因為在中文中不好區別Property和Attribute,所以我暫時的把這兩個單詞翻譯成屬性(Property)和性質(Attribute),如果有什么不對的地方請大家指出。
在C#中不僅僅屬性有自己的性質,類、方法、事件等都有自己的性質,由于本人知識限,所以只能給大家介紹一下屬性的性質了請大家原諒。
現在大家知道了性質,但是在C#中究竟什么是性質呢?下面我用一個例子來告訴大家,請看下面的一個WebService的例子:
[WebMethod]
public string HelloWorld()
{
return "Hello World by zhx";
}
這是一個WebService中一個對外發布方法的例子,其中[WebMethod]就是這個方法的Attribute。在WebService中如果方法不加上這個性質就不能夠對外發布,我在第一次用C#寫WebService時就沒用使用這個性質導致我還以為是我程序的錯誤了呢。
下面給大家看一個屬性的性質的例子:
private int _value;
[DefaultValue(1)]
[Description("文本框的值")]
public int Value
{
get
{
return this._value
}
set
{
this._value=value;
}
}
大家把這兩個性質[DefaultValue(1)]、[Description("文本框的值")]用到自己的性質以后,會發現什么?大家可以自己試驗一下。屬性的性質主要對.Net環境中的屬性編輯器起到UI的作用,所以大家在編寫完成代碼的時候先要編譯一下,然后再在窗體中引用呢自己的組件選定這個屬性才能起到作用。好,下面我就向大家一一的介紹我知道的性質。
先從簡單的給大家介紹:
1、 CategoryAttribute 大家從這個名字就可以看出來他的作用了,他的作用是把所定義的屬性按照一定的類型分類,就好像大家在系統中看到的“外觀”等的分類一樣。
2、 DescriptionAttribute 不知道大家是否還記得在系統中當選中一個屬性之后,在屬性瀏覽器中的下方就會出現該屬性的文字描述。這個性質就是起到了這樣的功能。
3、 DefaultValueAttribute 顧名思義這個性質當然是設置默認值的功能了,當用戶制定了改默認值后,屬性瀏覽器就會以加粗的字體顯示。
4、 ReadOnlyAttribute 這個性質也不難看出他是設置屬性的只讀性,這里的只讀性可不是屬性真正的只讀性,在這里只是指出在屬性瀏覽器中是否可以改寫的性質。
5、 BrowerAbleAttribute 這個性質功能是指出在屬性瀏覽器中是否可以瀏覽該屬性。有一些屬性是不希望在設計期間或者用屬性瀏覽器改寫的,就可以制定改性質。
這幾個性質不僅可以單獨使用,而且可以一起使用,下面是使用這幾個性質的一個例子:
private string _appVer="1.0";
[CategoryAttribute("自定義編輯器"),
DefaultValueAttribute("1.0"),
DescriptionAttribute("版本信息"),
ReadOnlyAttribute(true),
BrowerAbleAttribute(true)]
public string AppVer
{
get {return this._appVer;}
set {this._appVer=value;}
}
在編譯、選定改屬性之后可以看到如下的畫面。其中以紅色橢圓型標出的就是DescriptionAttribute性質所起到的作用,而其他性質得到的UI作用是在紅色矩形框中所展現的內容。
不知道大家是否發現在我的屬性AppVer和你的有一點不一樣?大家仔細看看,對了就是在我的屬性后面還多出了一個瀏覽按鈕,而且單擊他會彈出一個對話框,顯示版本信息,大家一定想知道這個功能是作用做出來的,大家先不要著急后面我在向大家介紹。
不知道大家是否注意到了,我們在使用Size、Font、Color等類型作為屬性的時候屬性瀏覽器會以怎樣的形式來改變我們屬性的值呢?下面的三個畫面。
大家仔細的研究一下就可看出這三個屬性可以分為基本的四個類型,Enum是下拉列表框的形式、Size是展開的形式、Font是彈出窗體的形式、Color是下拉UI的形式。但是對于性質的角度卻分為兩種類型,前兩類Enum、Size需要的性質是屬性轉換器(TypeConverter),而后兩種形式是需要編輯器(UITypeEditor)的。下面我就分別介紹這兩種性質。
1、 下拉列表框的形式:
要使用下拉列表框的形式的屬性我們首先要定義一個屬性,在這個例子中我定義了一個字符串類型的屬性 FileName。
private string _fileName;
public string FileName
{
get { return this._fileName;}
set { this._fileName=value; }
}
定義完屬性之后,我們還要自己一個屬性轉換器。那么什么是屬性轉換器呢?其實在屬性瀏覽器中只能夠識別字符串類型,所以我們要通過屬性轉換器把我們的屬性轉換成字符串,還要在屬性瀏覽器改變這個字符串之后在把這個字符串轉換成我們自己的屬性。大家聽起來是不是有一些胡涂了?沒關系下面我們做一個屬性轉換器大家就知道了。
因為在本例中用的屬性是字符串類型的所以我們要從System.ComponentModel.StringConverter繼承一個新的字符串形式的屬性轉換器。下面就是這段代碼和代碼中的注釋,相信大家一定能夠看懂的:
/// <summary>
/// 擴展字符串的轉換器(實現下拉列表框的樣式)
/// </summary>
public class FileNameConverter:System.ComponentModel.StringConverter
{
/// <summary>
/// 根據返回值確定是否支持下拉框的形式
/// </summary>
/// <returns>
/// true: 下來框的形式
/// false: 普通文本編輯的形式
/// </returns>
public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
/// <summary>
/// 下拉框中具體的內容
/// </summary>
public override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
{
return new StandardValuesCollection(new string[]{"File1.bat","File2.exe","File3.dll"});
}
/// <summary>
/// 根據返回值確定是否是不可編輯的文本框
/// </summary>
/// <returns>
/// true: 文本框不可以編輯
/// flase: 文本框可以編輯
/// </returns>
public override bool GetStandardValuesExclusive(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
好了,屬性轉換器寫完了,最后別忘了把這個屬性轉換器指定到我們剛才所寫的屬性上哦,代碼如下:
[CategoryAttribute("自定義的復雜類型設置(包括自定義類型轉換器)"),
TypeConverterAttribute(typeof(PropertyGridApp.FileNameConverter)),
ReadOnlyAttribute(false)]
public string FileName
{
get { return this._fileName;}
set { this._fileName=value; }
}
編譯之后的程序畫面如下
2、展開的形式
展開的形式多用于一個屬性為我們自定義類的類型,比如我們定義了一個類,該類中的一個屬性是另一個我們定義的類。在這種情況下屬性瀏覽器默認是沒有辦法來進行類型轉換的,所以顯示為不可編輯的內容。如果我們要以展開的形式編輯這個屬性就需要我們向上面一樣來重寫屬性轉換器。
我們首先定義一個自己的類來作為以后的屬性類型。具體代碼如下:
public class ExpandProperty
{
private int _intList=0;
public int IntList
{
get { return this._intList;}
set { this._intList=value; }
}
private string _strList="Null";
public string StrList
{
get { return this._strList;}
set { this._strList= value;}
}
}
然后我們在自己的另一個類中聲明一個這個類型的屬性,在這里如果我們不加任何的性質限制,屬性瀏覽器是不能轉換改屬性的。具體實現該屬性的代碼如下:
private ExpandProperty _dropList;
[CategoryAttribute("自定義的復雜類型設置(包括自定義類型轉換器)"),
TypeConverterAttribute(typeof(PropertyGridApp.ExpandConverter)),
ReadOnlyAttribute(false)]
public ExpandProperty DropList
{
get { return this._dropList;}
set { this._dropList= value;}
}
為了讓屬性瀏覽器能夠編輯該屬性,也就是說能夠把該屬性轉換成字符串,而且能夠從字符串轉換成該類的一個實例需要我們寫如下的代碼:
/// <summary>
/// 可以展開的類型轉換器
/// ExpandProperty
/// </summary>
public class ExpandConverter:System.ComponentModel.ExpandableObjectConverter
{
public ExpandConverter()
{
}
/// <summary>
/// 覆蓋此方法已確定屬性是否可以轉換
/// </summary>
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type destinationType)
{
if (destinationType==typeof(PropertyGridApp.ExpandProperty))
return true;
return base.CanConvertTo(context,destinationType);
}
/// <summary>
/// 覆蓋此方法并確保destinationType參數是一個String,然后格式化所顯示的內容
/// </summary>
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
{
if (destinationType == typeof (System.String) && value is PropertyGridApp.ExpandProperty)
{
PropertyGridApp.ExpandProperty source=(PropertyGridApp.ExpandProperty)value;
return source.IntList+","+source.StrList;
}
return base.ConvertTo(context,culture,value,destinationType);
}
/// <summary>
/// 覆蓋此方法已確定輸入的字符串是可以被轉化
/// </summary>
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
{
if (sourceType==typeof(string))
return true;
return base.CanConvertFrom(context,sourceType);
}
/// <summary>
/// 覆蓋此方法根據 ConvertTo() 方法的轉換格式來把所輸入的字符串轉換成類,并返回該類
/// </summary>
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
string s=(string)value;
int comma=s.IndexOf(",");
if (comma!=-1)
{
try
{
string intList=s.Substring(0,comma);
string strList=s.Substring(comma+1,s.Length-comma-1);
PropertyGridApp.ExpandProperty Ep=new ExpandProperty();
Ep.IntList=int.Parse(intList);
Ep.StrList=strList;
return Ep;
}
catch
{
return base.ConvertFrom(context,culture,value);
}
}
}
return base.ConvertFrom(context,culture,value);
}
}
編譯之后的畫面如下:
二:UI屬性編輯器(UITypeEditor)
這里的屬性編輯器的意思是能夠實現上面提到的彈出對話框和下拉UI的形式。廢話不說下面我們一一介紹。
1、 彈出對話框的形式
在本例中我使用了string類型的屬性來顯示版本的信息,大家可以隨便的寫各類的屬性,這里只需要指定改屬性的編輯器就可以了。
首先我們要建立一個string類型的屬性,代碼如下:
private string _appVer="1.0";
[CategoryAttribute("自定義編輯器"),
DefaultValueAttribute("1.0"),
DescriptionAttribute("版本信息"),
ReadOnlyAttribute(true),
EditorAttribute(typeof(AppVerConverter),typeof(System.Drawing.Design.UITypeEditor))]
public string AppVer
{
get {return this._appVer;}
set {this._appVer=value;}
}
大家可能已經注意到了在這個屬性之多出了一個性質EditorAttribute(typeof(AppVerConverter),typeof(System.Drawing.Design.UITypeEditor)),具體的意思大家可以參考MSDN我在這里就不用多說了,那么我們看看AppVerConverter這個類是怎么實現的就可以了。具體代碼如下:
/// <summary>
/// 自定義UI的屬性編輯器(彈出消息)
/// </summary>
public class AppVerConverter:System.Drawing.Design.UITypeEditor
{
/// <summary>
/// 覆蓋此方法以返回編輯器的類型。
/// </summary>
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
return System.Drawing.Design.UITypeEditorEditStyle.Modal;
}
/// <summary>
/// 覆蓋此方法以顯示版本信息
/// </summary>
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
System.Windows.Forms.MessageBox.Show("版本:1.0/n作者:張翔","版本信息");
return value;
}
}
這里需要說明的是我們的屬性編輯器必須從System.Drawing.Design.UITypeEditor繼承,要不然就不能顯示UI了。UITypeEditorEditStyle方法的返回值決定了改屬性編輯器的類型大家可以參考msdn我在這里就不多說了。編譯之后就可以看到如下的畫面了:
2、 下拉UI的類型
下拉UI類型主要是提供給用戶一個簡單的界面來選擇所要確定的屬性,這種方式提供給用戶非常友好的界面。下面的例子我們首先定義里一個Point類型的屬性,在默認的情況下這種類型的屬性是會以展開的形式來讓用戶編輯的。在這里我們擴展了他的功能,不僅僅能通過直接輸入的方式來改變值,而且還可以下拉出來一個控件,用戶可以在這個控件上根據鼠標的位置來確定具體的值。下面具體的代碼:
private System.Drawing.Point _dropUI;
[CategoryAttribute("自定義編輯器"),
DefaultValueAttribute("1"),
DescriptionAttribute("下拉可視控件"),
ReadOnlyAttribute(false),
EditorAttribute(typeof(DropEditor),typeof(System.Drawing.Design.UITypeEditor))]
public System.Drawing.Point DropUI
{
get { return this._dropUI;}
set { this._dropUI=value; }
}
public class DropEditor:System.Drawing.Design.UITypeEditor
{
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
return System.Drawing.Design.UITypeEditorEditStyle.DropDown;
}
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
System.Windows.Forms.Design.IWindowsFormsEditorService iws=(System.Windows.Forms.Design.IWindowsFormsEditorService)provider.GetService(typeof(System.Windows.Forms.Design.IWindowsFormsEditorService));
if (iws!=null)
{
PropertyGridApp.DropUIControl UIControl=new PropertyGridApp.DropUIControl((System.Drawing.Point)value,iws);
iws.DropDownControl(UIControl);
return UIControl.Value;
}
return value;
}
}
internal class DropUIControl:System.Windows.Forms.UserControl
{
public DropUIControl(System.Drawing.Point avalue,System.Windows.Forms.Design.IWindowsFormsEditorService iws)
{
this.Value=avalue;
this._tmpvalue=avalue;
this._iws=iws;
this.SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer|System.Windows.Forms.ControlStyles.UserPaint|System.Windows.Forms.ControlStyles.AllPaintingInWmPaint,true);
this.BackColor=System.Drawing.SystemColors.Control;
}
private System.Drawing.Point _value;
public System.Drawing.Point Value
{
get { return this._value;}
set { this._value=value; }
}
private System.Drawing.Point _tmpvalue;
private System.Windows.Forms.Design.IWindowsFormsEditorService _iws;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
string str="X:"+this._tmpvalue.X.ToString()+" ;Y:"+this._tmpvalue.Y.ToString();
System.Drawing.Graphics g=e.Graphics;
System.Drawing.SizeF sizef= g.MeasureString(str,this.Font);
g.DrawString(str,
this.Font,
new System.Drawing.SolidBrush(System.Drawing.Color.Black),
(int)((this.Width-(int)sizef.Width)/2),
this.Height-(int)sizef.Height);
g.PageUnit=System.Drawing.GraphicsUnit.Pixel;
g.FillEllipse(new System.Drawing.SolidBrush(System.Drawing.Color.Red),
this.Value.X-2,
this.Value.Y-2,
4,
4);
}
protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseMove(e);
this._tmpvalue=new System.Drawing.Point(e.X,e.Y);
this.Invalidate();
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseUp(e);
this.Value=this._tmpvalue;
this.Invalidate();
if (e.Button==System.Windows.Forms.MouseButtons.Left)
this._iws.CloseDropDown();
}
}
以上的代碼度非常的簡單,相信大家一定能夠看懂,如果有不明白的地方看看幫助,那里面解釋的非常的清楚。
在編寫屬性編輯器中我們都需要覆蓋其中的EditValue這個方法,大家是否注意到了其中的object Value這個參數?其實這個參數就是已經裝箱的屬性值,在我們自定義的處理完這個值的時候同樣可以返回一個裝箱的值來確定已經修改的屬性。在上面的兩個例子中我們只是簡單的使用了這個值,大家理解這個內容之后就可以做出更加個性化的編輯器了。
總結
以上是生活随笔為你收集整理的属性(Property)的性质(Attribute)介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: latex解决数据库中与或非符号如何打
- 下一篇: 中职计算机专业可以考什么大学,中职生可以