使用 WPF 验证规则和禁用“保存”按钮
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/231052/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using WPF Validation rules and the disabling of a 'Save' button
提问by ScottG
I have a page where a few textboxes cannot be empty before clicking a Save button.
我有一个页面,在单击“保存”按钮之前,其中一些文本框不能为空。
<TextBox...
<TextBox.Text>
<Binding Path ="LastName" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:StringRequiredValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
My rule works, I have a red border around my textbox until I enter a value. I now want to add this validation rule to my other text boxes.
我的规则有效,我的文本框周围有一个红色边框,直到我输入一个值。我现在想将此验证规则添加到我的其他文本框中。
How do I disable the Save button until the page has no validation errors? I'm not sure what to check.
在页面没有验证错误之前,如何禁用“保存”按钮?我不确定要检查什么。
采纳答案by Developer
Here is the complete sample what you need.
这是您需要的完整示例。
http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/
http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/
https://skydrive.live.com/?cid=2c6600f1c1d5e3be&id=2C6600F1C1D5E3BE%21203
https://skydrive.live.com/?cid=2c6600f1c1d5e3be&id=2C6600F1C1D5E3BE%21203
回答by Christoph
On the codebehind for the view you could wireup the Validation.ErrorEvent like so;
在视图的代码隐藏中,您可以像这样连接 Validation.ErrorEvent;
this.AddHandler(Validation.ErrorEvent,new RoutedEventHandler(OnErrorEvent));
And then
进而
private int errorCount;
private void OnErrorEvent(object sender, RoutedEventArgs e)
{
var validationEventArgs = e as ValidationErrorEventArgs;
if (validationEventArgs == null)
throw new Exception("Unexpected event args");
switch(validationEventArgs.Action)
{
case ValidationErrorEventAction.Added:
{
errorCount++; break;
}
case ValidationErrorEventAction.Removed:
{
errorCount--; break;
}
default:
{
throw new Exception("Unknown action");
}
}
Save.IsEnabled = errorCount == 0;
}
This makes the assumption that you will get notified of the removal (which won't happen if you remove the offending element while it is invalid).
这假设您将收到删除通知(如果您在无效元素时删除违规元素,则不会发生这种情况)。
回答by Todd White
You want to use Validation.HasErrorattached property.
您想使用Validation.HasError附加属性。
Along the same lines Josh Smith has an interesting read on Binding to (Validation.Errors)[0] without Creating Debug Spew.
同样,Josh Smith 对Binding to (Validation.Errors)[0] without Creating Debug Spew有一个有趣的阅读。
回答by Nihal
int count = 0;
private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added)
{
button1.IsEnabled = false;
count++;
}
if (e.Action == ValidationErrorEventAction.Removed)
{
count--;
if (count == 0) button1.IsEnabled = true;
}
}
回答by andrey.tsykunov
Here is a helper method which tracks validation errors on the dependency objects (and all its children) and calls delegate to notify about the change. It also tracks removal of the children with validation errors.
这是一个辅助方法,它跟踪依赖对象(及其所有子对象)上的验证错误并调用委托来通知更改。它还跟踪删除具有验证错误的子项。
public static void AddErrorHandler(DependencyObject element, Action<bool> setHasValidationErrors)
{
var errors = new List<Tuple<object, ValidationError>>();
RoutedEventHandler sourceUnloaded = null;
sourceUnloaded = (sender, args) =>
{
if (sender is FrameworkElement)
((FrameworkElement) sender).Unloaded -= sourceUnloaded;
else
((FrameworkContentElement) sender).Unloaded -= sourceUnloaded;
foreach (var error in errors.Where(err => err.Item1 == sender).ToArray())
errors.Remove(error);
setHasValidationErrors(errors.Any());
};
EventHandler<ValidationErrorEventArgs> errorHandler = (_, args) =>
{
if (args.Action == ValidationErrorEventAction.Added)
{
errors.Add(new Tuple<object, ValidationError>(args.OriginalSource, args.Error));
if (args.OriginalSource is FrameworkElement)
((FrameworkElement)args.OriginalSource).Unloaded += sourceUnloaded;
else if (args.OriginalSource is FrameworkContentElement)
((FrameworkContentElement)args.OriginalSource).Unloaded += sourceUnloaded;
}
else
{
var error = errors
.FirstOrDefault(err => err.Item1 == args.OriginalSource && err.Item2 == args.Error);
if (error != null)
errors.Remove(error);
}
setHasValidationErrors(errors.Any());
};
System.Windows.Controls.Validation.AddErrorHandler(element, errorHandler);
}
回答by Bilal
this is it you need to check the HasError control property from the code behaind
这是您需要从代码隐藏中检查 HasError 控件属性
and do this code in the save button click
并在保存按钮中执行此代码单击
BindingExpression bexp = this.TextBox1.GetBindingExpression(TextBox.TextProperty);
bexp.UpdateSource(); // this to refresh the binding and see if any error exist
bool hasError = bexp.HasError; // this is boolean property indique if there is error
MessageBox.Show(hasError.ToString());
回答by Gregor A. Lamche
Because it's still missing, here is an adaption of Developer's answer in case the link ever goes away:
因为它仍然缺失,这里是开发人员答案的改编版,以防链接消失:
XAML:
XAML:
<TextBox.Text Validation.Error="handleValidationError">
<Binding Path ="LastName"
UpdateSourceTrigger="PropertyChanged"
NotifyOnValidationError="True">
<Binding.ValidationRules>
<local:StringRequiredValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
<Button IsEnabled="{Binding HasNoValidationErrors}"/>
CodeBehind/C#:
代码隐藏/C#:
private int _numberOfValidationErrors;
public bool HasNoValidationErrors => _numberOfValidationErrors = 0;
private void handleValidationError(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added)
_numberOfValidationErrors++;
else
_numberOfValidationErrors--;
}
回答by Alexander Sirotkin
just inhert your ViewModel from System.ComponentModel.IDataErrorInfo for Validate and from INotifyPropertyChanged to notify button
只需从 System.ComponentModel.IDataErrorInfo 中为 Validate 和从 INotifyPropertyChanged 到通知按钮中继承您的 ViewModel
make property:
制作属性:
public bool IsValid
{
get
{
if (this.FloorPlanName.IsEmpty())
return false;
return true;
}
}
in xaml, connect it to button
在 xaml 中,将其连接到按钮
<Button Margin="4,0,0,0" Style="{StaticResource McVMStdButton_Ok}" Click="btnDialogOk_Click" IsEnabled="{Binding IsValid}"/>
in the IDataErrorInfo overrides, notify btutton
在 IDataErrorInfo 覆盖中,通知 btutton
public string this[string columnName]{
get
{
switch (columnName)
{
case "FloorPlanName":
if (this.FloorPlanName.IsEmpty())
{
OnPropertyChanged("IsValid");
return "Floor plan name cant be empty";
}
break;
}
}
}
回答by Kabuo
I've tried several of the solutions stated above; however, none of them worked for me.
我已经尝试了上述几种解决方案;然而,他们都没有对我来说有效。
My Simple Problem
我的简单问题
I have a simple input window that request a URI from the user, if the TextBox
value isn't a valid Uri
then the Okay
button should be disabled.
我有一个简单的输入窗口,它向用户请求 URI,如果该TextBox
值无效Uri
,Okay
则应禁用该按钮。
My Simple Solution
我的简单解决方案
Here is what worked for me:
这是对我有用的:
CommandBindings.Add(new CommandBinding(AppCommands.Okay,
(sender, args) => DialogResult = true,
(sender, args) => args.CanExecute = !(bool) _uriTextBoxControl.GetValue(Validation.HasErrorProperty)));
回答by David Shader
This website has the code you're looking for: https://www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf/
这个网站有你要找的代码:https: //www.wpfsharp.com/2012/02/03/how-to-disable-a-button-on-textbox-validationerrors-in-wpf/
For posterity the button code should look like this if you are using a ValidationRule override on the input fields:
对于后代,如果您在输入字段上使用 ValidationRule 覆盖,则按钮代码应如下所示:
<Button Content="<NameThisButton>" Click="<MethodToCallOnClick>" >
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="false" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=<TextBoxName>, Path=(Validation.HasError)}" Value="false" />
<Condition Binding="{Binding ElementName=<TextBoxName>, Path=(Validation.HasError)}" Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="true" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>