You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中如何将ViewModel数据传入ValidationRule?我的实现为何返回Null?

问题描述

我是C#和WPF编程新手,现有两个TextBox用于用户输入验证:

<TextBox
    x:Name="TextBox1">
    <TextBox.Text>
        <Binding
            NotifyOnValidationError="True"
            Path="String1"
            UpdateSourceTrigger="PropertyChanged"
            ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                <local:ValidationRule1 ValidatesOnTargetUpdated="True" />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>
<TextBox
    x:Name="TextBox2">
    <TextBox.Text>
        <Binding
            NotifyOnValidationError="True"
            Path="Int1"
            UpdateSourceTrigger="PropertyChanged"
            ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                <local:ValidationRule2 ValidatesOnTargetUpdated="True" />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

TextBox1用于输入字符串,TextBox2用于输入整数。ValidationRule1仅验证TextBox1不为空。我希望通过ValidationRule2检查两个TextBox的组合值是否已存在于数据库中,因此需要将TextBox1的字符串传递给ValidationRule2,尝试用Wrapper和BindingProxy实现后,ValidationRule2中的String1属性始终为Null,请问哪里出错了?

我的实现代码如下:

Wrapper代码

public class Wrapper : DependencyObject
{
    public static readonly DependencyProperty NewSitzeinteilungSachnummerProperty = DependencyProperty.Register("NewSitzeinteilungSachnummer", typeof(string), typeof(Wrapper));

    public string NewSitzeinteilungSachnummer
    {
        get { return (string)GetValue(NewSitzeinteilungSachnummerProperty); }
        set { SetValue(NewSitzeinteilungSachnummerProperty, value); }
    }
}

BindingProxy代码

public class BindingProxy : Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata());
}

调整后的XAML

<TextBox
    x:Name="TextBox2">
    <TextBox.Resources>
        <local2:BindingProxy x:Key="proxy" Data="{Binding}"/>
    </TextBox.Resources>
    <TextBox.Text>
        <Binding
            NotifyOnValidationError="True"
            Path="Int1"
            UpdateSourceTrigger="PropertyChanged"
            ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                <local1:ValidationRule2 ValidatesOnTargetUpdated="True" >
                    <local1:ValidationRule2.Wrapper>
                        <local1:Wrapper String1="{Binding String1, Source={StaticResource proxy}}"/>
                    </local1:ValidationRule2.Wrapper>
                </local1:ValidationRule2>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

错误分析与修正方案

1. Wrapper依赖属性与CLR属性不匹配

你定义的Wrapper依赖属性是NewSitzeinteilungSachnummerProperty,对应CLR属性是NewSitzeinteilungSachnummer,但XAML中绑定的是String1,属性名完全不对应,导致绑定失效,值始终为Null。

修正后的Wrapper代码:

public class Wrapper : DependencyObject
{
    public static readonly DependencyProperty String1Property = 
        DependencyProperty.Register(nameof(String1), typeof(string), typeof(Wrapper));

    public string String1
    {
        get { return (string)GetValue(String1Property); }
        set { SetValue(String1Property, value); }
    }
}

2. BindingProxy的作用域与绑定路径错误

你把BindingProxy放在TextBox的Resources中,此时{Binding}的DataContext是TextBox本身,而非ViewModel,导致Proxy的Data属性无法获取到ViewModel实例。另外,绑定路径应该指向Proxy的Data.String1,而非直接String1。

修正后的BindingProxy放置位置(放在Window/UserControl的Resources中,确保DataContext是ViewModel):

<Window.Resources>
    <local:BindingProxy x:Key="viewModelProxy" Data="{Binding}"/>
</Window.Resources>

修正后的TextBox2 XAML:

<TextBox x:Name="TextBox2">
    <TextBox.Text>
        <Binding
            NotifyOnValidationError="True"
            Path="Int1"
            UpdateSourceTrigger="PropertyChanged"
            ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                <local:ValidationRule2 ValidatesOnTargetUpdated="True" >
                    <local:ValidationRule2.Wrapper>
                        <local:Wrapper String1="{Binding Data.String1, Source={StaticResource viewModelProxy}}"/>
                    </local:ValidationRule2.Wrapper>
                </local:ValidationRule2>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

3. ValidationRule2的Wrapper属性定义

确保ValidationRule2正确暴露Wrapper属性,以便绑定生效:

public class ValidationRule2 : ValidationRule
{
    public Wrapper Wrapper { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (Wrapper == null || string.IsNullOrEmpty(Wrapper.String1))
        {
            return new ValidationResult(false, "TextBox1的值未传入");
        }

        string stringValue = Wrapper.String1;
        int? intValue = int.TryParse(value.ToString(), out int result) ? result : null;

        // 替换为实际数据库检查逻辑
        bool isDuplicate = CheckCombinationExists(stringValue, intValue);

        if (isDuplicate)
        {
            return new ValidationResult(false, "该组合值已存在于数据库中");
        }

        return ValidationResult.ValidResult;
    }

    private bool CheckCombinationExists(string str, int? num)
    {
        // 实现数据库查询逻辑
        return false;
    }
}

内容的提问来源于stack exchange,提问作者user25180321

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 07:44:58