整个控件形式的验证顺序

时间:2011-09-12 15:01:53

标签: c# wpf validation

我正在学习这个wpf的东西,并试图让我的头脑周围的控件验证。特别是我正在寻找的是......

  1. 表单上可以有100个控件(夸大但可能)。表单的布局和流程是特定顺序(通过用户的选项卡顺序)。用户可能永远不会到达某些“必需”字段并单击“保存”按钮。如何触发它,以便所有控件强制触发各自的“验证”事件。

  2. 基于以上所述,WPF框架是否按照用户正在查看的Tab键顺序处理验证规则。如果没有,那么如何控制它以匹配数据输入流而不是按顺序跳转,应用程序发生创建对象及其各自的验证规则。

  3. 是否有办法让所有失败的控件触发为在失败的控件周围放置红色边框的默认行为,而不是一次只有一个。

  4. 由于

3 个答案:

答案 0 :(得分:1)

通常,要完成您要查找的内容,请使用MVVM类型模式。这意味着您将收集WPF表单中的数据的每个控件绑定到支持字段或属性。您将为绑定添加验证,其样式将导致红色边框框。对于具有所需数据的控件,部分验证是填写它们。您可以为此定义一个称为“ValidWhenHasData”的验证规则或其他一些验证规则。

要使验证仅在您按“保存”等时触发,您可以通过多种方式执行此操作。我通常在每个验证规则中创建一个名为“IsEnabled”的属性,默认情况下将其设置为false;如果设置为false,则验证规则始终返回有效。然后,我在要验证的控件的代码隐藏中添加一个列表。单击“保存”时,我将浏览列表并将所有验证规则'IsEnabled设置为true,清除列表中控件的所有错误,然后刷新每个上的绑定。这将在未填充的任何内容上显示红色矩形,或者在您定义为错误条件的任何其他内容上显示红色矩形。您还可以使用此列表按照您选择的顺序将焦点设置为第一个验证失败的控件。

示例验证控件模板,其中包含验证错误工具提示的占位符:

<ControlTemplate x:Key="errorTemplate">
    <Canvas Width="{Binding Path=AdornedElement.ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Adorner}}}" Height="{Binding Path=AdornedElement.ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Adorner}}}">
        <Border BorderBrush="Red" BorderThickness="1">
            <AdornedElementPlaceholder/>
        </Border>
        <Border Canvas.Top="-5" Canvas.Right="-5" BorderBrush="Gray" BorderThickness="1" >
            <TextBlock x:Name="errorBlock" TextAlignment="Center" Background="Red" Foreground="White" Width="10" Height="10" FontSize="9" ctl:valTooltip.MessageBody="{Binding Path=AdornedElement.(Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Adorner}}}">*</TextBlock>
        </Border>
    </Canvas>
</ControlTemplate>

验证绑定示例:

<TextBox x:Name="TBNumItems" Margin="2,2,2,2" MinWidth="40" HorizontalAlignment="Left" Validation.ErrorTemplate="{StaticResource errorTemplate}">
    <TextBox.Text>
        <Binding x:Name="NumItemsBinding" Path="NumItems" NotifyOnSourceUpdated="True" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <cal:UIntValidationRule x:Name="NumItemsValidationRule" MinValue="1" MaxValue="99999" IsEnabled="False"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

验证背后的示例代码:

/// <summary>
/// Clears all validation errors
/// </summary>
void ClearAllValidationErrors()
{
    Validation.ClearInvalid(TBNumItems.GetBindingExpression(TextBox.TextProperty));
}


/// <summary>
///  Revalidates everything
/// </summary>
void RevalidateAll()
{
    ClearAllValidationErrors();

    TBNumItems.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}

答案 1 :(得分:1)

使您的数据对象实现IDataErrorInfo,它将在用户更改属性时对属性执行验证检查,然后使用以下样式将红色边框应用于具有验证错误的控件:

<!-- ValidatingControl Style -->
<Style TargetType="{x:Type FrameworkElement}" x:Key="ValidatingControl">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding 
                Path=(Validation.Errors)[0].ErrorContent, 
                RelativeSource={x:Static RelativeSource.Self}}" />
        </Trigger>
    </Style.Triggers>
</Style>

这将

  1. 仅在该属性发生更改时对单个属性执行验证检查
  2. 仅(并始终)在绑定到无效属性的控件上显示红色验证错误边框
  3. 修改

    以下是我将如何在对象上实现验证的示例:

    public class MyObject : ValidatingObject
    {
        public MyObject()
        {
            // Add Properties to Validate here
            this.ValidatedProperties.Add("SomeNumber");
        }
    
        // Implement validation rules here
        public override string GetValidationError(string propertyName)
        {
            if (ValidatedProperties.IndexOf(propertyName) < 0)
            {
                return null;
            }
    
            string s = null;
    
            switch (propertyName)
            {
                case "SomeNumber":
                    if (SomeNumber <= 0)
                        s = "SomeNumber must be greater than 0";
                    break;
            }
    
            return s;
        }
    
    }
    

    实现ValidatingObject的{​​{1}}基类通常包含以下内容:

    IDataErrorInfo

答案 2 :(得分:0)

我遇到了同样的问题。我想让控件知道是否需要它们,并自动向托管窗口报告任何更改。我不想编写复杂的XAML或其他代码,只需放置控件并设置属性以指示是否需要用户输入即可。然后,控件会自动搜索主机窗口,并在用户键入所需数据或将其删除时通知主机窗口,以便该窗口可以更改“保存”按钮的状态。最终的解决方案如下所示:

<wwl:CheckedWindow x:Class="Samples.SampleWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wwl="clr-namespace:WpfWindowsLib;assembly=WpfWindowsLib">
  <StackPanel>
    <wwl:CheckedTextBox x:Name="TestCheckedTextBox" MinWidth="100" MaxLength="20" IsRequired="True"/>
    <Button x:Name="SaveButton" Content="_Save"/>
  </StackPanel>
</wwl:CheckedWindow>

要使其正常工作,应将它添加到最常用的WPF控件IChecker中,该控件执行以下操作:

  • 知道数据何时更改
  • 了解数据何时保持不变(用户撤消了更改)
  • 知道何时“必需”控件缺少数据
  • 知道“必需”控件何时具有数据
  • 自动查找控件所在的窗口,并通知窗口有关每个状态更改的信息

如果任何控件通知窗口该控件的状态已更改,则该窗口会自动查询所有其他控件的状态。如果所有必需的控件都有数据,则会启用“保存”按钮。

知道用户已更改某些数据时,当用户尝试不保存就关闭窗口时,这很有用。然后,他会自动获得警告,并选择是否要保存或丢弃数据。

我不得不写太多的代码才能在此处发布,但是现在生活很轻松。只需将控件放到XAML中,然后在窗口中为“保存”按钮添加几行代码即可,仅此而已。以下是详细说明:https://www.codeproject.com/Articles/5257393/Base-WPF-Window-functionality-for-data-entry 该代码位于GitHub:https://github.com/PeterHuberSg/WpfWindowsLib