WPF中的ValidationRule實(shí)現(xiàn)參數(shù)綁定解決方案
背景
應(yīng)用開發(fā)過(guò)程中,常常會(huì)對(duì)用戶輸入內(nèi)容進(jìn)行驗(yàn)證,通常是基于類型、范圍、格式或者特定的要求進(jìn)行驗(yàn)證,以確保輸入符合預(yù)期。例如郵箱輸入框校驗(yàn)輸入內(nèi)容是否符合郵箱格式。在WPF中,數(shù)據(jù)模型允許將ValidationRules
與Binding
對(duì)象關(guān)聯(lián),可以通過(guò)繼承ValidationRule
類并重寫Validate
方法來(lái)創(chuàng)建自定義規(guī)則。
問(wèn)題
盡管創(chuàng)建自定義校驗(yàn)規(guī)則可以滿足大部分應(yīng)用場(chǎng)景,但是當(dāng)我們校驗(yàn)規(guī)則是動(dòng)態(tài)變化的時(shí)候就有些麻煩了。例如,開發(fā)一個(gè)文件管理系統(tǒng),要求文件名不能與系統(tǒng)中已有的文件重名。這個(gè)時(shí)候需要先獲取到系統(tǒng)中已有文件的名稱列表,并綁定到ValidationRule
上。然而ValidationRule
不是繼承于DepedencyObject
,不能添加依賴屬性,自定義的驗(yàn)證規(guī)則中的參數(shù)不支持綁定。
解決方案
接下來(lái)將給出一個(gè)解決方案,讓ValidationRule支持參數(shù)綁定。思路如下:
首先自定義一個(gè)繼承DepedencyObject的類ValidationParams,并在其中添加依賴屬性用于綁定數(shù)據(jù)。
public class ValidationParams:DependencyObject { public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(ValidationParams), new PropertyMetadata(null)); }
然后在自定義校驗(yàn)規(guī)則FileNameValidationRule中添加ValidationParams類型的屬性。
public class FileNameValidationRule : ValidationRule { public ValidationParams Params { get; set; } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { Regex reg = new Regex("[^()()a-zA-Z0-9_\u4e00-\u9fa5]"); if (reg.IsMatch(value.ToString()) || value.ToString().Trim() == "") return new ValidationResult(false, "請(qǐng)輸入字母、數(shù)字、下劃線或漢字"); else if ((Params.Data as List<string>).Contains(value.ToString())) return new ValidationResult(false, "名稱重復(fù),請(qǐng)修改名稱"); else return new ValidationResult(true, null); } }
最后在XAML中輸入框數(shù)據(jù)綁定時(shí)添加校驗(yàn)規(guī)則,并把已有文件的名稱列表綁定到校驗(yàn)規(guī)則參數(shù)中。
<ctoolkit:WatermarkTextBox x:Name="FileNameWTextBox" Watermark="請(qǐng)輸入文件名稱" ShowClearButton="True" Width="418" Height="30" HorizontalAlignment="Left" Margin="90,0,0,0"> <TextBox.Text> <Binding Path="FileName" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <chelper:FileNameValidationRule> <chelper:FileNameValidationRule.Params> <chelper:ValidationParams Data="{Binding DataContext.ListFileName,ElementName=self}"/> </chelper:FileNameValidationRule.Params> </chelper:FileNameValidationRule> </Binding.ValidationRules> </Binding> </TextBox.Text> </ctoolkit:WatermarkTextBox>
然而,事情并沒有那么順利,ValidationParams的Data始終是空的,也就是綁定不成功。這是為什么呢?經(jīng)過(guò)研究發(fā)現(xiàn),F(xiàn)ileNameValidationRule并不在可視化樹上,無(wú)法繼承和訪問(wèn)到DataContext,因此綁定失敗。
解決這個(gè)問(wèn)題的方法其實(shí)也不太復(fù)雜(其實(shí)找解決辦法也是花了點(diǎn)時(shí)間)。思路是利用資源字典和Freezable類。
- 即使不在邏輯樹中的對(duì)象也可以通過(guò)key訪問(wèn)到資源。
- Freezable類的主要目的是定義具有可修改狀態(tài)和只讀狀態(tài)的對(duì)象,但是比較幸運(yùn)的是這個(gè)類的實(shí)例不在可視化樹或邏輯樹中也可以繼承到DataContext,目前我也不清楚這里的原理。
根據(jù)這兩點(diǎn)信息,首先定義一個(gè)繼承于Freezable的類BindingProxy,包含一個(gè)用于綁定數(shù)據(jù)的依賴屬性DataProperty。
public class BindingProxy : Freezable { protected override Freezable CreateInstanceCore() { return new BindingProxy(); } public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc... public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null)); }
然后在WatermarkTextBox的資源字典中實(shí)例化BindingProxy,并綁定已有文件名稱列表,然后在校驗(yàn)規(guī)則參數(shù)ValidationParams的Data中綁定BindingProxy實(shí)例。
<ctoolkit:WatermarkTextBox x:Name="FileNameWTextBox" Watermark="請(qǐng)輸入文件名稱" ShowClearButton="True" Width="418" Height="30" HorizontalAlignment="Left" Margin="90,0,0,0"> <ctoolkit:WatermarkTextBox.Resources> <chelper:BindingProxy x:Key="FileNamesProxy" Data="{Binding DataContext.ListFileName,ElementName=self}"/> </ctoolkit:WatermarkTextBox.Resources> //上文中已有代碼此處省略... <chelper:ValidationParams Data="{Binding Source={StaticResource FileNamesProxy},Path=Data}"/> //上文中已有代碼此處省略... </ctoolkit:WatermarkTextBox>
小結(jié)
在WPF中,默認(rèn)情況下,DataContext是通過(guò)可視化樹來(lái)傳遞的。父元素的DataContext會(huì)自動(dòng)傳遞給其子元素,以便子元素可以訪問(wèn)父元素的數(shù)據(jù)對(duì)象。但是,不在可視化樹上的對(duì)象,無(wú)法繼承和直接綁定到DataContext。本文的案例也是在這個(gè)地方卡殼了,雖然最終解決了這個(gè)問(wèn)題,但是Freezable類如何繼承到DataContext的原理還有待研究。
到此這篇關(guān)于WPF中的ValidationRule實(shí)現(xiàn)參數(shù)綁定解決方案的文章就介紹到這了,更多相關(guān)WPF ValidationRule參數(shù)綁定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c#使用windows服務(wù)更新站點(diǎn)地圖的詳細(xì)示例
這篇文章主要介紹了c#使用windows服務(wù)更新站點(diǎn)地圖的詳細(xì)示例,需要的朋友可以參考下2014-04-04C#實(shí)現(xiàn)軟件防破解和防調(diào)試的幾種有效措施
軟件保護(hù)在現(xiàn)代應(yīng)用程序開發(fā)中變得越來(lái)越重要,尤其是在面對(duì)軟件盜版、調(diào)試和破解等問(wèn)題時(shí),在C#開發(fā)中,雖然沒有完全防止破解的辦法,但通過(guò)采取一些有效的防護(hù)措施,可以顯著增加破解的難度并保護(hù)軟件的知識(shí)產(chǎn)權(quán),本篇文章將探討在C#中實(shí)現(xiàn)軟件防破解和防調(diào)試的幾種常見技術(shù)2025-03-03C#實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能(附源碼)
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)易計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07淺析c#范型中的特殊關(guān)鍵字where & default
以下是對(duì)c#范型中的特殊關(guān)鍵字where和default進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下2013-09-09C#反射之基礎(chǔ)應(yīng)用實(shí)例總結(jié)
這篇文章主要介紹了C#反射之基礎(chǔ)應(yīng)用實(shí)例總結(jié),包括了反射的基本原理與用法實(shí)例,需要的朋友可以參考下2014-10-10C# 實(shí)現(xiàn)Zookeeper分布式鎖的參考示例
Zookeeper分布式鎖的原理是巧妙的是使用了znode臨時(shí)節(jié)點(diǎn)的特點(diǎn)和監(jiān)聽(watcher)機(jī)制,監(jiān)聽機(jī)制很簡(jiǎn)單,就是我們可以給znode添加一個(gè)監(jiān)聽器,當(dāng)znode節(jié)點(diǎn)狀態(tài)發(fā)生改變時(shí)(如:數(shù)據(jù)內(nèi)容改變,節(jié)點(diǎn)被刪除),會(huì)通知到監(jiān)聽器。本文講解使用c#實(shí)現(xiàn)該功能2021-06-06C# 特性AttributeUsage簡(jiǎn)介與使用教程
這篇文章主要介紹了C# 特性AttributeUsage簡(jiǎn)介與使用教程,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05