C#中WPF依賴屬性的正確學(xué)習(xí)方法
前言
我在學(xué)習(xí)WPF的早期,對(duì)依賴屬性理解一直都非常的不到位,其惡果就是,我每次在寫依賴屬性的時(shí)候,需要翻過(guò)去的代碼來(lái)復(fù)制黏貼。
相信很多朋友有著和我相同的經(jīng)歷,所以這篇文章希望能幫助到那些剛剛開始學(xué)依賴屬性的朋友。
那些[討厭]的依賴屬性的講解文章
初學(xué)者肯定會(huì)面臨一件事,就是百度,谷歌,或者M(jìn)SDN來(lái)查看依賴屬性的定義和使用,而這些文章雖然都寫的很好,但,那是相對(duì)于已經(jīng)學(xué)會(huì)使用依賴屬性的朋友而言。
而對(duì)于初學(xué)者而言,說(shuō)是誤導(dǎo)都不過(guò)分。
比如,官網(wǎng)的這篇文章https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/dependency-properties-overview
介紹依賴屬性是這樣。
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean),
typeof(MyCode)
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
他做了一個(gè)定義,然后告訴你,依賴屬性的定義格式如此。
如果你是個(gè)初學(xué)者,你想不疑惑都很難。因?yàn)闆]人能把這種定義給背下來(lái)。
其結(jié)果就是,你要和我當(dāng)初一樣,每次定義依賴屬性,都要去復(fù)制黏貼。但這并不是最大的惡果,最大的惡果是,因?yàn)樘^(guò)復(fù)雜的定義,讓你放棄了對(duì)他理解,就記住了依賴屬性要復(fù)制黏貼,從而導(dǎo)致了,你喪失了對(duì)依賴屬性靈活運(yùn)用的能力。
正確的理解依賴屬性
如何正確的理解依賴屬性呢?
很簡(jiǎn)單,拆分一下就可以理解了。
現(xiàn)在我們來(lái)拆分依賴屬性,首先拆分他的定義,將依賴和屬性拆分。
我們先看屬性,如下,我們定義了一個(gè)屬性。
private bool _IsSpinning;
public bool IsSpinning
{
get { return _IsSpinning; }
set { _IsSpinning = value; }
}
然后我們使用DependencyProperty類定義一個(gè)對(duì)象,這個(gè)對(duì)象將作為IsSpinning屬性的依賴,如下:
public static readonly DependencyProperty IsSpinningProperty
然后,我們?cè)趯⑦@個(gè)依賴對(duì)象,注冊(cè)到屬性IsSpinning的所在類上,如下:
DependencyProperty.Register( "IsSpinning", typeof(bool), typeof(你的屬性所在的類的名稱));
從注冊(cè)代碼中,我們可以看到,他注冊(cè)了三個(gè)信息:
1,當(dāng)前DependencyProperty類定義的對(duì)象IsSpinningProperty,依賴于屬性IsSpinning。
2,對(duì)象IsSpinningProperty的依賴類型與屬性IsSpinning的類型一樣都是bool。
3,對(duì)象IsSpinningProperty注冊(cè)的類是聲明屬性IsSpinning的類,即,在其他類里,將看不到該依賴對(duì)象。
現(xiàn)在,我們做最后的操作,修改屬性,將依賴對(duì)象IsSpinningProperty與屬性IsSpinning綁定。
如何綁定呢?很簡(jiǎn)單,將我們屬性定義里的【private bool _IsSpinning】替換為我們剛剛定義的依賴【IsSpinningProperty】即可。
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
這里我們看到了,在給屬性賦值和取值時(shí),用到了GetValue和SetValue,他們倆是哪來(lái)的呢?
使用F12,我們跟蹤進(jìn)去,發(fā)現(xiàn)它們是類DependencyProperty里定義的方法,那么為什么我們?cè)诖绑w里也可以用呢?
很簡(jiǎn)單,我們跟進(jìn)一下Window的父類,發(fā)現(xiàn)最后的父類Visual繼承了DependencyProperty,所以我們可以直接使用GetValue和SetValue來(lái)賦值和獲取依賴對(duì)象的值。也就是只要是繼承了類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); }
}
到這里,依賴屬性的拆分就完事了,現(xiàn)在,大家應(yīng)該很清楚依賴屬性到底是什么了吧。
現(xiàn)在你已經(jīng)理解這些依賴屬性的概念了,只要熟練一點(diǎn)點(diǎn),實(shí)現(xiàn)手敲依賴屬性已經(jīng)不是夢(mèng)了。
PS:有沒有人曾經(jīng)告訴你,依賴屬性的命名必須是 屬性名+Property,然后你還信以為真了。哈哈。
依賴屬性的簡(jiǎn)單應(yīng)用
現(xiàn)在讓我們來(lái)自定義一個(gè)帶依賴屬性的系統(tǒng)控件來(lái)加深記憶。
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); }
}
}
如上述代碼所示,我們定義了一個(gè)繼承至Button的類KButton。
在KButtion中,我們定義了四個(gè)依賴屬性:
ForeImageProperty:按鈕的前景圖片。
BackImageProperty:按鈕的背景圖片。
MouseOverBackColorProperty:按鈕在鼠標(biāo)經(jīng)過(guò)時(shí)的顏色。
StretchProperty:按鈕圖片的拉伸模式。
代碼非常簡(jiǎn)潔,除了四個(gè)依賴屬性之外,什么也沒有;現(xiàn)在我們?nèi)ザxKbutton類型的樣式。
為了演示方便,我直接將樣式定義在了App.xaml文件內(nèi)。
<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>
樣式代碼如上所示,也非常簡(jiǎn)單,就是定義了一個(gè)模板,然后在模板里擺放好按鈕背景圖和按鈕文字的位置。然后將我們之前定義好的依賴屬性綁定到對(duì)應(yīng)的值上。
其中需要注意的是,在模板中綁定自定義依賴屬性,是使用RelativeSource.TemplatedParent的,如
{Binding ForeImage,
RelativeSource={x:Static RelativeSource.TemplatedParent}}。
而在模板的數(shù)據(jù)事件DataTrigger中,綁定依賴屬性的模式卻是分兩種的。
第一種,綁定數(shù)據(jù)事件DataTrigger的條件時(shí),使用RelativeSource.Self,如{Binding IsMouseOver,RelativeSource={x:Static RelativeSource.Self}}。
第二種,條件成立,觸發(fā)模板變化時(shí),使用RelativeSource.TemplatedParent,如{Binding BackImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}。
----------------------------------------------------------------------------------------------------
現(xiàn)在我們使用下我們制作好的自定義控件,代碼如下所示:
<DockPanel>
<StackPanel>
<local:KButton Height="50" Width="50" Stretch="None" ForeImage="/Image/關(guān)閉.png" BackImage="/Image/關(guān)閉退出.png" Background="Gray" MouseOverBackColor="Brown"/>
<local:KButton Height="50" Width="50" Margin="0,10,0,0" Stretch="None" ForeImage="/Image/關(guān)閉.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>
界面效果如下:
自定義用戶控件中使用依賴屬性
首先我們添加新項(xiàng),然后選擇用戶控件。
然后,我們添加一個(gè)依賴屬性HeaderTitle,同時(shí)設(shè)置當(dāng)前控件的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();
}
現(xiàn)在,我們?cè)谟脩艨丶腦aml頁(yè)面添加一個(gè)TextBlock,并綁定他的Text為我們剛剛定義的HeaderTitle,代碼如下所示。
<Grid>
<TextBlock Text = "{Binding HeaderTitle}" TextAlignment="Center"></TextBlock>
</Grid>
接著我們回到主窗體,引用這個(gè)用戶控件,代碼如下所示:
<local:DependecyUserControl Height = "30" HeaderTitle="我是Header" DockPanel.Dock="Top"></local:DependecyUserControl>
運(yùn)行結(jié)果:
可以看到,我們成功在主頁(yè)面設(shè)置了用戶控件的依賴屬性,并讓他成功的綁定到了用戶控件中的TextBlock的Text屬性。也就是說(shuō),我們簡(jiǎn)單的實(shí)現(xiàn)了Header的Title動(dòng)態(tài)設(shè)置。
結(jié)語(yǔ)
WPF擁有非常強(qiáng)大的自定義能力,而,正確的學(xué)會(huì)了依賴屬性是體會(huì)到它強(qiáng)大的第一步。
----------------------------------------------------------------------------------------------------
到此WPF依賴屬性的正確學(xué)習(xí)方法就已經(jīng)講解完成了。
代碼已經(jīng)傳到Github上了,歡迎大家下載。
Github地址:https://github.com/kiba518/WpfDependency
總結(jié)
以上所述是小編給大家介紹的C#中WPF依賴屬性的正確學(xué)習(xí)方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)我們網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
上一篇:C#控制臺(tái)實(shí)現(xiàn)飛行棋游戲
欄 目:C#教程
下一篇:Unity實(shí)現(xiàn)物體左右移動(dòng)效果
本文標(biāo)題:C#中WPF依賴屬性的正確學(xué)習(xí)方法
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/4685.html
您可能感興趣的文章
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并打開的方法
- 01-10C#實(shí)現(xiàn)Winform中打開網(wǎng)頁(yè)頁(yè)面的方法
- 01-10C#實(shí)現(xiàn)由四周向中心縮小的窗體退出特效
- 01-10Extjs4如何處理后臺(tái)json數(shù)據(jù)中日期和時(shí)間
- 01-10C#中DataGridView常用操作實(shí)例小結(jié)
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10asp.net中XML如何做增刪改查操作
- 01-10C#利用反射技術(shù)實(shí)現(xiàn)去掉按鈕選中時(shí)的邊框效果
- 01-10C#中查找Dictionary中的重復(fù)值的方法
- 01-10C#及WPF獲取本機(jī)所有字體和顏色的方法


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過(guò)重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10delphi制作wav文件的方法
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?


