理解依賴項屬性 依賴項屬性是專門為WPF創建的,在WPF的核心特征中使用。 創建依賴項屬性 public class DP: DependencyObject { //聲明依賴項屬性 public static readonly DependencyProperty MydpProperty; st ...
理解依賴項屬性
依賴項屬性是專門為WPF創建的,在WPF的核心特征中使用。
創建依賴項屬性
public class DP: DependencyObject
{
//聲明依賴項屬性
public static readonly DependencyProperty MydpProperty;
static DP()
{
//指示依賴屬性使用什麼服務(如數據綁定、動畫以及日誌)
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(default(double),
FrameworkPropertyMetadataOptions.AffectsMeasure);
//註冊依賴屬性
MydpProperty = DependencyProperty.Register("Mydp", typeof(double), typeof(DP), metadata,
new ValidateValueCallback(ShirtValidateCallback));
//以上Register方法參數
//1、屬性名 2、屬性數據類型 3、擁有該屬性的類型 4、附加屬性設置的FrameworkPropertyMetadata對象(可選) 5、驗證屬性的回調函數(可選)
}
//添加屬性包裝器 DependencyObject.SetValue() or DependencyObject.GetValue()
//DependencyObject.Clear(DP.MydpProperty) 刪除本地值設置
public double Mydp
{
set { SetValue(MydpProperty, value); }
get { return (double)GetValue(MydpProperty); }
}
private static bool ShirtValidateCallback(object value)
{
return true;
}
}
使用依賴項屬性
依賴項屬性的兩個關鍵行為——更改通知和動態值識別。Visual Studio快捷鍵 (propdp+Tab)
-
更改通知:當屬性值發生改變,依賴項屬性不會自動引發事件,以通知一個屬性值發生變化。而是觸發一個受保護的OnPropertyChangedCallBack()方法,該方法通過兩個WPF服務(數據綁定和觸發器)傳遞信息,並調用PropertyChangedCallback回調函數。
-
動態值識別:按照一定優先順序來檢索基本值,檢索改變屬性值的提供者。
優先順序由小到大讓如下:
1、預設值(FrameworkPropertyMetadata對象設置的值)。2、繼承而來的值。3、主題樣式值。 4、項目樣式值。5、本地值(元素對象直接設置的值)
1、基本值(如上)。2、表達式值(數據綁定和資源)3、動畫的目標,應用該動畫。4、運行CoerceValueback回調函數修的正屬性值。
共用的依賴項屬性
DependencyProperty.AddOwner(Typeof(DependencyObject));
//註冊在TextElement靜態構造函數中,在TextBlock靜態構造函數中只是簡單的重用
TextBlock.FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock));
附加屬性
註冊附加屬性使用RegisterAttached()方法,與註冊依賴屬性相同,附加屬性不設置屬性包裝器,通過調用兩個靜態方法來設置和獲取屬性值。Visual Studio快捷鍵
(propa+Tab)
//註冊附加屬性
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.RegisterAttached("Password", typeof(string), typeof(ADP), new PropertyMetadata(string.Empty));
public static string GetPassword(DependencyObject obj)
{
return (string)obj.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject obj, string value)
{
obj.SetValue(PasswordProperty, value);
}
//這段代碼不會拋異常,這是因為Button不會去找他不知道的屬性值
Button btn = sender as Button;
btn.SetValue(PasswordBox.PasswordCharProperty, '*');
//PasswordCharProperty是屬於PasswordBox的屬性值,所以密碼圖形會發生改變。
if (this.pwd is PasswordBox passwordbox)
{
passwordbox.SetValue(PasswordBox.PasswordCharProperty, '*');
}
示例,以PasswordBox添加附加屬性來對密碼進行binding。
public class PasswordHelper
{
/// <summary>
/// 回調函數中避免無意義的賦值操作
/// </summary>
static bool _isUpdate = false;
/// <summary>
/// PasswordProperty 附加屬性的功能就像是一個橋梁,通過回調函數和密碼框事件來實現數據通知。
/// </summary>
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordHelper),
new PropertyMetadata(string.Empty, new PropertyChangedCallback(PasswordChangedCallBack)));
public static string GetPassword(DependencyObject obj)
{
return (string)obj.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject obj, string value)
{
obj.SetValue(PasswordProperty, value);
}
private static void PasswordChangedCallBack(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
//當附加屬性PasswordHelper.PasswordProperty發生改變時,觸發此回調方法
PasswordBox passwordbox = o as PasswordBox;
passwordbox.PasswordChanged -= Passwordbox_PasswordChanged;
if (!_isUpdate)
{
//PasswordProperty綁定屬性發生變化時,將PasswordProperty值賦給界面PasswordBox的Password屬性
passwordbox.Password = e.NewValue?.ToString();
}
passwordbox.PasswordChanged += Passwordbox_PasswordChanged;
}
private static void Passwordbox_PasswordChanged(object sender, RoutedEventArgs e)
{
//當界面PasswordBox的Password發生變化時觸發此事件處理器。
PasswordBox passwordBox = sender as PasswordBox;
_isUpdate = true;
//當密碼值發生變化時,將密碼賦值給附加屬性PasswordProperty
SetPassword(passwordBox, passwordBox.Password);
_isUpdate = false;
}
public static bool GetAttach(DependencyObject obj)
{
return (bool)obj.GetValue(AttachProperty);
}
public static void SetAttach(DependencyObject obj, bool value)
{
obj.SetValue(AttachProperty, value);
}
//初始化時為PasswordBox的PasswordChanged事件添加事件處理器
public static readonly DependencyProperty AttachProperty =
DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordHelper),
new PropertyMetadata(false, new PropertyChangedCallback(AttachChangedCallBack)));
private static void AttachChangedCallBack(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = o as PasswordBox;
if (passwordBox != null)
return;
//當舊值是true時,清理事件處理器
if ((bool)e.OldValue)
{
passwordBox.PasswordChanged -= Passwordbox_PasswordChanged;
}
//當此附加屬性設置為True時添加事件處理啟
if ((bool)e.NewValue)
{
passwordBox.PasswordChanged += Passwordbox_PasswordChanged;
}
}
}
<PasswordBox Width="200" Height="20" Margin="0,10" local:PasswordHelper.Attach="True"
local:PasswordHelper.Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
屬性驗證
WPF提供兩種方法來阻止非法值:
- ValidateValueCallback:該回調函數可接受或拒絕新值,通常用與捕獲違反屬性約束的明顯錯誤。作為DependencyProperty.Register()的一個參數提供該回調函數。
- CoerceValueCallback:該回調函數能將新值修改為更能接受的值。作為FrameworkPropertyMetadata對象的構造函數的一個參數提供該回調函數。
進行屬性驗證的過程:
1)首先,CoerceValueCallback方法有機會修改提供的值,或者返回DependencyProperty.UnsetValue,這會完全拒絕修改。
2)接下來激活ValiadataValueCallback方法,返回true接受一個合法值,返回false拒絕值。ValiadataValueCallback方法不能訪問設置屬性的對象,不能檢查其他屬性值。
3)最後,如果前兩個階段都成功,就會觸發PropertyChangedCallback方法。
public class MyBtn : Button
{
public double Max
{
get { return (double)GetValue(MaxProperty); }
set { SetValue(MaxProperty, value); }
}
// Using a DependencyProperty as the backing store for Max. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MaxProperty =
DependencyProperty.Register("Max", typeof(double), typeof(MyBtn),
new PropertyMetadata(default(double), new PropertyChangedCallback(MaxPropertyChangedCallback),
new CoerceValueCallback(MaxCoerceValueCallback)), new ValidateValueCallback(MaxValidateValueCallback));
//當此回調返回DependencyProperty.UnsetValue時,不會進入PropertyChangedCallback回調函數,回調修改後返回的值類型要與DependncyProperty類型一致,否則會在INorifyPropertyChanged介面的PropertyChanged事件的調用的地方拋出異常。
public static object MaxCoerceValueCallback(DependencyObject sender, object obj)
{
if (double.Parse(obj.ToString()) > 50)
{
return (object)50.0;
}
return obj;
#if test
return DependencyProperty.UnsetValue;
#endif
}
public static void MaxPropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
MyBtn button = (MyBtn)o;
button.Height = (double)e.NewValue;
}
//當此回調函數返回false時,不會再進入CoerceValueCallback和PropertyChangedCallback回調函數,會在INorifyPropertyChanged介面的PropertyChanged事件的調用的地方拋出異常。
public static bool MaxValidateValueCallback(object value)
{
if (double.TryParse(value.ToString(), out double i))
{
return true;
}
else
{
return false;
}
}
}
作者:藍白永恆出處:https://www.cnblogs.com/wzmcnblogs/p/16183637.html
文章內容:以上內容均為本人學習整理,如有錯誤,望不吝賜教
版權:本文版權歸作者和博客園共有
轉載:歡迎轉載,但未經作者同意,必須保留此段聲明;必須在文章中給出原文連接;否則必究法律責任