程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 《Programming WPF》翻譯 第9章 4.模板

《Programming WPF》翻譯 第9章 4.模板

編輯:關於.NET

對一個自定義元素最後的設計考慮是,它是如何連接其可視化的。如果一個元素直接從 FrameworkElement中派生,這將會適當的生成它自己的可視化。(第7章描述了如何創建一個圖形外觀。 )尤其是,如果你創建了一個元素,是為了提供一個特定的可視化表現,該元素應該完全控制這個可視化 是如何管理的,一旦你編寫了一個控件,通常你不會將一個圖形硬編碼到裡面。

記住,一個控件的工作是提供行為。可視化是由控件模板提供的。這種可視化是由控件模板提供的。 一個控件可能提供一組默認的可視化,而應允許這些可視化被替換,為了提供像內遷控件一樣的彈性。( 第五章描述了如何使用模板替換一個控件的可視化)符合這種方法的控件,這裡可視化從控件中分離出來 ,通常引用到一個沒有外觀的控件。所有內遷到WPF的控件都是沒有外觀的。

當然,控件完全獨立於其可視化是不可能的。任何控件將對模板必須滿足的需求施加影響,如果控件 操作正確。這些需求的程度隨控件不同而不同。例如,Button有一個相當簡單的需求——僅僅需要一個占 位符放置標題或內容。Slider控件需要更廣泛的需求:可視化必須提供兩個按鈕(增加和減少), “Thumb”,以及運行時Thumb上的一個跟蹤。此外,它還需要能夠響應點擊和拖動在這些元素的任意一個 ,以及能夠定位這個Thumb。

在任意控件類型和樣式或模板之間有一個隱式的約定。這個控件允許它的外觀通過替換可視化樹的方 式進行自定義,但是這棵樹必須輪流提供代表這棵樹的某些特征。這個約定的本性依賴於這個控件,內嵌 控件使用一些不同的樣式,緊緊依賴於它們的可視化結構。下面的部分描述了很多將控件與其模板聯系在 一起的方式

9.4.1屬性別名

控件和模板間最松散的約定形式是控件簡單的定義了公有屬性,以及允許模板來決定哪一個屬性在別 名中可見。(參見第5章獲取更多屬性別名的信息。)這個控件並不關心

在控件中是什麼。

這裡有一個單行的約定:控件提供屬性和命令,不需要返回值。盡管如此,如果必要的話,這樣的控 件仍能響應用戶輸入。事件路由允許事件從可視化向上冒泡到控件。控件能夠處理這些事件而不需要知道 任何關於可視化本性的信息。

為了支持這個模型,你所要做的是,使用本章先前描述的依賴屬性機制,來實現這些屬性。示例9-11 顯示了一個自定義控件,並且定義了一個單獨的名為Foo的依賴屬性,Brush類型。

依賴屬性支持這個控件的用戶在模板中提及,正如示例9-12所示。

示例9-12

<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
    <Grid>
        <Rectangle Fill="{TemplateBinding Foo}" />
    </Grid>
</ControlTemplate>

所有的依賴屬性自動支持屬性別名。這種情形下的“約定”是由一組你的控件提供的依賴屬性暗示的 。

9.4.2占位符

一些控件希望在模板中找到一個特定的占位符元素。這將要麼采取該元素指定類型的形式,或者可以 是一個元素標記了一個特定的屬性。

控件通過派生於ContentControl支持內容模板,使用元素類型的方法。它們希望在模板中找到一個 ContentPresenter元素。這是一個特殊意圖的元素,它的工作是在其他內容中擔當一個占位符。

實際上,這是一個松散的強迫性的約定。如果模板中沒有ContentPresenter,ContentControl通常不 會申訴。控件並不絕對依賴於表現的內容,為了放在那裡起作用。或者你能到達另一個極端,以及放一些 ContentPresenter在你的模板中,可以使子內容多次出現。

你不需要做任何特殊的事情來支持ContentPresenter的使用,只要你派生於ContentControl,它可以 很好的工作。控件的用戶能夠編寫一個模板,正如示例9-13所示。

示例9-13

<ControlTemplate TargetType="{x:Type local:MyContentControl}">
    <Grid>
        <Rectangle Fill="White" />
        <ContentPresenter />
    </Grid>
</ControlTemplate>

9.4.3通過屬性指定占位符

