理解依賴項屬性
依賴項屬性是專門為WPF創建的,在WPF的核心特征中使用,
創建依賴項屬性
public class DP: DependencyObject
{
//宣告依賴項屬性
public static readonly DependencyProperty MydpProperty;
static DP()
{
//指示依賴屬性使用什么服務(如資料系結、影片以及日志)
FrameworkPropertyMetadata metadata = https://www.cnblogs.com/wzmcnblogs/archive/2022/04/23/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 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
文章內容:以上內容均為本人學習整理,如有錯誤,望不吝賜教
著作權:本文著作權歸作者和博客園共有
轉載:歡迎轉載,但未經作者同意,必須保留此段宣告;必須在文章中給出原文連接;否則必究法律責任
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/464943.html
標籤:.NET技术
