【问题标题】:Multiple field validator in WPF search formWPF 搜索表单中的多字段验证器
【发布时间】:2011-05-16 13:29:37
【问题描述】:

我有一个相当简单的视图,它用作搜索表单。有两个组合框和一个带有“搜索”按钮的文本框。如果下拉列表中没有选择或文本框为空,则无法执行搜索。我在我的应用程序的几个地方使用了 IDataErrorInfo,但它似乎不适合这里(我没有“SearchPageModel”,我不确定如何在视图模型上实现它),并且由于完全缺乏验证器控件,我不知道该怎么做。如果用户尝试搜索而之前没有这样做,我只想显示一条有关填写所有信息的消息。最简单的方法是什么?

更新: 按照第一个答案的链接中的建议,我创建了一个验证规则并将我的文本框修改为如下所示:

    <TextBox Grid.Column="1" Grid.Row="3" Name="tbxPartNumber" Margin="6">
        <TextBox.Text>
            <Binding Path="SelectedPartNumber" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <local:RequiredTextValidation/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

但是,这里有一个新问题:当我转到屏幕并在文本框中输入内容,然后将其删除时,该框以红色突出显示,正如预期的那样。 Validation.GetHasErrors(tbxPartNumber) 返回真。如果我转到屏幕并且根本不与文本框交互,则 Validation.GetHasErrors(tbxPartNumber) 返回 false。它似乎只在我修改文本时才有效......它不会验证用户是否只是出现并点击搜索而不输入任何内容。有没有办法解决这个问题?

【问题讨论】:

  • 更新了我的答案以尝试解决这个问题。

标签: wpf validation mvvm requiredfieldvalidator


【解决方案1】:

article on MSDN 提供了一个很好的示例,说明如何验证此类内容,请查看相应的小节(“验证用户提供的数据”)。关键是使用ValidationRules 并检查对话框的整个逻辑树是否有错误。

编辑: 在 ValidationRule 上设置 ValidatesOnTargetUpdated="True" 应该可以解决问题。事实上,该属性的 MSDN 文档中的示例正是这种情况。进一步this answer 可能对这种情况感兴趣。

Edit2:这是导致验证失败的完整代码:

<Window x:Class="Test.Dialogs.SearchDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:diag="clr-namespace:Test.Dialogs"
        xmlns:m="clr-namespace:HB.Xaml"
        Title="Search" SizeToContent="WidthAndHeight" ResizeMode="NoResize"
        Name="Window" DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.Resources>
            <Style x:Key="BaseStyle" TargetType="{x:Type FrameworkElement}">
                <Setter Property="Margin" Value="3"/>
                <Setter Property="VerticalAlignment" Value="Center"/>
            </Style>
            <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseStyle}"/>
            <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource BaseStyle}"/>
            <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}"/>
            <Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}"/>
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.Children>
            <TextBlock Grid.Column="0" Grid.Row="0" Text="Scope:"/>
            <ComboBox Grid.Column="1" Grid.Row="0" ItemsSource="{m:EnumItems {x:Type diag:SearchDialog+ScopeMode}}">
                <ComboBox.SelectedItem>
                    <Binding Path="Scope">
                        <Binding.ValidationRules>
                            <diag:HasSelectionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </ComboBox.SelectedItem>
            </ComboBox>

            <TextBlock Grid.Column="0" Grid.Row="1" Text="Direction:"/>
            <ComboBox Grid.Column="1" Grid.Row="1" ItemsSource="{m:EnumItems {x:Type diag:SearchDialog+DirectionMode}}">
                <ComboBox.SelectedItem>
                    <Binding Path="Direction">
                        <Binding.ValidationRules>
                            <diag:HasSelectionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </ComboBox.SelectedItem>
            </ComboBox>


            <TextBlock Grid.Column="0" Grid.Row="2" Text="Expression:"/>
            <TextBox Name="tb" Grid.Column="1" Grid.Row="2">
                <TextBox.Text>
                    <Binding Path="Expression" UpdateSourceTrigger="PropertyChanged">
                        <Binding.ValidationRules>
                            <diag:StringNotEmptyValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>

            <Button Grid.Column="1" Grid.Row="3" Content="Search" Click="Search_Click"/> 
        </Grid.Children>
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Test.Dialogs
{
    /// <summary>
    /// Interaction logic for SearchDialog.xaml
    /// </summary>
    public partial class SearchDialog : Window
    {
        public enum ScopeMode { Selection, Document, Solution }
        public enum DirectionMode { Up, Down }

        public ScopeMode Scope { get; set; }
        public DirectionMode Direction { get; set; }
        private string _expression = String.Empty;
        public string Expression
        {
            get { return _expression; }
            set { _expression = value; }
        }


        public SearchDialog()
        {
            InitializeComponent();
        }

        private void Search_Click(object sender, RoutedEventArgs e)
        {
            (sender as Button).Focus();
            if (IsValid(this)) MessageBox.Show("<Searching>");
            else MessageBox.Show("Errors!");
        }

        bool IsValid(DependencyObject node)
        {
            if (node != null)
            {
                bool isValid = Validation.GetHasError(node);
                if (!isValid)
                {
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }
            return true;
        }
    }

    public class HasSelectionValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            if (value == null)
            {
                return new ValidationResult(false, "An item needs to be selected.");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
    }

    public class StringNotEmptyValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            if (String.IsNullOrWhiteSpace(value as string))
            {
                return new ValidationResult(false, "The search expression is empty.");
            }
            else
            {
                return new ValidationResult(true, null);
            }
        }
    }
}

【讨论】:

  • 嗯,这确实会导致它在屏幕加载时进行验证,因此搜索按钮单击可以正常工作,但现在的问题是数据错误模板在屏幕加载时可见,在用户之前什么都做。我想我可以手动清除错误...
  • 当我在没有此设置的情况下对其进行测试时,它实际上不会验证,不确定为什么它会在您的情况下通过。
  • 您是否在单击按钮时导致验证错误?你能粘贴你的测试代码吗?
  • 添加了我的代码,由于某种原因,窗口本身有验证错误,不确定它们是否来自文本框,但如果你删除组合框的东西,它仍然有错误。
猜你喜欢
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-29
  • 2020-03-10
  • 1970-01-01
相关资源
最近更新 更多