C#控制項開發(二)

來源:互聯網
上載者:User
五、 基礎知識:使用Attribute來訂製屬性視窗的顯示
控制顯示的機制和用IDL定義的組件是一樣的,不過是增加了中繼資料特性。控制顯示使用最普遍的特性是BrowsableAttribute。預設狀態下,屬性視窗顯示對象中定義的所有的公開的、可讀的(即public、有get或者set方法的)屬性,並且把他們放在“雜項(Misc)”類別中。下面是一個簡單的組件例子:

public class SimpleComponent : System.ComponentModel.Component
{

private string data = "(none)";

private bool dataValid = false;

public string Data

{

get

{

return data;

}

set

{

if (value != data)

{

dataValid = true;

data = value;

}

}

}

public bool IsDataValid

{

get

{

// perform some check on the data

//

return dataValid;

}

}

}

是這個例子在屬性視窗中的顯示:

圖1.顯示在屬性視窗中的簡單組件

在這個例子中,SimpleComponent有兩個屬性:Data和IsDataValid。實際上,由於IsDataValid是唯讀,因此顯示在這裡並沒有多大意義,設計人員在設計狀態沒有必要知道這個屬性的值。因此,我們給他加上BrowsableAttribute特性讓屬性視窗不顯示他。

[Browsable(false)]

public bool IsDataValid

{

get

{

// perform some check on the data

//

return dataValid;

}

}

編譯器會自動在屬性類別名後添加“Attribute”字元,因此我們可以在代碼中省略掉他。當然,輸入“[BrowsableAttribute(false)]”是一樣的效果。對於那些沒有指定特性的屬性或者類,編譯器都使用預設特性和預設特性值加以描述。在這個例子中,BrowsableAttribute的預設值為true。這個原則對於Visual Basic .NET同樣是一致的。兩者唯一的區別就是Visual Basic .NET使用角括弧(‘<’和‘>’)來標記特性,而不是在C#中使用的中括弧(‘[’和‘]’)。

編譯器會自動在屬性類別名後添加“Attribute”字元,因此我們可以在代碼中省略掉他。當然,輸入“[BrowsableAttribute(false)]”是一樣的效果。對於那些沒有指定特性的屬性或者類,編譯器都使用預設特性和預設特性值加以描述。在這個例子中,BrowsableAttribute的預設值為true。這個原則對於Visual Basic .NET同樣是一致的。兩者唯一的區別就是Visual Basic .NET使用角括弧(‘<’和‘>’)來標記特性,而不是在C#中使用的中括弧(‘[’和‘]’)。

同時,我們注意一下在圖1中Data屬性的值“abc”是粗體。這意味著屬性的值不是預設值,而且這個值在設計器為form或者control產生代碼的時候將會儲存下來(即會產生一個指派陳述式)。而對於屬性的預設值就沒有必要來產生指派陳述式,產生代碼意味著增加組件初始化的時間(InitializeComponent方法)和代碼檔案的大小。那麼SimpleComponent該如何將預設值通知屬性視窗的呢?要實現這個特性,我們就需要使用DefaultValueAttribute特性對屬性加以描述,也就可以在對象的構建器中為屬性賦值。當屬性視窗顯示內容值的時候,它就會比較當前值和DefaultValueAttribute指定的預設值,如果兩者不相等的話,就會把值顯示成粗體。在下面的例子裡,Data屬性的值如果不是“(none)”就會被顯示成粗體。

[DefaultValue("(none)")]

public string Data

{

// . . .

}

我們同樣可以給屬性添加更為複雜的判斷邏輯而不只是一些簡單的固有值的比較,這可以通過給組件增加一些特殊方法加以實現。屬性判斷邏輯方法的名字必須以“ShouldSerialize”開頭,並且接著就是屬性的名字,而且此方法的傳回值為“Boolean”。在這個例子裡,這種方法就叫“ShouldSerializeData”。在SimpleComponent組件中增加下面的代碼就可以實現和DefaultValueAttribute同樣的效果,不過他卻可以有更強的邏輯代碼。

private bool ShouldSerializeData()

{

return Data != "(none)";

}

