WPF Binding转换与校验
Binding是WPF的核心,而数据的转换与校验是与Binding配套的,其重要性不言而喻,前面介绍了WPF的Binding,现在来看下Converter&Validation。本文目标是以简单的Demo展示Converter&Validation的用法。
Binding用于数据有效性校验的是Binding的ValidationRules属性,用于数据类型转换的是Binding的Converter属性。
当Source端Path所关联的数据与Target目标属性数据类型不一致是,我们可以添加数据转换器。给出一个Demo。
首先在xaml界面中定义一个Grid。
<Grid> <TextBlock x:Name="txtMsg" Text="{Binding ElementName=txtBox, Path=(Validation.Errors)[0].ErrorContent}" Foreground="Red" FontWeight="Bold" Margin="34,12,161,280" /> <DataGrid AutoGenerateColumns="False" Margin="34,48,44,21" Name="dataGrid1" DataContext="{Binding}"> <DataGrid.Columns> <DataGridTemplateColumn Header="Id" Width="*" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock FontSize="16" Text="{Binding Id}" Background="{Binding Id,Converter={StaticResource IdConverter1}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="Name" Width="2*" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <!--<TextBlock Text="{Binding Name}"/>--> <TextBlock x:Name="txtBox" Validation.ErrorTemplate="{StaticResource errorTemplate}" Validation.Error="txtBox_Error" > <TextBlock.Text> <Binding Path="Name" NotifyOnValidationError="True" > <Binding.ValidationRules> <local:NameValidationRule ValidatesOnTargetUpdated="True" /> </Binding.ValidationRules> </Binding> </TextBlock.Text> </TextBlock> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="Age" Width="*" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Age}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid>
下面自定义一个DataTable对象,作为Grid的数据源。
using System.Data; namespace ConverterAndValidation { public class ClassData { /// <summary> /// 手动创建一个DataTable /// </summary> /// <returns></returns> public static DataTable GetDataTable() { DataTable dt = new DataTable(); dt.Columns.Add("Id"); dt.Columns.Add("Name"); dt.Columns.Add("Age"); // for (int i = 1; i <= 10; i++) { DataRow dr = dt.NewRow(); dr.ItemArray = new object[] { i, "DebugLZQ"+i, 25+i }; dt.Rows.Add(dr); } return dt; } } }
Binding如下:
DataTable dt = ClassData.GetDataTable();
dataGrid1.ItemsSource = dt.DefaultView;
为了进行转换需要实现IValueConverter接口。
using System; using System.Windows.Data; using System.Windows.Media; namespace ConverterAndValidation { class IdConverter:IValueConverter { #region IValueConverter 成员 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int id = int.Parse(value.ToString()); if (id == 1) return new SolidColorBrush(Colors.Silver ); if (id == 2) return new SolidColorBrush(Colors.Teal ); else return new SolidColorBrush(Colors.Gold ); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } }
如何消费这个IdConverter呢?
添加一个xmlns
xmlns:local="clr-namespace:ConverterAndValidation"
添加Window.Resources资源
<local:IdConverter x:Key="IdConverter1"/>
在Binding处
<TextBlock FontSize="16" Text="{Binding Id}" Background="{Binding Id,Converter={StaticResource IdConverter1}}"/>
下面同样以这个例子,写数据校验的Demo。
为了进行校验,需要准备一个抽象类ValidationRule的派生类。
using System.Windows.Controls; namespace ConverterAndValidation { class NameValidationRule:ValidationRule { public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { string name = value.ToString(); if (name!= "DebugLZQ5") { return new ValidationResult(true, null); } return new ValidationResult(false, "Error Name,Validation Failed."); } } }
如何消费这个Validation?在Window.Resources中添加
<local:NameValidationRule x:Key="NameValidationRule1"/>
<ControlTemplate x:Key="errorTemplate"> <!--<StackPanel> <TextBlock Foreground="Red">Invalid Value!!!</TextBlock> <AdornedElementPlaceholder/> </StackPanel>--> <DockPanel> <TextBlock Foreground="Red">Invalid Value!!!</TextBlock> <AdornedElementPlaceholder/> </DockPanel> </ControlTemplate>
Binding部分
<TextBlock x:Name="txtBox" Validation.ErrorTemplate="{StaticResource errorTemplate}" Validation.Error="txtBox_Error" > <TextBlock.Text> <Binding Path="Name" NotifyOnValidationError="True" > <Binding.ValidationRules> <local:NameValidationRule ValidatesOnTargetUpdated="True" /> </Binding.ValidationRules> </Binding> </TextBlock.Text> </TextBlock>
txtBox_Error如下
private void txtBox_Error(object sender, ValidationErrorEventArgs e) { if (e.Action == ValidationErrorEventAction.Added) // Validation Error Occurred { txtMsg.Text = e.Error.ErrorContent.ToString(); } else // No Error { txtMsg.Text = ""; } }
程序的运行结果如下:
附:程序完整的xaml如下:
View Code
<Window x:Class="ConverterAndValidation.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ConverterAndValidation" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <local:IdConverter x:Key="IdConverter1"/> <local:NameValidationRule x:Key="NameValidationRule1"/> <ControlTemplate x:Key="errorTemplate"> <!--<StackPanel> <TextBlock Foreground="Red">Invalid Value!!!</TextBlock> <AdornedElementPlaceholder/> </StackPanel>--> <DockPanel> <TextBlock Foreground="Red">Invalid Value!!!</TextBlock> <AdornedElementPlaceholder/> </DockPanel> </ControlTemplate> </Window.Resources> <Grid> <TextBlock x:Name="txtMsg" Text="{Binding ElementName=txtBox, Path=(Validation.Errors)[0].ErrorContent}" Foreground="Red" FontWeight="Bold" Margin="34,12,161,280" /> <DataGrid AutoGenerateColumns="False" Margin="34,48,44,21" Name="dataGrid1" DataContext="{Binding}"> <DataGrid.Columns> <DataGridTemplateColumn Header="Id" Width="*" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock FontSize="16" Text="{Binding Id}" Background="{Binding Id,Converter={StaticResource IdConverter1}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="Name" Width="2*" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <!--<TextBlock Text="{Binding Name}"/>--> <TextBlock x:Name="txtBox" Validation.ErrorTemplate="{StaticResource errorTemplate}" Validation.Error="txtBox_Error" > <TextBlock.Text> <Binding Path="Name" NotifyOnValidationError="True" > <Binding.ValidationRules> <local:NameValidationRule ValidatesOnTargetUpdated="True" /> </Binding.ValidationRules> </Binding> </TextBlock.Text> </TextBlock> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="Age" Width="*" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding Age}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window>