WPF依賴屬性詳解


前言

如果看文字版本不沒耐心, 點擊下方查看視頻講解。
點擊觀看視頻

回顧

在講解依賴屬性之前, 首先我們熟悉一下WPF當中的綁定(Binding), 可能你曾用過WPF中綁定的語法。

下面演示了在Button按鈕上為Content屬性設置了一個綁定語法, 如下所示:

 <Button Content="{Binding Content}"/>

當你在Content屬性按下F12轉到定義時,可以觀察到Button按鈕所繼承的類的定義,如下所示:

如圖上紅圈位置, 定義了一個靜態的只讀字段ContentProperty。
通過查看該字段的類型DependencyProperty,沒錯!它就是一個依賴屬性。

看到這里, 你應該有了一個概念, 在WPF當中, 所有支持綁定的屬性本質上它都是封裝后的依賴屬性。
那么也就是說, 只有依賴屬性才可以進行綁定
如果你不能夠理解, 我們再舉個例子, 當你使用WPF當中PasswordBox控件的時候, 你會發現Password屬性不支持綁定, 當按下F12轉到定義,會發現該Password就是一個普通屬性:

這也就是為什么Password不支持綁定的真正原因。

屬性和依賴屬性

現在, 我們來解決另外一個概念問題, 可能看到上面, 你還是不太清楚屬性和依賴屬性它們的區別在哪里?

屬性

很常見, 在C#中的標准屬性,通常會由一個非靜態類型的私有字段支持, 假設當前有一個對象, 它擁有100個標准屬性,
並且背后都定義了一個4字節的字段, 如果我們初始化10000個這樣的對象, 那么這些字段將占用100×4×10000= 3.81M 內存。
但是實際上, 我們並非使用到所有的屬性, 這就意味着大多數內存會被浪費!

依賴屬性

如何解決屬性帶來的問題? 我們回到現實生活當中想象一種場景, 假設老王和你的女朋友去旅游, 他們准備東西的時候大都是把必要的帶上, 而不是說女朋友想喝水,要不然在行李箱里面放一箱水? 那么是不是意味着上廁所把紙帶上? 洗發水? 沐浴露? 天吶, 這真是一場糟糕的旅行。
我們都知道, 水、廁所紙、洗發水、沐浴露這些酒店里面都有阿, 為什么要我們自己帶? 所以我們懂了, 這些不必要帶的東西我們可以依賴外部提供給我們。是的, 我們把這種思想帶到編程當中。
所以, 這就是WPF當中的依賴屬性的理念, 也許你在其它的地方都聽過別人講解過依賴屬性, 並且他們都告訴你依賴屬性本身沒有值, 可以依賴綁定來源獲得值。

總結

下面是對比屬性/依賴屬性改的定義:

       //依賴屬性

        public static readonly DependencyProperty MyPropertyProperty =
           DependencyProperty.Register("MyProperty", typeof(int), typeof(Test), new PropertyMetadata(0));

        public int MyProperty
        {
            get { return (int)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        //屬性

        private int name;

        public int Name
        {
            get { return name; }
            set { name = value; }
        }

通過上面我們可以了解到, 普通的屬性通過定義了一個私有字段, 然后通過這個私有字段進行讀取或設置值。
而對於依賴屬性, 它同樣是使用屬性的訪問方式, 但是它獲取和設置值是通過依賴屬性而不再是私有字段。

依賴屬性定義

同樣, 你也許在許多的博客當中, 別人教你怎么定義依賴屬性, 它通過DependencyProperty類的靜態Register方法注冊, 如下所示:

    public class Test : DependencyObject
    {
        public string Message
        {
            get { return (string)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("Message", typeof(string), typeof(Test), new PropertyMetadata(null));
    }

上面的代碼當中, 我們定義了一個string類型的依賴屬性Message, 如果你們有看過WPF的源代碼, 你可能會了解, 在其背后, 生成了一個key/value存儲在Hashtable里面。

  • 生成key的代碼片段
  • 添加到Hashtable中

    終於解開了疑惑,有了這個全局的Hashtable存在, 意味着,他就是用來存儲依賴屬性實例的地方。

注意:定義依賴屬性的地方, 你會發現它需要繼承於DependencyObject對象, 通過該對象當中的提供的GetValue/SetValue方法, 我們可以獲取/設置依賴屬性的值:

GetValue/SetValue哪里來?

看看WPF中的繼承關系, 噢,懂了。 基類就是DependencyObject。

噢! 我的🐎🦆, 這也就是為什么, 微軟提供了標准屬性的訪問方式!讓我們傻傻分不清其內部通過依賴屬性來設置或獲取值。

在線搜索WPF源代碼

附加屬性

字母意思來理解, 附加屬性就是對於一個對象而言, 本來它不具備這個屬性, 但是由於附加給這個對象, 然后才有了這個屬性,這種我們稱之為附加屬性。
:附加屬性也是依賴屬性, 只是它的注冊方式與表達方式略有不同。
如果仍然不理解, 我們可以找到WPF當中經常用到的例子, 如下所示, 當一個按鈕處在不同的容器當中, 它就具有了不同的附加屬性:

        <Grid>
            <!--在Grid當中,具備Row/Column附加屬性-->
            <Button Grid.Row="0" Grid.Column="0" />
        </Grid>
       
        <DockPanel>
            <!--在DockPanel中,具備Dock附加屬性-->
            <Button DockPanel.Dock="Left" />
        </DockPanel>

        <Canvas>
            <!--在Canvas中,具備Left/Top/Rifht/Bottom等附加屬性-->
            <Button Canvas.Left="10"/>
        </Canvas>

依賴屬性與附加屬性對比

聲明方式

創建依賴屬性

我們可以輸入propdp再按兩下tab鍵生成一個依賴屬性的模板,如下所示:
: 聲明依賴屬性的所在位置的對象必須直接或簡介繼承於DependencyObject對象, 這樣它才具備GetValue/SetValue方法。

        public int MyProperty
        {
            get { return (int)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));

創建附加屬性

我們可以輸入propa再按兩下tab鍵生成一個附加屬性的模板,如下所示:
:聲明附加屬性的對象無需繼承於DependencyObject, 因為這個時候DependencyObject對象作為方法參數傳遞。

        public static int GetMyProperty(DependencyObject obj)
        {
            return (int)obj.GetValue(MyPropertyProperty);
        }

        public static void SetMyProperty(DependencyObject obj, int value)
        {
            obj.SetValue(MyPropertyProperty, value);
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.RegisterAttached("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));

使用場景

依賴屬性: 當您需要單獨創建控件時, 並且希望控件的某個部分能夠支持數據綁定時, 你則可以使用到依賴屬性。
附加屬性: 這種情況很多, 正因為WPF當中並不是所有的內容都支持數據綁定, 但是我們希望其支持數據綁定, 這樣我們就可以創建基於自己聲明的附加屬性,添加到元素上, 讓其元素的某個原本不支持數據綁定的屬性間接形成綁定關系。
例如:為PassWord定義附加屬性與PassWord進行關聯。例如DataGrid控件不支持SelectedItems, 但是我們想要實現選中多個條目進行數據綁定, 這個時候也可以聲明附加屬性的形式讓其支持數據綁定。


免責聲明!

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



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