ValidateItemsInItemsControl在ItemsControl中的验证项处理

该应用程序提示用户输入多个客户,并为每个客户指定一个销售代表。 该应用程序检查销售代表和客户是否属于同一区域。 如果所有验证规则都成功,则该示例将调用 UpdateSources 来验证绑定并将值保存到源。

实现效果:

  1. 进行一项组件Customers的数据(地区与对应代理)验证,并显示错误提示。
  2. 对再添加一项组件进行数据验证,并显示验证错误信息框提示。

clipboard.png
clipboard.png

练习:

  1. ItemsControl.ItemBindingGroup 属性
  2. ComboBox的itemsSource绑定与SelectedItem绑定
  3. Validation.ValidationAdornerSite

数据源xaml
类型作为方法参数值的表示如下:

<ObjectDataProvider MethodName="GetValues"
              ObjectType="{x:Type sys:Enum}"
              x:Key="RegionValues">

    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="local:Region" />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

<local:Representantives x:Key="SaleReps"/>

复杂的数据模板如下:

<DataTemplate x:Key="ItemTemplate" >
    <StackPanel Orientation="Horizontal" >
        <TextBlock Text="Customer Name" Margin="5"/>
        <TextBox Width="100" Margin="5" Text="{Binding Name}"/>
        <TextBlock Text="Region" Margin="5"/>
        <ComboBox ItemsSource="{Binding Source={StaticResource RegionValues}}" 
        SelectedItem="{Binding Location}"  Width="100" Margin="5"/>
        <TextBlock Text="Service Representative" Margin="5"/>
        <ComboBox ItemsSource="{Binding Source={StaticResource SaleReps}}"
        SelectedItem="{Binding ServiceRepresentative}"  Width="200" Margin="5"/>
        <Button Content="Save Customer" Click="saveCustomer_Click"/>
    </StackPanel>
</DataTemplate>

ItemsControl作为可添加元素的控件如下:
其中Validation.ValidationAdornerSite 和Validation.ValidationAdornerSiteFor 附加属性相互引用,您可以设置其中任一属性。例如,假设 Label 显示数据绑定 TextBox 上发生的验证错误。 可以执行下列操作之一来建立该关系:

  1. 将 TextBox 的 Validation.ValidationAdornerSite 设置为 Label。
  2. 将 Label 的 Validation.ValidationAdornerSiteFor 设置为 TextBox。

当设置其中一个属性时,另一个属性会设置为您在其上设置附加属性的元素;无论您选择前面哪个选项, TextBox 的 Validation.ValidationAdornerSite 均为 Label,且 Label 的 ValidationAdornerSiteFor 均为 TextBox。

<ItemsControl Margin="5"  Name="customerList"  ItemTemplate="{StaticResource ItemTemplate}"
          ItemsSource="{Binding}">
    <ItemsControl.ItemBindingGroup>
        <BindingGroup>
            <BindingGroup.ValidationRules>
                <local:AreasMatch/>
            </BindingGroup.ValidationRules>
        </BindingGroup>
    </ItemsControl.ItemBindingGroup>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="{x:Type ContentPresenter}">
            <Setter Property="Validation.ValidationAdornerSite"
                                        Value="{Binding ElementName=validationErrorReport}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

<Label Name="validationErrorReport" 
     Content="{Binding RelativeSource={RelativeSource Self}, 
   Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)[0].ErrorContent}"
   Margin="5" Foreground="Red" HorizontalAlignment="Center"/>

思路:

  1. 在ItemTemplate中处理要模型类Customer的属性数据绑定,其中有ComboBox显示枚举类型及SelectedItem的数据绑定。
  2. 在ItemsControl中进行ItemBindingGroup,进行item的模型类属性间的匹配验证;当点击保存按钮时进行数据验证:当其中一项验证成功后可添加下一项,或多项中只要有一项验证错误就进行提示,不可再添加项。(此示例有bug,在未选择ComboBox数据时进行验证程序崩溃)
  3. 添加按钮进行添加项,同时进行数据验证。
private void saveCustomer_Click(object sender, RoutedEventArgs e)
{
    var btn = sender as Button;
    var container = (FrameworkElement) customerList.ContainerFromElement(btn);

    // If the user is trying to change an items, when another item has an error,
    // display a message and cancel the currently edited item.
    if (_bindingGroupInError != null && _bindingGroupInError != container?.BindingGroup)
    {
        MessageBox.Show("Please correct the data in error before changing another customer");
        container.BindingGroup.CancelEdit();
        return;
    }

    if (container.BindingGroup.ValidateWithoutUpdate())
    {
        container.BindingGroup.UpdateSources();
        _bindingGroupInError = null;
        MessageBox.Show("Item Saved");
    }
    else
    {
        _bindingGroupInError = container.BindingGroup;
    }
}

以上代码进行保存时进行数据验证,具体步骤如下:

  1. 找到拥有当前项的ItemsControl,判断验证集合BindingGroup _bindingGroupInError若出现有ItemsControl的验证错误信息,就显示里面的项有验证错误,提示后进行container.BindingGroup.CancelEdit();
  2. 若验证成功,则此方法将更新源,但不会使源提交挂起的更改并结束编辑事务。 也就是说,如果源对象实现 IEditableObject, 则调用此方法时不会调用 EndEdit。 若要使源提交挂起的更改,请使用 CommitEdit 方法。
private void AddCustomer_Click(object sender, RoutedEventArgs e)
{
    if (_bindingGroupInError == null)
    {
        _customerData.Add(new Customer());
    }
    else
    {
        MessageBox.Show("Please correct the data in error before adding a new customer.");
    }
}

扩展:

  1. BindingGroup.ValidateWithoutUpdate 方法:对绑定和将 ValidationStep 属性设置为 RawProposedValue 或 ConvertedProposedValue 的 ValidationRule 对象运行转换器。如果验证规则成功,则为 true;否则为 false。
  2. 则该示例将调用 UpdateSources 来验证绑定并将值保存到源。

李志玮
22 声望34 粉丝

求索~~


引用和评论

0 条评论