一些控件尋找用一個特定屬性標記的元素。例如,派生於ItemsControl的控件,如ListBox和MenuItem ,希望模板包括一個帶有Panel.IsItemsHost屬性設為true的元素。這標志了Panel將要扮演控件數據項目 的宿主。ItemCOntrol使用附屬屬性取代占位符的原因是,允許你決定使用什麼類型的Panel,作為數據項 的宿主。(ItemControl還支持ItemsPresenter占位符元素的使用。這將使用於當樣式不希望利用特定的 panel類型的時候以及想要使用無論控件的默認panel是什麼的時候)

為了實現使用此技術的控件,你需要定義一個自定義附屬依賴屬性,將其應用到占位符。這是一個 Boolean屬性。示例9-14注冊了這樣一個附屬屬性,並定義了通常的訪問器功能。

示例9-14

public class ControlWithPlaceholder : Control {
    public static DependencyProperty IsMyPlaceholderProperty;

    static ControlWithPlaceholder( ) {

        PropertyMetadata
 isMyPlaceholderMetadata = new PropertyMetadata(false,
            new PropertyInvalidatedCallback
(OnIsMyPlaceholderChanged));

        IsMyPlaceholderProperty = DependencyProperty.RegisterAttached(
            "IsMyPlaceholder", typeof(bool),
            typeof(ControlWithPlaceholder), isMyPlaceholderMetadata);
    }

    public static bool GetIsMyPlaceholder(DependencyObject target) {
        return (bool) target.GetValue(IsMyPlaceholderProperty);
    }
    public static void SetIsMyPlaceholder(DependencyObject target, bool value) {
        target.SetValue(IsMyPlaceholderProperty, value);
    }

注意到示例9-14為PropertyMetaData提供了一個PropertyInvalidatedCallBack。這指示了一個可以在 任意時間調用的方法,這個附屬屬性可以在任意元素上被設置或修改。在這種方法中,我們的控件將發現 哪個元素被設置為占位符,示例9-15顯示了這個方法。

示例9-15

    private static void OnIsMyPlaceholderChanged(DependencyObject target) {

        FrameworkElement targetElement = target as FrameworkElement;
        if (targetElement != null && GetIsMyPlaceholder(targetElement)) {
            ControlWithPlaceholder containingControl =
                targetElement.TemplatedParent as ControlWithPlaceholder;
            if (containingControl != null) {
                containingControl.placeholder = targetElement;
            }
        }
    }
    private FrameworkElement placeholder;

}

這個示例開始於檢測屬性被應用到派生於FrameworkElement的對象。記住我們希望這個屬性會被應用 到一個特定的控件模板內的UI元素,因此如果被應用到別的元素而不是FrameworkElement,我們這麼做就 得不到什麼有用的東西。

其次,我們通過GetIsMyPlaceholder訪問器方法檢測了屬性值,該方法是我們在示例9-14為附屬屬性 定義的。這將是些微單獨的,如果有人顯示的設置這個屬性為false,但是如果確實是這樣,我們干脆不 應該把元素作為占位符。

如果這個屬性設置為true,我們繼續獲取目標元素的TemplatedParent屬性。因為元素作為控件的模板 一部分,這將返回可視化所屬於的控件。(如果這個元素不是控件的成員,那麼返回null。既然這個屬性 僅僅對模板中的元素有意義,如果沒有模板化的父一級,我們就做不了任何事情。)我們還檢查了父一級 是一個控件類型的一個實例,而且忽略了屬性,如果被應用到一個模板中的元素,在某種其它類型的控件 模板中。

示例9-16顯示了如何在一個控件模板中使用屬性,來表明是哪一個元素在占位符中。

示例9-16

<ControlTemplate TargetType="{x:Type local:ControlWithPlaceholder}">
    <Grid local:ControlWithPlaceholder.IsMyPlaceholder="true" />
</ControlTemplate>

一些控件希望有一種模板,提供一組詳細明確的元素,來履行特定的角色在控件的標簽中。例如, HorizontalSlider控件希望模板包含表示可拖動thumb的元素,這個可點擊的跟蹤,在thumb的任意一邊, 等等。模板需要指出哪一個元素是哪一個。這可以通過使用上述顯示的技術,定義多個附屬屬性來實現。
當你寫一個使用了占位符的控件時,你可能選擇不執行這個約定。例如,如果模板的任意部分不見了, slider控件不會抱怨。一旦你只提供了要尋找的一些元素,這可以工作而不用抱怨。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved