首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将DataContext绑定到ValidationRule

将DataContext绑定到ValidationRule
EN

Stack Overflow用户
提问于 2010-12-03 20:39:31
回答 7查看 7.3K关注 0票数 12

我有一个自定义ValidationRule,它需要访问ViewModel,以便与ViewModel的其他属性一起验证提供的值。我以前试图通过使用ValidationGroup来实现这一点,但放弃了这个想法,因为我正在修改的代码需要进行大量的重构才能启用这个路由。

我找到了一个thread on a newsgroup,它显示了一种将控件的DataContext绑定到该ValidationRule的方法,在该控件中,ValidationRule通过从DependencyObject继承的中间类的方式运行到该ValidationRule,但我无法将其绑定。

有人能帮上忙吗?

我的ValidationRule如下...

代码语言:javascript
复制
class TotalQuantityValidator : CustomValidationRule {

    public TotalQuantityValidator()
        : base(@"The total number must be between 1 and 255.") {
    }

    public TotalQuantityValidatorContext Context { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) {

        ValidationResult validationResult = ValidationResult.ValidResult;

        if (this.Context != null && this.Context.ViewModel != null) {

            int total = ...
            if (total <= 0 || total > 255) {
                validationResult = new ValidationResult(false, this.ErrorMessage);
            }

        }

        return validationResult;

    }

}

CustomValidationRule的定义如下...

代码语言:javascript
复制
public abstract class CustomValidationRule : ValidationRule {

    protected CustomValidationRule(string defaultErrorMessage) {
        this.ErrorMessage = defaultErrorMessage;
    }

    public string ErrorMessage { get; set; }

}

TotalQuantityValidatorContext的定义如下...

代码语言:javascript
复制
public class TotalQuantityValidatorContext : DependencyObject {

    public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(@"ViewModel",
        typeof(MyViewModel), typeof(TotalQuantityValidatorContext),
        new PropertyMetadata {
            DefaultValue = null,
            PropertyChangedCallback = new PropertyChangedCallback(TotalQuantityValidatorContext.ViewModelPropertyChanged)
        });

    public MyViewModel ViewModel {
        get { return (MyViewModel)this.GetValue(TotalQuantityValidatorContext.ViewModelProperty); }
        set { this.SetValue(TotalQuantityValidatorContext.ViewModelProperty, value); }
    }

    private static void ViewModelPropertyChanged(DependencyObject element, DependencyPropertyChangedEventArgs args) {
    }

}

整个东西都是这样用的.

代码语言:javascript
复制
<UserControl x:Class="..."
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:val="clr-namespace:Validators" x:Name="myUserControl">

    <TextBox Name="myTextBox">
        <TextBox.Text>
            <Binding NotifyOnValidationError="True" Path="myViewModelProperty" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <val:TotalQuantityValidator>
                        <val:TotalQuantityValidator.Context>
                            <val:TotalQuantityValidatorContext ViewModel="{Binding ElementName=myUserControl, Path=DataContext}" />
                        </val:TotalQuantityValidator.Context>
                    </val:TotalQuantityValidator>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

</UserControl>

正在将UserControl的DataContext设置为代码隐藏中的MyViewModel实例。我知道此绑定的工作方式与标准控件绑定的运行方式相同。

TotalQuantityValidator.Validate方法被正确调用,但是每当我查看ContextViewModel属性时,它总是空的( TotalQuantityValidatorContext属性被正确地设置为TotalQuantityValidatorContext的一个实例)。但是,我可以从调试器中看到,从未调用过TotalQuantityValidatorContextViewModel属性上的设置器。

有没有人能建议我如何让这个绑定工作?

提前谢谢。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-12-03 21:57:48

我会避免使用验证规则。如果您需要访问视图模型中的信息来执行验证,那么最好将验证逻辑放在视图模型本身中。

您可以让视图模型实现IDataErrorInfo,只需在绑定上打开基于数据错误信息的验证即可。

即使您不会遇到这种(非常常见的)需要上下文信息的问题,验证规则也不是表示验证的好方法:验证规则通常与业务逻辑相关,或者至少与信息的语义方面相关。Xaml似乎不适合放置这些东西--为什么我要在源文件中放置一个主要任务是确定应用程序的布局和可视化设计的业务规则?

验证逻辑在你的应用程序中属于更底层的部分。即使视图模型也可能是错误的层,但在这种情况下,您可以简单地让视图模型负责在哪里找到验证逻辑。

票数 7
EN

Stack Overflow用户

发布于 2010-12-03 23:05:56

我刚刚找到了一个完美的答案!

如果将ValidationRule的ValidationStep属性设置为ValidationStep.UpdatedValue,则传递给Validate方法的值实际上是一个BindingExpression。然后,您可以询问BindingExpression对象的DataItem属性,以获取绑定到的模型。

这意味着我现在可以根据需要验证已分配的值以及其他属性的现有值。

票数 6
EN

Stack Overflow用户

发布于 2010-12-03 21:05:48

您遇到的问题是,您的DataContext是在您创建验证规则后设置的,并且没有通知它已更改。解决此问题的最简单方法是将xaml更改为以下内容:

代码语言:javascript
复制
<TextBox.Text>
    <Binding NotifyOnValidationError="True" Path="myViewModelProperty" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
            <local:TotalQuantityValidator x:Name="validator" />
        </Binding.ValidationRules>
    </Binding>
</TextBox.Text>

然后在设置DataContext后直接设置上下文:

代码语言:javascript
复制
public MainWindow()
{
    InitializeComponent();
    this.DataContext = new MyViewModel();
    this.validator.Context = new TotalQuantityValidatorContext { ViewModel = (MyViewModel)this.DataContext };
}

实际上,您现在可以删除Context类,只在包含ViewModel的ValidationRule上直接拥有一个属性。

编辑

基于您的评论,我现在建议对上面的代码( XAML很好)稍作修改,如下所示:

代码语言:javascript
复制
public MainWindow()
{
    this.DataContextChanged += new DependencyPropertyChangedEventHandler(MainWindow_DataContextChanged);
    InitializeComponent();
}

private void MainWindow_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    this.validator.Context = new TotalQuantityValidatorContext { ViewModel = (MyViewModel)this.DataContext };
}

这将在视图模型更改时更新您的上下文。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4345606

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档