WPF依賴屬性的正確學習方法

前言html

我在學習WPF的早期,對依賴屬性理解一直都很是的不到位,其惡果就是,我每次在寫依賴屬性的時候,須要翻過去的代碼來複制黏貼。git

相信不少朋友有着和我相同的經歷,因此這篇文章但願能幫助到那些剛剛開始學依賴屬性的朋友。github

那些[討厭]的依賴屬性的講解文章ide

初學者確定會面臨一件事,就是百度,谷歌,或者MSDN來查看依賴屬性的定義和使用,而這些文章雖然都寫的很好,但,那是相對於已經學會使用依賴屬性的朋友而言。學習

而對於初學者而言,說是誤導都不過度。this

好比,官網的這篇文章https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/dependency-properties-overviewspa

介紹依賴屬性是這樣。htm

public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(MyCode)
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

他作了一個定義,而後告訴你,依賴屬性的定義格式如此。對象

若是你是個初學者,你想不疑惑都很難。由於沒人能把這種定義給背下來。blog

其結果就是,你要和我當初同樣,每次定義依賴屬性,都要去複製黏貼。但這並非最大的惡果,最大的惡果是,由於太過複雜的定義,讓你放棄了對他理解,就記住了依賴屬性要複製黏貼,從而致使了,你喪失了對依賴屬性靈活運用的能力。

正確的理解依賴屬性

如何正確的理解依賴屬性呢?

很簡單,拆分一下就能夠理解了。

如今咱們來拆分依賴屬性,首先拆分他的定義,將依賴和屬性拆分。

咱們先看屬性,以下,咱們定義了一個屬性。

private bool _IsSpinning;
public bool IsSpinning
{
    get { return _IsSpinning; }
    set { _IsSpinning = value; }
}

而後咱們使用DependencyProperty類定義一個對象,這個對象將做爲IsSpinning屬性的依賴,以下:

public static readonly DependencyProperty IsSpinningProperty

而後,咱們在將這個依賴對象,註冊到屬性IsSpinning的所在類上,以下:

DependencyProperty.Register( "IsSpinning", typeof(bool),  typeof(你的屬性所在的類的名稱));

從註冊代碼中,咱們能夠看到,他註冊了三個信息:

1,當前DependencyProperty類定義的對象IsSpinningProperty,依賴於屬性IsSpinning。

2,對象IsSpinningProperty的依賴類型與屬性IsSpinning的類型同樣都是bool。

3,對象IsSpinningProperty註冊的類是聲明屬性IsSpinning的類,即,在其餘類裏,將看不到該依賴對象。

如今,咱們作最後的操做,修改屬性,將依賴對象IsSpinningProperty與屬性IsSpinning綁定。

如何綁定呢?很簡單,將咱們屬性定義裏的【private bool _IsSpinning】替換爲咱們剛剛定義的依賴【IsSpinningProperty】便可。

public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

這裏咱們看到了,在給屬性賦值和取值時,用到了GetValue和SetValue,他們倆是哪來的呢?

使用F12,咱們跟蹤進去,發現它們是類DependencyProperty裏定義的方法,那麼爲何咱們在窗體裏也能夠用呢?

很簡單,咱們跟進一下Window的父類,發現最後的父類Visual繼承了DependencyProperty,因此咱們能夠直接使用GetValue和SetValue來賦值和獲取依賴對象的值。也就是隻要是繼承了類DependencyProperty的子類,均可以使用依賴屬性。

完整版依賴屬性定義代碼:

public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register("IsSpinning", typeof(bool), typeof(DependecyUserControl));
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

到這裏,依賴屬性的拆分就完事了,如今,你們應該很清楚依賴屬性究竟是什麼了吧。

如今你已經理解這些依賴屬性的概念了,只要熟練一點點,實現手敲依賴屬性已經不是夢了。 

PS:有沒有人曾經告訴你,依賴屬性的命名必須是 屬性名+Property,而後你還信覺得真了。哈哈。

依賴屬性的簡單應用

