我有一个带有几个文本字段的窗口和一个确定和取消按钮。当我单击“确定”时,它需要验证我的字段并在它们有效时执行它们并显示错误消息(如果它们不存在。)
在我的ViewModel中,我有
public ICommand OKCommand { get; private set; }
public Action ErrorAction { get; set; }
OKCommand = new BaseCommand(_ =>
{
if (string.IsNullOrEmpty(ErrorMessage))
{
// Do stuff with the contents of the fields
...
}
else ErrorAction();
});
public string ErrorMessage
{
get
{
// Gets the error message for the fields
...
}
}
在我的代码背后,我有
if (ViewModel.ErrorAction == null) ViewModel.ErrorAction = new Action(() => MessageDialog.ShowError(ViewModel.ErrorMessage));
我的问题是ErrorMessage
在出现错误时被调用两次,首先是OKCommand
,再次是ErrorAction
。
我能想到的唯一解决方案是
OKCommand
中是否存在错误,并在适当时设置ErrorMessage
像这样的东西
private bool HasError
{
get
{
// Do the same as ErrorMessage but populate ErrorMessage and return a bool
...
}
}
OKCommand = new BaseCommand(_ =>
{
if (!HasError)
{
// Do stuff with the contents of the fields
...
}
else ErrorAction();
});
虽然两种方法都工作,但我认为两者都不是很好 - 第一次有第二次调用,第二次增加了一个间接级别。还有其他选择吗?
答案 0 :(得分:0)
有一种验证TextBox文本的简单方法:
它叫做 ValidationRule
You can directly see that there is an error(Error in MouseOverMessage) and the Button is disabled
<Window x:Class="TestWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestWpf"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MyValidatorProperties x:Key="properties"/>
<local:MyCustomValidationRule x:Key="validator" />
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="2" />
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<ControlTemplate x:Key="validationTemplate">
<DockPanel>
<TextBlock Foreground="Red" FontSize="17">!</TextBlock>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
</Window.Resources>
<Grid>
<TextBox x:Name="tbName" Height="23" Validation.ErrorTemplate="{StaticResource validationTemplate}" Style="{StaticResource textBoxInError}" Margin="10,10,349,286">
<TextBox.Text>
<Binding Path="myName" Source="{StaticResource properties}"
UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<local:MyCustomValidationRule Type="myName" ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Button x:Name="btnCreate" Content="Create" Width="58" Height="23" Margin="174,10,285,286" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=tbRepositoryName}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</Window>
代码背后:
ValidatiorClass:
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Controls;
namespace TestWpf
{
class MyCustomValidationRule : ValidationRule
{
public string Type { get; set; }
public override ValidationResult Validate(object p_value, CultureInfo p_cultureInfo)
{
switch (Type)
{
case "myName":
string a_strValue = p_value as string;
if (!string.IsNullOrEmpty(a_strValue))
{
Match a_match = Regex.Match((string)p_value, @"^[a-zA-Z\d]+$");
return a_match.Success ? new ValidationResult(true, "Name is valid!") : new ValidationResult(false, $"Input should be a Valid Name (a-z, A-Z, 0-9)");
}
return new ValidationResult(false, "Empty name!");
default:
return new ValidationResult(false, $"UnkownValidation Parameter: " + Type);
}
}
}
}
绑定到TextBox的属性:
using System.ComponentModel;
namespace TestWpf
{
class MyValidatorProperties : INotifyPropertyChanged
{
private string m_myName = "";
public string myName
{
get
{
return m_myName;
}
set
{
if (m_myName != value)
{
m_myName = value;
OnPropertyChanged("myName");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string info)
{
PropertyChanged?.Invoke(null, new PropertyChangedEventArgs(info));
}
}
}
<强> PS:强> 如果您不想禁用Button并显示消息,则可以将Button替换为:
<Button x:Name="btnCreate" Content="Create" Width="58" Height="23" Click="btnCreate_Click" />
并添加方法:
private void btnCreate_Click(object sender, RoutedEventArgs e)
{
if(System.Windows.Controls.Validation.GetHasError(tbName))
{
//Show Message
}
}
答案 1 :(得分:0)
最后我决定,鉴于没有任何选项明显优于我目前的解决方案,我会坚持这一点。
为了将来参考,此article描述了数据验证的替代方法。但是,不幸的是,我的要求意味着这对我来说不是一个简单的选择。