【问题标题】:WPF DependencyProperty Validation Binding to the object propertyWPF DependencyProperty Validation 绑定到对象属性
【发布时间】:2015-02-07 03:34:07
【问题描述】:

我正在尝试为给定控件创建验证规则(在这种情况下,它是 TextBox)。

我无法成功绑定到对象的属性,尽管采取了适当的步骤:利用了 ValidationRule 和 DepedencyProperty。

请在下面找到代码。附带说明的是,自定义 Validation 类中的“Is Required”始终为 False,除非我在 XAML 中明确设置值(没有绑定,根据“Is Ranged”参数)。

感谢任何提示和建议。

提前谢谢你:)

XAML 代码:

<TextBox Style="{StaticResource ValidationError}" LostFocus="ForceValidationCheck"
         Visibility="{Binding Type, Converter={StaticResource Visibility}, ConverterParameter='Number'}"
         IsEnabled="{Binding RelativeSource={x:Static RelativeSource.Self}, Converter={StaticResource IsEnabled}}">
    <TextBox.Text>
        <Binding Path="Value">
            <Binding.ValidationRules>
                <validation:NumericValidation>
                    <validation:NumericValidation.Dependency>
                        <validation:NumericDependency IsRequired="{Binding Path=IsRequired}" IsRanged="True" Min="5"/>
                    </validation:NumericValidation.Dependency>
                </validation:NumericValidation>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

验证类:

public NumericDependency Dependency { get; set; }

public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
    isRequired = Dependency.IsRequired;
}

验证依赖类:

public static readonly DependencyProperty IsRequiredProperty =
        DependencyProperty.Register("IsRequired", typeof(bool), typeof(NumericDependency), new UIPropertyMetadata(default(bool)));

public bool IsRequired
{
    get
    {
        return (bool) GetValue(IsRequiredProperty);
    }
    set
    {
        SetValue(IsRequiredProperty, value);
    }
}

【问题讨论】:

    标签: wpf validation binding validationrules dependencyobject


    【解决方案1】:

    您可以使用代理。它将允许您将属性绑定到您的 ValidationRule。

    Proxy example

    这是一个可以帮助你的代码示例:

    <Utils:Proxy In="{Binding IsRequired, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" Out="{Binding ElementName=numericValidationRule, Path=IsRequired}" />
    <TextBox>
        <TextBox.Text>
            <Binding Path="Value">
                <Binding.ValidationRules>
                    <NumericValidation x:Name="numericValidationRule" />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    

    【讨论】:

    • 链接已失效。
    【解决方案2】:

    IsRequired 始终为 false,因为“依赖”对象不是逻辑树的一部分,因此您不能使用 ElementName 或 DataContext 作为内部数据绑定的源。

    这个问题的解决方法基于以下几点 Thomas Levesque 的文章:http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

    您必须创建一个继承“Freezable”并声明数据依赖属性的类。 Freezable 类的有趣特性是 Freezable 对象可以继承 DataContext,即使它们不在可视树或逻辑树中:

    public class BindingProxy : Freezable
    {
       #region Overrides of Freezable
       protected override Freezable CreateInstanceCore()
       {
          return new BindingProxy();
       }
       #endregion
    
       public object Data
       {
          get { return (object)GetValue(DataProperty); }
          set { SetValue(DataProperty, value); }
       }
    
       // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
       public static readonly DependencyProperty DataProperty =
          DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }
    

    然后,您可以在文本框的资源中声明此类的实例,并将 Data 属性绑定到当前 DataContext:

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

    最后,将此 BindingProxy 对象指定为绑定的 Source:

    <validation:NumericDependency IsRequired="{Binding Source={StaticResource proxy} Path=Data.IsRequired}" IsRanged="True" Min="5"/>
    

    请注意,绑定路径必须以“Data”为前缀,因为该路径现在是相对于 BindingProxy 对象的。

    【讨论】:

      【解决方案3】:

      还有另一种实现控件验证的方法。但是,我仍然想知道如何解决我最初遇到的问题,因此非常感谢您的帮助。

      另一种方式是实现模型的IDataErrorInfo接口。

      例子:

      public string this[string columnName]
      {
          get
          {
              if (string.Equals(columnName, "Value", StringComparison.CurrentCultureIgnoreCase))
              {
                  string value = Convert.ToString(Value);
      
                  if (string.IsNullOrEmpty(value) && IsRequired)
                  {
                      return ValidationMessage.RequiredValue;
                  }
              }
      
              return string.Empty;
          }
      }
      

      【讨论】:

        【解决方案4】:

        自定义 Validation 类中的“Is Required”始终为 False,因为它没有设置。而 false 是 bool 的默认值。

        来自http://www.codeproject.com/Articles/18678/Attaching-a-Virtual-Branch-to-the-Logical-Tree-in

        ValidationRule 甚至没有 DataContext 属性,因为它不是从 FrameworkElement 派生的!

        请注意,IntegerContainer 是一个 FrameworkElement,而不是一个依赖对象。

        【讨论】: