1. 程式人生 > >WPF 之 Binding 對資料的校驗與轉換(三)

WPF 之 Binding 對資料的校驗與轉換(三)

# 一、前言 ​ Binding 的作用就是架在 **Source** 和 **Target** 之間的橋樑,資料可以在這座橋樑的幫助下來流通。就像現實中的橋樑會設定一些關卡進行安檢一樣,Binding 這座橋上也可以設定關卡對資料的有效性進行校驗。不僅如此,當兩端要求使用不同的資料型別時,我們還可以為資料設定轉換器。 ​ Binding 用於資料有效性校驗的關卡是它的 **ValidationRules** 屬性,用於資料轉換的關卡是它的 **Converter ** 屬性。 # 二、Binding 對資料的校驗 ​ 例如:我們把一個 Slider 的Value 屬性和 TextBox 的 Text 屬性雙向繫結在一起, Slider 的Value 的有效值是 0~100。當我們使用 Binding 繫結數值時,需要對該 Binding 的 ValidationRules 新增校驗規則。具體實現如下所示: ​ 第一步:我們宣告一個 RangeValidationRule 類編寫校驗規則,該類需要繼承 **ValidationRule** 類(該類為抽象類),ValidationRule類的作用是**提供建立自定義規則的一個方式,旨在檢查使用者輸入的有效性**。具體程式碼如下: ```c# public class RangeValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { if (double.TryParse(value.ToString(), out var d)) { if (d >= 0 && d <= 100) { return new ValidationResult(true, null); } } return new ValidationResult(false, "Validation value"); } } ``` ​ 第二步:對 TextBox 的 Text 屬性進行 Binding 繫結,並對該 Binding 的 ValidationRules 新增一個校驗規則 RangeValidationRule 類,具體實現如下: ```html ``` 然後,我們在文字框中,輸入200,發現 TextBox 會顯示紅色邊框,這表示數值是錯誤的,具體顯示如下圖: ![image-20210205151612353](https://i.loli.net/2021/02/05/PYNawxbMqW38FS4.png) # 三、Binding 的資料轉換 ​ 例如:我們實現如下一個程式,程式的用途是在列表裡向玩家顯示一些軍用飛機的狀態。資料型別如下: ```c# public enum Category { Bomber, Fighter, } public enum State { Available, Locked, Unknown, } public class Plane { public Category Category { get; set; } public string Name { get; set; } public State State { get; set; } } ``` ​ 在UI中,Plane 的 Category 屬性被對映為圖片,State 被對映為 CheckBox 的 IsChecked 屬性。具體轉換規則如下: ```c# public class CategoryToSourceConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var c = (Category)value; switch (c) { case Category.Bomber: return "image/bomber.png"; case Category.Fighter: return "image/fighter.png"; } return new ValidationResult(false, "Validation Value"); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class StateToBoolConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var s = (State) value; switch (s) { case State.Available: return true; case State.Locked: return false; default: return null; } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var b = (bool?) value; switch (b) { case true: return State.Available; case false: return State.Locked; default: return State.Unknown; } } } ``` ​ 我們新增一個 ViewModel 繫結到 UI 上,ViewModel 程式碼如下(屬性變更可以閱讀 ): ```c# public class Window3VM : NotifyProperty { private ObservableCollection _planes; private string _output; public ObservableCollection Planes { get => _planes; set => SetProperty(ref _planes, value); } public string Output { get => _output; set => SetProperty(ref _output, value); } } ``` ​ 我們把 ViewModel 繫結到 UI 介面上,並把轉換規則新增到對應的 Binding 上,具體實現如下: ```html
``` ​ 如下所示,當我們點選Load 按鈕後,加載出來列表,點選 Save 按鈕後,把整個列表輸出到右邊的文字框: ```c# /// /// Window3.xaml 的互動邏輯 /// public partial class Window3 : Window { private readonly Window3VM vm; public Window3() { InitializeComponent(); this.DataContext= vm =new Window3VM(); } private void ButtonLoad_OnClick(object sender, RoutedEventArgs e) { vm.Planes=new ObservableCollection() { new Plane(){Name = "B-1", Category = Category.Bomber, State = State.Unknown,}, new Plane(){Name = "F-35",Category = Category.Fighter,State = State.Unknown,}, new Plane(){Name = "B-6", Category = Category.Bomber, State = State.Unknown,}, new Plane(){Name = "F-22",Category = Category.Fighter,State = State.Unknown,}, new Plane(){Name = "J-20",Category = Category.Fighter,State = State.Unknown,}, }; } private void ButtonSave_OnClick(object sender, RoutedEventArgs e) { StringBuilder sb = new StringBuilder(); foreach (var plane in vm.Planes) { sb.Append($"{plane.Category},{plane.Name},{plane.State}\r\n"); } vm.Output = sb.ToString(); } } ``` ![image-20210205154832112](https://i.loli.net/2021/02/05/jao8LbkZdYfz