WPF DependencyProperty Validation Binding to the object property

最后都变了- 提交于 2019-12-07 17:59:30

You can use a proxy. It will allow you to bind a Property to your ValidationRule.

Proxy example

Here is a code sample that may help you :

<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>

IsRequired is always false because the "Dependency" object is not part of the logical tree, so you can not use ElementName or DataContext as source for internal data binding.

The solution to this problem is based on the following Thomas Levesque's article: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

You must create a class that inherits "Freezable" and declares a Data dependency property. The interesting feature of a Freezable class is that Freezable objects can inherit the DataContext even when they’re not in the visual or logical tree:

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));
}

You can then declare an instance of this class in the resources of you textbox, and bind the Data property to the current DataContext:

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

Finally, specify this BindingProxy object as the Source for the binding:

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

Note that the binding path must be prefixed with "Data" since since the path is now relative to the BindingProxy object.

There is another way of implementing the Validation of the Controls. However, I would still like to know how to solve my initial issue, so any help is appreciated.

Another way is implementing the IDataErrorInfo interface of the model.

Example:

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;
    }
}

"Is Required" in the custom Validation class is always False, because it is not set. and false is the default value for bool.

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

ValidationRule does not even have a DataContext property since it does not derive from FrameworkElement!

Note that IntegerContainer is a FrameworkElement, not a Dependency Object.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!