《深入浅出WPF》读书笔记.6binding系统(下)
背景
主要讲数据校验和数据转换以及multibinding
代码
binding的数据校验
<Window x:Class="BindingSysDemo.ValidationRulesDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingSysDemo"
mc:Ignorable="d"
Title="ValidationRulesDemo" Height="200" Width="400">
<StackPanel VerticalAlignment="Center">
<TextBox x:Name="tb1" Margin="5"></TextBox>
<Slider x:Name="sld1" Minimum="-10" Maximum="110" Margin="5"></Slider>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace BindingSysDemo
{
/// <summary>
/// ValidationRulesDemo.xaml 的交互逻辑
/// </summary>
public partial class ValidationRulesDemo : Window
{
public ValidationRulesDemo()
{
InitializeComponent();
Binding binding = new Binding("Value") { Source = this.sld1, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
RangeValidationRule rule = new RangeValidationRule();
//此参数用来校验source数据
rule.ValidatesOnTargetUpdated = true;
binding.ValidationRules.Add(rule);
//通过路由事件获取校验的报错信息
//信号在UI树上传递的过程乘坐路由事件
binding.NotifyOnValidationError = true;
this.tb1.SetBinding(TextBox.TextProperty, binding);
//监听校验失败错误
this.tb1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
}
private void ValidationError(object sender, RoutedEventArgs e)
{
if (Validation.GetErrors(this.tb1).Count > 0)
{
this.tb1.ToolTip = Validation.GetErrors(this.tb1)[0].ErrorContent.ToString();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace BindingSysDemo
{
public class RangeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
//throw new NotImplementedException();
double d = 0;
if (double.TryParse(value.ToString(), out d))
{
if (d >= 0 && d <= 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "Validation failed!");
}
}
}
binding的数据转换
<Window x:Class="BindingSysDemo.BindingConverterDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingSysDemo"
mc:Ignorable="d"
Title="BindingConverterDemo" Height="500" Width="600">
<Window.Resources>
<local:Category2SourceConverter x:Key="c2s"></local:Category2SourceConverter>
<local:State2NullableBoolConverter x:Key="s2b"></local:State2NullableBoolConverter>
</Window.Resources>
<StackPanel Background="AliceBlue">
<ListBox x:Name="listBoxPlane" Height="300" Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="40" Height="20" Source="{Binding Path=Category, Converter={StaticResource c2s}}"></Image>
<TextBlock Text="{Binding Path=Name}" Width="60" Margin="80,0"></TextBlock>
<CheckBox IsThreeState="True" IsChecked="{Binding Path=State, Converter={StaticResource s2b}}"></CheckBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="btnLoad" Content="Load" Height="25" Margin="5" Click="btnLoad_Click"></Button>
<Button x:Name="btnSave" Content="Save" Height="25" Margin="5" Click="btnSave_Click"></Button>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace BindingSysDemo
{
/// <summary>
/// BindingConverterDemo.xaml 的交互逻辑
/// </summary>
public partial class BindingConverterDemo : Window
{
public BindingConverterDemo()
{
InitializeComponent();
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
List<Plane> planes = new List<Plane>()
{
new Plane(){Category=Category.Bomber,Name="B-1",State=State.Unknown},
new Plane(){Category=Category.Bomber,Name="B-2",State=State.Unknown},
new Plane(){Category=Category.Fighter,Name="F-22",State=State.Unknown},
new Plane(){Category=Category.Fighter,Name="Su-47",State=State.Unknown},
new Plane(){Category=Category.Bomber,Name="B-52",State=State.Unknown},
new Plane(){Category=Category.Fighter,Name="J-10",State=State.Unknown}
};
this.listBoxPlane.ItemsSource = planes;
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (Plane p in listBoxPlane.Items)
{
sb.AppendLine(string.Format("Category ={0},Name={1},State={2}", p.Category, p.Name, p.State));
}
File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "PlaneList.txt", sb.ToString());
MessageBox.Show("保存成功!");
}
}
public enum Category
{
Bomber,
Fighter
}
public enum State
{
Available,
Locked,
Unknown
}
public class Plane
{
public Category Category { get; set; }
public State State { get; set; }
public string Name { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace BindingSysDemo
{
public class Category2SourceConverter : IValueConverter
{
//将Category转换成Uri
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Category category = (Category)value;
switch (category)
{
case Category.Fighter:
return @"\Icon\Fighter.png";
case Category.Bomber:
return @"\Icon\Bomber.png";
default:
return null;
}
}
//不会被调用
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class State2NullableBoolConverter : IValueConverter
{
//将State转换成bool
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
State state = (State)value;
switch (state)
{
case State.Locked:
return false;
case State.Available:
return true;
case State.Unknown:
default:
return null;
}
}
//不会被调用
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? nb = (bool?)value;
switch (nb)
{
case true:
return State.Available;
case false:
return State.Locked;
case null:
default:
return State.Unknown;
}
}
}
}
multibinding
当页面显示信息不仅由一个控件来决定,就可以使用multibinding。凡是使用binding的地方都可以使用multibinding
<Window x:Class="BindingSysDemo.MultiBindingDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingSysDemo"
mc:Ignorable="d"
Title="MultiBindingDemo" Height="400" Width="600">
<StackPanel>
<TextBox x:Name="tb1" Height="23" Margin="5"></TextBox>
<TextBox x:Name="tb2" Height="23" Margin="5"></TextBox>
<TextBox x:Name="tb3" Height="23" Margin="5"></TextBox>
<TextBox x:Name="tb4" Height="23" Margin="5"></TextBox>
<Button x:Name="btn1" Content="Submit" Width="80" Margin="5"></Button>
</StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace BindingSysDemo
{
/// <summary>
/// MultiBindingDemo.xaml 的交互逻辑
/// </summary>
public partial class MultiBindingDemo : Window
{
public MultiBindingDemo()
{
InitializeComponent();
this.SetMultiBinding();
}
private void SetMultiBinding()
{
//准备基础binding
Binding b1 = new Binding("Text") { Source = this.tb1 };
Binding b2 = new Binding("Text") { Source = this.tb2 };
Binding b3 = new Binding("Text") { Source = this.tb3 };
Binding b4 = new Binding("Text") { Source = this.tb4 };
//multibinding
MultiBinding mb = new MultiBinding();
mb.Bindings.Add(b1);
mb.Bindings.Add(b2);
mb.Bindings.Add(b3);
mb.Bindings.Add(b4);
mb.Converter = new LoginMultiBindingConverter();
this.btn1.SetBinding(Button.IsEnabledProperty, mb);
}
}
public class LoginMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!values.Cast<string>().Any(o => string.IsNullOrEmpty(o)) && values[0].ToString() == values[2].ToString()
&& values[1].ToString() == values[3].ToString())
{
return true;
}
return false;
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
git代码
GitHub - wanghuayu-hub2021/WpfBookDemo: 深入浅出WPF的demo
这章完结了,顺手点个赞老铁。