WPF 之 Binding 對資料的校驗與轉換(三)
阿新 • • 發佈:2021-02-06
# 一、前言
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