结合Validation.HasError财产MVVM [英] Binding Validation.HasError property in MVVM

查看:366
本文介绍了结合Validation.HasError财产MVVM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在实施有效性规则来检查是否存在无效的字符在文本框。我很高兴,设置我已经实现了类继承有效性规则在我的文本框将其设置为红色时,发现这样的人物,但我也想使用 Validation.HasError 属性或属性Validation.Errors弹出一个消息框,告诉有在页面中的文本框的各种错误的用户。

有一个属性在我的视图模型 Validation.HasError 和/或到Validation.Errors性质为了让我在我的视图模型对它们的访问?

下面是对TextBox我的错误方式:

 <风格X:键=ErrorValidationTextBox的TargetType ={X:类型$ P ​​$ PS:OneTextBox}>
    < setter属性=Validation.ErrorTemplate>
        < Setter.Value>
            <&控件模板GT;
                < D​​ockPanel中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 =顶部
                 的Horizo​​ntalAlignment =左WIDTH =300>
    < preS:OneTextBox.Text>
        <绑定路径=InterfaceSpecification.NameUpdateSourceTrigger =的PropertyChanged>
            < Binding.ValidationRules>
                < interfaceSpecsModule:NoInvalidCharsRule />
            < /Binding.ValidationRules>
        < /装订>
    < / preS:OneTextBox.Text>
< / preS:OneTextBox>


解决方案

Validation.HasError 只读的属性,因此绑定​​不会与这个属性的工作。这可以在 ILSpy 中可以看出

 公共虚拟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#,原来的语言是 VB.NET

XAML

 &LT;窗​​口x:类=HasErrorTestValidation.MainWindow
        的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
        的xmlns:X =htt​​p://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风格你可以尝试实施<一个href=\"http://msdn.microsoft.com/en-us/library/system.componentmodel.idataerrorinfo.aspx\"><$c$c>IDataErrorInfo接口。欲了解更多信息请参阅本:

强制使用WPF复杂的业务数据规则

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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