如今讓咱們來自定義一個帶依賴屬性的系統控件來加深記憶。

public class KButton : Button 
{
    public static readonly DependencyProperty ForeImageProperty;
    public static readonly DependencyProperty BackImageProperty;
    public static readonly DependencyProperty MouseOverBackColorProperty;
    public static readonly DependencyProperty StretchProperty; 
    static KButton()
    {
        ForeImageProperty = DependencyProperty.Register("ForeImage", typeof(string), typeof(KButton),null);
        ForeImageProperty = DependencyProperty.Register("BackImage", typeof(string), typeof(KButton),null);
        MouseOverBackColorProperty = DependencyProperty.Register("MouseOverBackColor", typeof(Brush), typeof(KButton), null);
        StretchProperty = DependencyProperty.Register("Stretch", typeof(Stretch), typeof(KButton), null);

        DefaultStyleKeyProperty.OverrideMetadata(typeof(KButton), new FrameworkPropertyMetadata(typeof(KButton)));//使KButton去讀取KButton類型的樣式,而不是去讀取Button的樣式
    }
   
    public string ForeImage
    {
        get { return (string)GetValue(ForeImageProperty); }
        set { SetValue(ForeImageProperty, value); }
    }
    public string BackImage
    {
        get { return (string)GetValue(BackImageProperty); }
        set { SetValue(BackImageProperty, value); }
    }
    public Brush MouseOverBackColor
    {
        get { return (Brush)GetValue(MouseOverBackColorProperty); }
        set { SetValue(MouseOverBackColorProperty, value); }
    }
    public Stretch Stretch
    {
        get { return (Stretch)GetValue(StretchProperty); }
        set { SetValue(StretchProperty, value); }
    } 
}

如上述代碼所示,咱們定義了一個繼承至Button的類KButton。

在KButtion中,咱們定義了四個依賴屬性:

ForeImageProperty:按鈕的前景圖片。

BackImageProperty:按鈕的背景圖片。

MouseOverBackColorProperty:按鈕在鼠標通過時的顏色。

StretchProperty:按鈕圖片的拉伸模式。

代碼很是簡潔,除了四個依賴屬性以外,什麼也沒有;如今咱們去定義Kbutton類型的樣式。

爲了演示方便,我直接將樣式定義在了App.xaml文件內。

        <Style TargetType="{x:Type local:KButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel Name="dpCon" Width="{Binding Width, RelativeSource={x:Static RelativeSource.TemplatedParent}}" 
                               Height="{Binding Height, RelativeSource={x:Static RelativeSource.TemplatedParent}}"
                               Background="{Binding Background, RelativeSource={x:Static RelativeSource.TemplatedParent}}"
                               ToolTip="{Binding ToolTip, RelativeSource={x:Static RelativeSource.TemplatedParent}}"
                               >
                            <DockPanel DockPanel.Dock="Top" Name="dpBtn">
                                <DockPanel.Background>
                                    <ImageBrush ImageSource="{Binding ForeImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}" Stretch="{Binding Stretch,RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                                </DockPanel.Background>
                                <TextBlock FontSize="15" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="#f9fcff" Text="{Binding Content, RelativeSource={x:Static RelativeSource.TemplatedParent}}"></TextBlock>
                            </DockPanel>
                        </DockPanel>
                        <ControlTemplate.Triggers>  
                            <DataTrigger Binding="{Binding IsMouseOver,RelativeSource={x:Static RelativeSource.Self}}" Value="True">
                                <Setter Property="Background" TargetName="dpBtn">
                                    <Setter.Value>
                                        <ImageBrush ImageSource="{Binding BackImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}" Stretch="{Binding Stretch,RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="Background" TargetName="dpCon" Value="{Binding MouseOverBackColor, RelativeSource={x:Static RelativeSource.TemplatedParent}}"></Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding BackImage,RelativeSource={x:Static RelativeSource.Self},Mode=TwoWay}" Value="{x:Null}">
                                <Setter Property="Background" TargetName="dpBtn">
                                    <Setter.Value>
                                        <ImageBrush ImageSource="{Binding ForeImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}" Stretch="{Binding Stretch,RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                                    </Setter.Value>
                                </Setter> 
                            </DataTrigger>
                            <Trigger Property="IsEnabled" Value="true"/>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="Gray"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

樣式代碼如上所示,也很是簡單,就是定義了一個模板,而後在模板裏擺放好按鈕背景圖和按鈕文字的位置。而後將咱們以前定義好的依賴屬性綁定到對應的值上。

其中須要注意的是,在模板中綁定自定義依賴屬性,是使用RelativeSource.TemplatedParent的,如{Binding ForeImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}。

而在模板的數據事件DataTrigger中,綁定依賴屬性的模式倒是分兩種的。

第一種,綁定數據事件DataTrigger的條件時,使用RelativeSource.Self,如{Binding IsMouseOver,RelativeSource={x:Static RelativeSource.Self}}。

第二種,條件成立,觸發模板變化時,使用RelativeSource.TemplatedParent,如{Binding BackImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}。

----------------------------------------------------------------------------------------------------

如今咱們使用下咱們製做好的自定義控件,代碼以下所示:

<DockPanel>
    <StackPanel>
        <local:KButton  Height="50" Width="50" Stretch="None" ForeImage="/Image/關閉.png" BackImage="/Image/關閉退出.png" Background="Gray" MouseOverBackColor="Brown"/>
        <local:KButton  Height="50" Width="50" Margin="0,10,0,0" Stretch="None" ForeImage="/Image/關閉.png" Background="Gray" MouseOverBackColor="Brown"/>
        <local:KButton  Height="100" Width="100" Margin="0,10,0,0" Content="籃子" Stretch="Fill"  ForeImage="/Image/籃子.png" Background="Gray" MouseOverBackColor="Brown"/>
    </StackPanel> 
</DockPanel>

界面效果以下:

自定義用戶控件中使用依賴屬性

首先咱們添加新項,而後選擇用戶控件。

而後,咱們添加一個依賴屬性HeaderTitle,同時設置當前控件的DataContext爲自身—this.DataContext = this。

public string HeaderTitle
{
    get { return (string)GetValue(HeaderTitleProperty); }
    set { SetValue(HeaderTitleProperty, value); }
} 
public static readonly DependencyProperty HeaderTitleProperty = DependencyProperty.Register("HeaderTitle", typeof(string), typeof(DependecyUserControl), null); 
public DependecyUserControl()
{
    this.DataContext = this;
    InitializeComponent();
}

如今,咱們在用戶控件的Xaml頁面添加一個TextBlock,並綁定他的Text爲咱們剛剛定義的HeaderTitle,代碼以下所示。

<Grid>
    <TextBlock Text = "{Binding HeaderTitle}" TextAlignment="Center"></TextBlock>
</Grid>

接着咱們回到主窗體,引用這個用戶控件,代碼以下所示:

<local:DependecyUserControl Height = "30" HeaderTitle="我是Header"  DockPanel.Dock="Top"></local:DependecyUserControl>

運行結果:

能夠看到,咱們成功在主頁面設置了用戶控件的依賴屬性,並讓他成功的綁定到了用戶控件中的TextBlock的Text屬性。也就是說,咱們簡單的實現了Header的Title動態設置。

結語

WPF擁有很是強大的自定義能力,而,正確的學會了依賴屬性是體會到它強大的第一步。

----------------------------------------------------------------------------------------------------

到此WPF依賴屬性的正確學習方法就已經講解完成了。

代碼已經傳到Github上了,歡迎你們下載。

Github地址:https://github.com/kiba518/WpfDependency

----------------------------------------------------------------------------------------------------

注:此文章爲原創,歡迎轉載,請在文章頁面明顯位置給出此文連接!
若您以爲這篇文章還不錯,請點擊下方的推薦】,很是感謝!

http://www.javashuo.com/article/p-qgwhsjox-dk.html

相關文章
相關標籤/搜索