我有一个简单的 WPF 对话框,允许用户输入名称。我们正在使用没有任何代码隐藏文件的 Mvvm 方法。我需要验证输入,并且只有在输入有效时才启用 OK 按钮。我目前正在使用 View 中的自定义错误模板和 ValidationRule 类的自定义实现进行验证。
对话框中的文本框定义为:
<TextBox Width="250" Height="25" Margin="5"
Validation.ErrorTemplate="{StaticResource customErrorTemplate}">
<TextBox.Text>
<Binding Path="WitnessName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ValidationRules:NameRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
NameRule 定义为:
public class NameRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var isValid = (value as string == null) || Regex.IsMatch(value.ToString(), @"^[\p{L} \.'\-]+$");
return new ValidationResult(isValid, "Name can contain only letters, apostrophes and hyphens.");
}
}
OK 按钮 IsEnabled 属性绑定(bind)到 View 模型上的 IsOkEnabled 属性,仅当输入有效时才为 true。
<Button Name="OnOkClick" Margin="5" IsEnabled="{Binding IsOkEnabled}">OK</Button>
通过监视 WitnessName PropertyChanged 事件来更新 IsOkEnabled 属性以响应 WitnessName 文本中的更改。
public string WitnessName
{
get
{
return this.witnessName;
}
set
{
this.witnessName = value;
this.NotifyOfPropertyChange(() => this.IsOkEnabled);
}
}
问题在于,在 View 中进行验证时,当输入无效输入时,不会在 vew 模型上触发 PropertyChanged 事件,因此不会更新 IsOkEnabled 属性并且“确定”按钮保持启用状态。
有没有办法强制更新 IsOkEnabled 属性以响应我当前实现中甚至无效的输入?
我都看过Karl Shifflet's和 Josh Smith's建议,但都没有使用(据我所知) View 错误模板,我想用一个来提供视觉反馈。
更新:按照 Danny 的建议使用绑定(bind)的 ICommand 尝试此操作
我已经通过创建一个特定于 OK 按钮的 VM 来尝试这个,它实现了 ICommand。 OkButtonViewModel 具有保存对话 VM 的属性(由 IoC 和 unity 设置),并且 CanExecute 和 Execute 实现引用此 VM 上的相关属性/方法。
在 OkButtonViewModel 中:
public bool CanExecute(object parameter)
{
return this.witnessDialogue.IsValid;
}
public void Execute(object parameter)
{
this.witnessDialogue.OnOkClick();
}
如何将我的按钮绑定(bind)到这个虚拟机而不是对话虚拟机?如果 OkButtonViewModel 是对话 VM 上的属性,我可以做到这一点,但当依赖关系相反时,我可以做到这一点,它需要按钮才能使用对话 VM 上的实现。
最佳答案
摆脱 OnClick 事件处理程序,而是使用对命令的绑定(bind)。
使用返回 Model.IsValid 的 CanExecute 方法在 VM 中注册命令。
如果验证失败是在 View 与 View 模型的绑定(bind)中,
那么 View 模型仍然有效 - 因为它没有存储更新(由于类型不匹配、范围检查等)。
在这种情况下,请考虑在抛出异常之前将错误状态存储在 VM 中,然后在成功设置相同属性时清除错误状态。
修改后的代码:
XAML:
(注意 ValidationRules:NameRule 实例的作用域是在 TextBox 中,其他用法会收到另一个不同字段值的实例)
<TextBox Width="250" Height="25" Margin="5"
Validation.ErrorTemplate="{StaticResource customErrorTemplate}">
<TextBox.Text>
<Binding Path="WitnessName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ValidationRules:NameRule x:Name="nameValidator" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
验证规则:
public class NameRule : ValidationRule, INotifyPropertyChanged
{
public bool HasFailed // set default of field behind to false
{
get; // change to support INotifyPropertyChanged
set; // change to support INotifyPropertyChanged
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var isValid = (value as string == null) || Regex.IsMatch(value.ToString(), @"^[\p{L} \.'\-]+$");
HasFailed = !isValid;
return new ValidationResult(isValid, "Name can contain only letters, apostrophes and hyphens.");
}
}
命令:
public bool CanExecute(object parameter)
{
return this.witnessDialogue.IsValid && !this.witnessDialogue.nameValidator.HasFailed;
}
public void Execute(object parameter)
{
this.witnessDialogue.OnOkClick();
}
关于wpf - 如何禁用 WPF 对话框确定按钮以响应自定义 ValidationRule 类确定的无效输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4783082/