我有一个相当简单的视图,它可以作为搜索表单。有两个组合框和一个文本框,带有“搜索”按钮。如果下拉列表中没有选择或文本框为空,则无法执行搜索。我在我的应用程序中的一些地方使用过IDataErrorInfo,但它似乎不适合这里(我没有'SearchPageModel',我不确定如何在viewmodel上实现它),以及完全没有验证器控件,我不知道该怎么做。我只是想显示一条消息,如果用户在没有先前这样做的情况下尝试搜索,则填写所有信息。什么是最简单的方法?
更新: 根据第一个答案的链接中的建议,我创建了一个验证规则并修改了我的文本框,如下所示:
<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。它似乎只有在我修改文本时才有效...它不会验证用户是否只是显示并点击搜索而不键入任何内容。有办法解决这个问题吗?
答案 0 :(得分:2)
这个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);
}
}
}
}