一般來說,將屬性分類對設計者來說介面更加友好。我們就是用CategoryAttribute特性來給屬性分類。這個特性就使用一個簡單的類目字串,屬性視窗可以據此將屬性顯示在類目的子項中。類目名稱可以自行決定。

[DefaultValue("(none)"), Category("Sample")]

public string Data

{

// . . .

}

組件開發人員經常遇到的一個問題就是如何?這個類目字串的本地化。我們看看CategoryAttribute類,就可以看到他的GetLocalizedString方法就提供了這樣的功能。要實作類別目字串的本地化,就要從CategoryAttribute類派生新的屬性類別。在這個例子裡,我們從組件的字串資源中得到以索引值為索引的本地化的類目字串。在指定屬性的CategoryAttribute特性時,用這個索引值(Key)替換原來的類目名作為輸入參數。這樣屬性窗在查詢屬性的CategoryAttribute就會調用GetLocalizedString方法並且把key值作為參數傳入方法,在屬性視窗中顯示返回屬性的類目名稱。

internal class LocCategoryAttribute : CategoryAttribute

{

public LocCategoryAttribute(string categoryKey) : base(categoryKey)

{

}

protected override string GetLocalizedString(string key)

{

// get the resource set for the current locale.

//

ResourceManager resourceManager = new ResourceManager();

string categoryName = null;

// walk up the cultures until we find one with

// this key as a resource as our category name

// if we reach the invariant culture, quit.

//

for (CultureInfo culture = CultureInfo.CurrentCulture;

categoryName == null &&

culture != CultureInfo.InvariantCulture;

culture = culture.Parent)

{

categoryName = (string)resourceManager.GetObject(key, culture);

}

return categoryName;

}

}

使用這個本地化類目名稱,我們要先定義一個包含有這個key的資源檔,並且把這個特性使用到屬性上去。

[LocCategory("SampleKey")]

public string Data

{

// . . .

}

當我們在設計視窗的時候,如果選擇了Form上的多個組件,屬性視窗就會顯示他們共同屬性,共同屬性是按組件的屬性名稱和類型區別的。如果改變共同屬性的值,那麼所有的被選擇的組件的這個屬性值都會跟著改變。而把一個屬性包括在和其他屬性的合成裡一般來說意義不大。通常,共同屬性都是有唯一的值,比如另一個組件的名字。由於當選擇了多個組件的時候,改變共同屬性的值,所有的被選擇組件的對應屬性值都會改變,因此,需要指定某些屬性不被合并為共同屬性。MergablePropertyAttribute就可以做到這點。只要簡單的把這個特性參數設為false值,就可以在選擇多個組件的時候隱藏掉這個屬性,自然他的值就不會跟著變化了。

一些屬性的值可以影響到另外的一些屬性值。例如,在實現資料繫結的組件中,清除掉DataSource的值,當然應該清除掉DataMember的值。RefreshPropertiesAttribute就讓我們實現這個功能。他的預設參數是“none,”也就是不影響到其他屬性,如果指定其他的特性參數,屬性視窗就可以在改變這個屬性值的同時,自動的更新其他屬性的值。另外的兩個值,其一是Repaint,它讓屬性視窗重新擷取屬性的值並且重畫他們;還有就是All,它就意味著組件自己要重新擷取屬性的值。如果值的改變導致屬性的數目的增減,那麼我們就要使用All。不過要注意到這個一般用在進階場合,並且速度要比Repaint慢。RefreshProperties.Repaint適用於大部分的情況。需要注意的是,這個特性是用在引發改變的屬性上,而不是被改編的屬性上。

最後,DefaultPropertyAttribute和DefaultEventAttribute使用在類層級的場合,他們讓屬性視窗高亮顯示這些屬性和事件。當選擇其他的組件的時候,屬性視窗總是試圖定位到和上次選擇的組件相同的屬性或事件上。如果沒有找到這樣的屬性或事件的話,它就會將輸入指標定位到DefaultPropertyAttribute指定的屬性。在Event視圖就會定位到DefaultEventAttribute指定的事件。同時,這個事件也是當你雙擊組件時,自動使用的事件。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.