把對象賦值給屬性
一、依賴屬性
1.定義依賴屬性
一般情況下只是使用,但如果要自定義WPF控件或者給現有的WPF控件增加新功能時就需要自定義。
定義時需要用到特殊的語法:
- 靜態的
- 使用readonly只能在構造時初始化
- 必須是DependencyProperty類實例
- 屬性名稱后面要帶上Property
定義一個Margin依賴項屬性的例子
public static readonly DependencyProperty MarginProperty;
2.注冊依賴屬性
(1)創建FrameworkPropertyMetadata對象,指明通過依賴項屬性使用什么服務(支持數據綁定,動畫,日志等)
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure);
(2)調用DependencyProperty.Register()靜態方法注冊屬性
五個參數
- 屬性名
- 屬性使用的數據類型
- 擁有該屬性的類型
- 具有附加屬性設置的FrameworkPropertyMetadata對象(此參數可選)
- 用於驗證屬性的回調函數(此參數可選)
在構造函數中
MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(FrameworkElement), metadata, new ValidateValueCallback(FrameworkElement.IsMarginValid));
3.封裝WPF依賴屬性
使用DependencyObject類的SetValue()和GetValue()方法
public Thickness Margin { set { SetValue(MarginProperty, value); } get { return (Thickness)GetValue(MarginProperty); } }
設置屬性
element.Margin = new Thickness(5);
4.例子
一個按鈕繼承關系 Button--》ButtonBase--》ContentControl--》Control--》FrameworkElement--》UIElement--》Visual--》DependencyObject--》DispatcherObject--》Object
其中
- ButtonBase 表示所有 Button 控件的基類,在System.Windows.Controls.Primitives命名空間下(和winfrom下的ButtonBase雖然名字相同,但完全是兩條不同的路線)
- ContentControl 表示包含一段任意類型內容的控件
- Control 表示用戶界面 (UI) 元素的基類,這些元素使用 ControlTemplate 來定義其外觀
- FrameworkElement 提供 WPF元素的屬性、事件和方法的 WPF 框架級別集
- UIElement 是 WPF 核心級實現的基類,這些實現是在 WPF元素和基本表示特性上生成的
- Visual 為 WPF 中的呈現提供支持,其中包括命中測試、坐標轉換和邊界框計算
- DependencyObject 表示參與依賴屬性系統的對象,如果設置依賴屬性直接繼承此類即可
完整代碼:自定義FrameworkElement類
class FrameworkElement:UIElement { public static readonly DependencyProperty MarginProperty; static FrameworkElement() { FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(new Thickness(), FrameworkPropertyMetadataOptions.AffectsMeasure); MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(FrameworkElement), metadata, new ValidateValueCallback(FrameworkElement.IsMarginValid)); } private static bool IsMarginValid(object value) { throw new NotImplementedException(); } public Thickness Margin { set { SetValue(MarginProperty, value); } get { return (Thickness)GetValue(MarginProperty); } } }
去掉ValidateValueCallback參數
使用
FrameworkElement element = new FrameworkElement(); element.Margin = new Thickness(5);
4.依賴屬性變更通知
有兩種方式通知依賴屬性變化 --后補
(1)屬性值創建綁定
(2)編寫能夠自動改變其他屬性或開始動畫的觸發器
5.共享依賴屬性
查看TextBlock源碼,沒有用DependencyProperty.Register注冊,而是使用了TextElement的FontFamilyProperty的依賴屬性
FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock));
6.附加依賴屬性
附加屬性被應用的類不是定義附加屬性的那個類,
比如 DockPanel 的DockProperty屬性
[CommonDependencyProperty] public static readonly DependencyProperty DockProperty; static DockPanel() { DockProperty = DependencyProperty.RegisterAttached("Dock", typeof(Dock), typeof(DockPanel), new FrameworkPropertyMetadata(Dock.Left, OnDockChanged), IsValidDock); }
DockPanel.Dock 屬性作用到了Border上
<DockPanel LastChildFill="True"> <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top"> <TextBlock Foreground="Black">Dock = "Top"</TextBlock> </Border> <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top"> <TextBlock Foreground="Black">Dock = "Top"</TextBlock> </Border> <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom"> <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock> </Border> <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left"> <TextBlock Foreground="Black">Dock = "Left"</TextBlock> </Border> <Border Background="White" BorderBrush="Black" BorderThickness="1"> <TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock> </Border> </DockPanel>
附加屬性不需要進行屬性封裝,可以用於任何依賴對象
二、屬性驗證
1.驗證回調
2.強制回調