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>
原文地址:https://www.cnblogs.com/DebugLZQ/p/2794046.html