Question

I am having problems with Binding. Since RelativeSource needs the visual tree to travel up and find the desired Ancestor, you are only allowed to use it on an UIElement but I am trying to do a RelativeSource binding on an Non-UIElement, such as is a ValidationRule, which as you all know isnt inside the VisualTree nor its UIElement. As you can expect the binding breaks. RelativeSource couldn't be found because like i said there is no VisualTree or LogicalTree available. I need to make it work though.

Here is an example of XAML:

<StackPanel DataContext{Binding}>
  <Grid>
    <ContentControl Content{Binding MVPart1>
      <TextBox>
       <TextBox.Text>
        <Binding Path="VMPart1Property1">
         <Binding.ValidationRules>
           <my:MyValidationRule>
            <my:ValidationRule.DOC>
             <my:DepObjClass DepProp={Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}}/>
            </my:ValidationRule.DOC>
          </Binding.ValidationRules>
         </Binding>
       </TextBox.Text>
      </TextBox>  
    </ContentControl>
  </Grid>
</StackPanel>

So basically MyValidationRule is derivering from ValidationRule class, but thats not UIElement nor DependencyObject and therefore I had to create a class which derivates from DependencyObject called DepObjClass to be able to write down the xaml binding expression.

Here is code:

public class MyValidationRule : ValidationRule
{
  public DepObjClass DOC
  {
    get;
    set;
  }

  public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
  {
      string text = value as string;
      if (!string.IsNullOrEmpty(text))
      {
         return new ValidationResult(true, string.Empty);
      }

      return new ValidationResult(false, "Not working blahhh");
   }
}

public class DepObjClass : DependencyObject
{
  public object DepProp
  {
    get
    {
      return (object)GetValue(DepPropProperty);
    }
    set
    {
      SetValue(DepPropProperty, value);
    }
  }

  public static DependencyProperty DepPropProperty
     = DependencyProperty.Register(typeof(object), typeof(DepObjClass)......);
}

Now to sum up. MyValidatonRule is not UIElement its not DependencyObject but it has a property of a type that is, hence why the xaml binding expression compiles.

When I run the application the binding itself isnt working because StackPanel couldnt be found because ValidationRule doesnt have VisualTree nor my validation rule participates in Logical or Visual Tree.

The question is how do I make such case work, how to find StackPanel from an Non-UIElement such as my ValidationRule?

I appologize for my code not comipiling but I hope you can understand what I am trying to do. I am giving 50 points to you guys for the right answer.

Was it helpful?

Solution

You can do the following:

  1. Create a helper component which derives from Freezable and defines a DependencyProperty for what you want to bind.

  2. Create a ValidationRule with a property which takes an object of the helper component, similar to what you have done already.

  3. Declare an instance of the helper component in the Resources of an object which can bind to whatever you want to bind. Freezable and its derived classes inherit the binding context (the location in the logical tree) of any control in whose Resources they are declared, so there you can create your binding.

  4. When declaring the ValidationRule, use {StaticResource} to assign the helper component to the property in the ValidationRule. StaticResource works without a binding context, as long as the resource is declared before it is used.

The XAML would look like this:

<StackPanel>
  <StackPanel.Resources>
    <my:Helper x:Key="helper" ValProperty="{Binding}"/>
  </StackPanel.Resources>
  <Grid>
      <TextBox DataContext="{Binding MVPart1}">
       <TextBox.Text>
        <Binding Path="VMPart1Property1">
         <Binding.ValidationRules>
           <my:MyValidationRule Helper="{StaticResource helper}"/>
          </Binding.ValidationRules>
         </Binding>
       </TextBox.Text>
      </TextBox>  
  </Grid>
</StackPanel>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top