views:

97

answers:

2

How do I set the DataContext of "myElement" to the same DataContext as the user control in XAML? I have been able to do it in code-behind via myElement.DataContext = this.DataContext in the UserControl constructor, but I'm trying to understand how to do the same thing in XAML.

This is related to creating virtual branches to the logical tree (see this article).

<UserControl ... DataContext="{Binding RelativeSource={RelativeSource self}}">
    ...
    <TextBox Name="myTextBox">    
        <TextBox.Text>        
            <Binding Path="MySource" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>             
                    <base:StringEqualsRules>
                        <base:StringEqualRule.BoundElement>
                            <base:ValidationRuleElement 
                                x:Name="myElement"
                                DataContext="???"
                                Value="{Binding MyProperty}" />
                        </base:StringEqualRule.BoundElement>
                    </base:StringEqualsRule>
                 </Binding.ValidationRules>
             </Binding>    
         </TextBox.Text>
    </TextBox>
    ...
</UserControl>
+1  A: 

Give the top-level UserControl element an x:Name then use an ElementName binding. Like so:

<UserControl ... x:Name="Root" DataContext="...">
    <SomeNestedChild DataContext="{Binding DataContext, ElementName=Root}" />
</UserControl>
Josh Einstein
A related solution would be to use an AncestorType binding for type UserControl (or even his custom user control class).
itowlson
I'm not familiar with this virtual branch technique Josh Smith wrote about but it seems to be that the logical tree would be "disconnected" in a way that would make the AncestorType not work as intended.
Josh Einstein
@Josh - That's correct. The FindAncestor won't work in this scenario because myElement is not part of the logical tree.
Taylor Leese
I will try this solution and see what happens.
Taylor Leese
It looks like Binding using ElementName doesn't work either since myElement is not part of the logical tree. Is there any way to do this binding using a Dynamic/Static resource?
Taylor Leese
This is the exception I see in the output window: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=root'. BindingExpression:Path=DataContext; DataItem=null; target element is 'ValidationRuleElement' (Name='myElement'); target property is 'DataContext' (type 'Object')
Taylor Leese
It looks like the problem is that the NameScope in the validation rule is null which is why the lookup by ElementName fails. Any ideas?
Taylor Leese
Hm, off hand I don't know too much about WPF validation rules (I've opted to do validation in the ViewModel using IDataErrorInfo) but is the rule instance aware of its TextBox parent at all? Perhaps you could (in code using NameScope.SetNameScope) add it to the correct name scope as needed.
Josh Einstein
Scratch that... I can see ValidationRule does not derive from DependencyObject.
Josh Einstein
Yeah, the fact that it doesn't derive from DependencyObject is the source of the problem.
Taylor Leese
Seems like the best thing to do might be to stick with code-behind for setting the DataContext.
Taylor Leese
Yeah I think so for now. Sorry I couldn't be of more help. I'm sure there's a clever way to do it with an attached property or something, but my brain is in pretty bad shape right now.
Josh Einstein
A: 

Using code-behind turned out to be the easiest and cleanest solution I've found so far:

myElement.DataContext = this.DataContext
Taylor Leese