问题描述
我目前正在实施有效性规则
来检查是否存在无效的字符在文本框。我很高兴,设置我已经实现了类继承有效性规则
在我的文本框将其设置为红色时,发现这样的人物,但我也想使用 Validation.HasError
属性或属性Validation.Errors弹出一个消息框,告诉有在页面中的文本框的各种错误的用户。
有一个属性在我的视图模型
到 Validation.HasError
绑定的方式EM>和/或到Validation.Errors性质为了让我在我的视图模型对它们的访问?
下面是对TextBox我的错误方式:
<风格X:键=ErrorValidationTextBox的TargetType ={X:类型$ P $ PS:OneTextBox}>
< setter属性=Validation.ErrorTemplate>
< Setter.Value>
<&控件模板GT;
< DockPanel中LastChildFill =真>
< TextBlock的DockPanel.Dock =右
前景=红
字号=12磅
文本={绑定的ElementName = MyAdorner,
路径= AdornedElement(Validation.Errors)[0] .ErrorContent}过夜。;
< / TextBlock的>
< AdornedElementPlaceholder X:NAME =MyAdorner/>
< / DockPanel中>
< /控件模板>
< /Setter.Value>
< /二传手>
< /样式和GT;
下面是我声明我的文本框(OneTextBox封装常规WPF的TextBox)在我的XAML:
< preS:OneTextBox水印=姓名......保证金=85,12,0,0风格={StaticResource的ErrorValidationTextBox}
AcceptsReturn =FALSEMAXLINES =1HEIGHT =22VerticalAlignment =顶部
的HorizontalAlignment =左WIDTH =300>
< preS:OneTextBox.Text>
<绑定路径=InterfaceSpecification.NameUpdateSourceTrigger =的PropertyChanged>
< Binding.ValidationRules>
< interfaceSpecsModule:NoInvalidCharsRule />
< /Binding.ValidationRules>
< /装订>
< / preS:OneTextBox.Text>
< / preS:OneTextBox>
的 Validation.HasError
是只读的属性,因此绑定
不会与这个属性的工作。这可以在:
公共虚拟BOOL HasError
{
得到
{
返回this._validationError!= NULL;
}
}
作为一种替代方法,你应该看到一个伟大的<一个href=\"http://wpfglue.word$p$pss.com/2009/12/03/forwarding-the-result-of-wpf-validation-in-mvvm/\"><$c$c>article$c$c>它提供了在使用的形式解决方案的连接的依赖属性,在那里你会看到示例的详细说明。
下面是这篇文章的完整的例子,我只是把它翻译下 C#
,原来的语言是 VB.NET
:
XAML
&LT;窗口x:类=HasErrorTestValidation.MainWindow
的xmlns =http://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
XMLNS:地方=CLR的命名空间:HasErrorTestValidation
WindowStartupLocation =中心屏幕
标题=主窗口HEIGHT =350WIDTH =525&GT; &LT; Window.DataContext&GT;
&lt;局部:TESTDATA /&GT;
&LT; /Window.DataContext> &LT;&StackPanel的GT;
&LT;文本框X:NAME =TestTextBox
本地:ProtocolSettingsLayout.MVVMHasError ={绑定路径= HasError}&GT;
&LT; TextBox.Text&GT;
&LT;绑定路径=TestTextUpdateSourceTrigger =的PropertyChanged&GT;
&LT; Binding.ValidationRules&GT;
&lt;局部:OnlyNumbersValidationRule ValidatesOnTargetUpdated =真/&GT;
&LT; /Binding.ValidationRules>
&LT; /装订&GT;
&LT; /TextBox.Text>
&LT; /文本框&GT; &LT;&的TextBlock GT;
&LT; TextBlock.Text&GT;
&LT;绑定路径=HasError的StringFormat =HasError是{0}/&GT;
&LT; /TextBlock.Text>
&LT; / TextBlock的&GT; &LT;&的TextBlock GT;
&LT; TextBlock.Text&GT;
&LT;绑定路径=(Validation.HasError)的ElementName =TestTextBox的StringFormat =Validation.HasError是{0}/&GT;
&LT; /TextBlock.Text>
&LT; / TextBlock的&GT;
&LT; / StackPanel的&GT;
&LT; /窗GT;
code-背后
公共部分类主窗口:窗口
{
公共主窗口()
{
的InitializeComponent();
}
}#区域模式公共类TESTDATA:INotifyPropertyChanged的
{
私人布尔_hasError = FALSE; 公共BOOL HasError
{
得到
{
返回_hasError;
} 组
{
_hasError =价值;
NotifyPropertyChanged(HasError);
}
} 私人字符串_testText =0; 公共字符串TestText
{
得到
{
返回_testText;
} 组
{
_testText =价值;
NotifyPropertyChanged(TestText);
}
} #区域的PropertyChanged 公共事件PropertyChangedEventHandler的PropertyChanged; 保护无效NotifyPropertyChanged(字符串sProp)
{
如果(的PropertyChanged!= NULL)
{
的PropertyChanged(这一点,新PropertyChangedEventArgs(sProp));
}
} #endregion
}#endregion#区域有效性规则公共类OnlyNumbersValidationRule:有效性规则
{
公众覆盖的ValidationResult验证(对象的值,CultureInfo的CultureInfo的)
{
VAR的结果=新的ValidationResult(TRUE,NULL); 字符串NumberPattern = @^ [0-9 - ] + $;
正则表达式RGX =新的正则表达式(NumberPattern); 如果(rgx.IsMatch(value.ToString())== FALSE)
{
结果=新的ValidationResult(假的,必须是唯一的编号);
} 返回结果;
}
}#endregion公共类ProtocolSettingsLayout
{
公共静态只读的DependencyProperty MVVMHasErrorProperty = DependencyProperty.RegisterAttached(MVVMHasError
typeof运算(布尔)
typeof运算(ProtocolSettingsLayout)
新FrameworkPropertyMetadata(假的,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
空值,
CoerceMVVMHasError)); 公共静态布尔GetMVVMHasError(DependencyObject的D)
{
返回(布尔)d.GetValue(MVVMHasErrorProperty);
} 公共静态无效SetMVVMHasError(DependencyObject的D,布尔值)
{
d.SetValue(MVVMHasErrorProperty,值);
} 私有静态对象CoerceMVVMHasError(DependencyObject的D,对象baseValue)
{
布尔RET =(布尔)baseValue; 如果(BindingOperations.IsDataBound(D,MVVMHasErrorProperty))
{
如果(GetHasErrorDescriptor(四)== NULL)
{
DependencyPropertyDescriptor DESC = DependencyPropertyDescriptor.FromProperty(Validation.HasErrorProperty,d.GetType());
desc.AddValueChanged(D,OnHasErrorChanged);
SetHasErrorDescriptor(D,DESC);
RET = System.Windows.Controls.Validation.GetHasError(D);
}
}
其他
{
如果(GetHasErrorDescriptor(D)!= NULL)
{
DependencyPropertyDescriptor DESC = GetHasErrorDescriptor(D);
desc.RemoveValueChanged(D,OnHasErrorChanged);
SetHasErrorDescriptor(D,NULL);
}
} 返回RET;
} 私人静态只读的DependencyProperty HasErrorDescriptorProperty = DependencyProperty.RegisterAttached(HasErrorDescriptor
typeof运算(DependencyPropertyDescriptor)
typeof运算(ProtocolSettingsLayout)); 私有静态DependencyPropertyDescriptor GetHasErrorDescriptor(DependencyObject的D)
{
VAR RET = d.GetValue(HasErrorDescriptorProperty);
返回RET为DependencyPropertyDescriptor;
} 私有静态无效OnHasErrorChanged(对象发件人,EventArgs的发送)
{
DependencyObject的D =发件人为DependencyObject的; 如果(D!= NULL)
{
d.SetValue(MVVMHasErrorProperty,d.GetValue(Validation.HasErrorProperty));
}
} 私有静态无效SetHasErrorDescriptor(DependencyObject的D,DependencyPropertyDescriptor值)
{
VAR RET = d.GetValue(HasErrorDescriptorProperty);
d.SetValue(HasErrorDescriptorProperty,值);
}
}
作为替代使用有效性规则
的,在MVVM风格你可以尝试实施<$c$c>IDataErrorInfo$c$c>接口。欲了解更多信息请参阅本:
I am currently implementing a ValidationRule
to check if some invalid character are in a TextBox. I am happy that setting the class I have implemented that inherits ValidationRule
on my TextBox sets it in red when such characters are found, but I would also like to use the Validation.HasError
property or the Validation.Errors property to pop a messagebox telling the user that there are errors in the various textboxes in the page.
Is there a way to bind a property in my ViewModel
to the Validation.HasError
and/or to the Validation.Errors properties in order for me to have access to them in my ViewModel?
Here is my error style for the TextBox:
<Style x:Key="ErrorValidationTextBox" TargetType="{x:Type pres:OneTextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Red"
FontSize="12pt"
Text="{Binding ElementName=MyAdorner,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
</TextBlock>
<AdornedElementPlaceholder x:Name="MyAdorner"/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is how I declare my TextBox (OneTextBox encapsulates the regular WPF TextBox) in my XAML:
<pres:OneTextBox Watermark="Name..." Margin="85,12,0,0" Style="{StaticResource ErrorValidationTextBox}"
AcceptsReturn="False" MaxLines="1" Height="22" VerticalAlignment="Top"
HorizontalAlignment="Left" Width="300" >
<pres:OneTextBox.Text>
<Binding Path="InterfaceSpecification.Name" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<interfaceSpecsModule:NoInvalidCharsRule/>
</Binding.ValidationRules>
</Binding>
</pres:OneTextBox.Text>
</pres:OneTextBox>
The Validation.HasError
is readonly property, therefore Binding
will not work with this property. This can be seen in ILSpy
:
public virtual bool HasError
{
get
{
return this._validationError != null;
}
}
As an alternative, you should see a great article
which provides a solution in the form of use attached dependency properties, there you will see a detailed explanation of the example.
Below is a full example from this article, I just translated it under C#
, the original language is VB.NET
:
XAML
<Window x:Class="HasErrorTestValidation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:HasErrorTestValidation"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:TestData />
</Window.DataContext>
<StackPanel>
<TextBox x:Name="TestTextBox"
local:ProtocolSettingsLayout.MVVMHasError="{Binding Path=HasError}">
<TextBox.Text>
<Binding Path="TestText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:OnlyNumbersValidationRule ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock>
<TextBlock.Text>
<Binding Path="HasError" StringFormat="HasError is {0}"/>
</TextBlock.Text>
</TextBlock>
<TextBlock>
<TextBlock.Text>
<Binding Path="(Validation.HasError)" ElementName="TestTextBox" StringFormat="Validation.HasError is {0}"/>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
#region Model
public class TestData : INotifyPropertyChanged
{
private bool _hasError = false;
public bool HasError
{
get
{
return _hasError;
}
set
{
_hasError = value;
NotifyPropertyChanged("HasError");
}
}
private string _testText = "0";
public string TestText
{
get
{
return _testText;
}
set
{
_testText = value;
NotifyPropertyChanged("TestText");
}
}
#region PropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string sProp)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(sProp));
}
}
#endregion
}
#endregion
#region ValidationRule
public class OnlyNumbersValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var result = new ValidationResult(true, null);
string NumberPattern = @"^[0-9-]+$";
Regex rgx = new Regex(NumberPattern);
if (rgx.IsMatch(value.ToString()) == false)
{
result = new ValidationResult(false, "Must be only numbers");
}
return result;
}
}
#endregion
public class ProtocolSettingsLayout
{
public static readonly DependencyProperty MVVMHasErrorProperty= DependencyProperty.RegisterAttached("MVVMHasError",
typeof(bool),
typeof(ProtocolSettingsLayout),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
null,
CoerceMVVMHasError));
public static bool GetMVVMHasError(DependencyObject d)
{
return (bool)d.GetValue(MVVMHasErrorProperty);
}
public static void SetMVVMHasError(DependencyObject d, bool value)
{
d.SetValue(MVVMHasErrorProperty, value);
}
private static object CoerceMVVMHasError(DependencyObject d,Object baseValue)
{
bool ret = (bool)baseValue;
if (BindingOperations.IsDataBound(d,MVVMHasErrorProperty))
{
if (GetHasErrorDescriptor(d)==null)
{
DependencyPropertyDescriptor desc = DependencyPropertyDescriptor.FromProperty(Validation.HasErrorProperty, d.GetType());
desc.AddValueChanged(d,OnHasErrorChanged);
SetHasErrorDescriptor(d, desc);
ret = System.Windows.Controls.Validation.GetHasError(d);
}
}
else
{
if (GetHasErrorDescriptor(d)!=null)
{
DependencyPropertyDescriptor desc= GetHasErrorDescriptor(d);
desc.RemoveValueChanged(d, OnHasErrorChanged);
SetHasErrorDescriptor(d, null);
}
}
return ret;
}
private static readonly DependencyProperty HasErrorDescriptorProperty = DependencyProperty.RegisterAttached("HasErrorDescriptor",
typeof(DependencyPropertyDescriptor),
typeof(ProtocolSettingsLayout));
private static DependencyPropertyDescriptor GetHasErrorDescriptor(DependencyObject d)
{
var ret = d.GetValue(HasErrorDescriptorProperty);
return ret as DependencyPropertyDescriptor;
}
private static void OnHasErrorChanged(object sender, EventArgs e)
{
DependencyObject d = sender as DependencyObject;
if (d != null)
{
d.SetValue(MVVMHasErrorProperty, d.GetValue(Validation.HasErrorProperty));
}
}
private static void SetHasErrorDescriptor(DependencyObject d, DependencyPropertyDescriptor value)
{
var ret = d.GetValue(HasErrorDescriptorProperty);
d.SetValue(HasErrorDescriptorProperty, value);
}
}
As an alternative to the use of ValidationRule
, in MVVM style you can try to implement IDataErrorInfo
Interface. For more info see this:
Enforcing Complex Business Data Rules with WPF
这篇关于结合Validation.HasError财产MVVM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!