Валидатор нескольких полей в форме поиска WPF - PullRequest
2 голосов
/ 16 мая 2011

У меня довольно простое представление, которое функционирует как форма поиска.Есть два поля со списком и текстовое поле с кнопкой «поиск».Поиск не может быть выполнен, если в выпадающем списке нет выбора или если текстовое поле пусто.Я использовал 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) возвращает значение true.Если я перехожу на экран и вообще не взаимодействую с текстовым полем, Validation.GetHasErrors (tbxPartNumber) возвращает false.Похоже, что он работает только когда я изменяю текст ... он не будет проверяться, если пользователь просто появится и нажмет на поиск, ничего не печатая.Есть ли способ обойти это?

1 Ответ

2 голосов
/ 16 мая 2011

Эта статья на MSDN дает хороший пример того, как проверять подобные вещи, проверьте соответствующий подраздел ( "Проверка предоставленных пользователем данных" ).Ключ использует ValidationRules и проверяет все логическое дерево диалога на наличие ошибок.

Редактировать: Настройка ValidatesOnTargetUpdated="True" на ValidationRule должен решить эту проблему.Фактически, пример в документации MSDN этого свойства - именно этот сценарий.Далее этот ответ может представлять интерес в этом контексте.

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);
            }
        }
    }
}
...