3

My UserControl requires binding to the ancestor (the ancestor being the MainWindow) and to itself (it's code behind).

To bind to the ancestor, I'm using

DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType=Window}}"> 

To bind a control to the code behind (and thus using the 'local' DataContext), I'm using

<TextBlock Text ="{Binding MyUC3Property}" Name="MyName" />

and in the code behind, setting it like

this.MyName.DataContext = this;

The above works fine, where I can bind to the codebehind and to the ancestor.

Now, I still want to bind to the code behind and the ancestor but set the DataContext in the XAML only (if possible).

I've tried

<TextBlock Text ="{Binding MyUC3Property}" DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}" /> 

and ensured the constructor does not set the DataContext (since I want it all done in the XAML) - (although even if I do set this.DataContext = this; the error persists)

and the output window tells me there is a binding error.

System.Windows.Data Error: 40 : BindingExpression path error: 'MyUC3Property' property not found on 'object' ''TextBlock' (Name='')'. BindingExpression:Path=MyUC3Property; DataItem='TextBlock' (Name=''); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

I guess I'm missing something obvious, but I can't tell what.

Dave
  • 8,163
  • 11
  • 67
  • 103
  • *What* binding error is there? What is the error message? – O. R. Mapper Dec 06 '13 at 09:14
  • In the constructor of the window / control set `this.DataContext = this;` – RononDex Dec 06 '13 at 09:17
  • I presume you renamed `MyUC3Property` into `MyLocalProperty` for the sample source code in the question? – O. R. Mapper Dec 06 '13 at 09:17
  • @RononDex I did try this, but how will it help? It will 'overwrite' that I do want binding to the parent. – Dave Dec 06 '13 at 09:20
  • @DaveRook Hope this pdf will be helpful to you http://www.nbdtech.com/Free/WpfBinding.pdf – asitis Dec 06 '13 at 09:20
  • So you have other controls that are binded to properties not in code behind? – RononDex Dec 06 '13 at 09:21
  • I am still not sure I understand what you want to bind to. `MyUC3Property` is a property of the user control, it seems (the "local code-behind")? If so, isn't that exactly what the "parent" is, like in your first example? `Self` in the `TextBox` is the `TextBox` itself. – O. R. Mapper Dec 06 '13 at 09:22
  • Yes. See http://programmers.stackexchange.com/questions/220448/is-a-god-viewmodel-desired-in-wpf for a picture, all my usercontrols are binding to a parent. I now want to bind to the parent and to the code behind. – Dave Dec 06 '13 at 09:23
  • @DaveRook: What is the difference between the "parent" and the "code-behind"? Both denote the very same user control, don't they? – O. R. Mapper Dec 06 '13 at 09:25
  • Sorry, I should be using the term ancestor. Yes, @O.R.Mapper, 'MyUC3Property' is local to the UserControl. The issue is, my DataContext of the UserControl is already set to the Ancestor. So, I need a way of setting just the Textbox Datacontext to use the code behind of the UserControl. – Dave Dec 06 '13 at 09:25

3 Answers3

9

You should be able to bind to the user control the same way as you do to the window:

DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1,AncestorType=UserControl}}">

What you have tried was referring to the relative source Self from the TextBox. However, in that context, Self refers to the TextBox, not to the enclosing user control.

O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114
  • This hurts my head. You're right, this answers the question, but how? Surely the code behind is `self` yet it appears as if we're searching for an ancester which is 1 level up from this control? – Dave Dec 06 '13 at 09:32
  • I'm sorry I can only give 1 * +1, what a wonderfully clear explanation. Thank you – Dave Dec 06 '13 at 09:34
  • its easier to use ElementName Binding for this cases - its easier for your head ;) – blindmeis Dec 06 '13 at 09:50
  • @blindmeis: True @head, though YMMV - when inserting many such bindings via copy-and-paste, changing the `ElementName` value to the name of the current user control (unless it is a totally non-descriptive name, which seems somewhat sloppy) is more cumbersome than binding to the next `UserControl` ancestor. – O. R. Mapper Dec 06 '13 at 10:14
3

for usercontrols you should never set the datacontext to self. check to comment from H.B. from here

i use ElementName Binding

 <UserControl x:Name="uc">
   <TextBlock Text="{Binding ElementName=uc, Path=MyDependencyPropertyDefinedInMyUserControl}"/>

using the usercontrol:

 <Window>
   <MyUserControl MyDependencyPropertyDefinedInMyUserControl="{Binding Path=MyValueForTheTextBox}"/>

i try to explain it a little bit for your textbox case (ignor my poor english btw :))

if you want create a usercontrol with a textbox and this usercontrol/textbox should show the text from differrent viewmodels in different views - then you have a problem as far as the viewmodels have different propertynames. now the dependency property in your usercontrol come into the game. you create a DP where all your viewmodels can bind to and you bind your textbox within your usercontrol just to the DP from your usercontrol.

Community
  • 1
  • 1
blindmeis
  • 22,175
  • 7
  • 55
  • 74
  • If everything binds like this, does it not mean you end up with a big 'god' like ViewModel (which I have no problem with as the data is relevant etc, I just want to get a better understanding) – Dave Dec 06 '13 at 10:07
  • the elementname binding for your usercontrol has nothing to do with the viewmodel. the viewmodel binds to the Dependencyproperty from the usercontrol – blindmeis Dec 06 '13 at 10:21
  • I appreciate that, but this still means all of the properties will live higher the tree. Your post has really helped about structuring my project as a whole, so a big thank you. I'm guessing that, all my UserControls should be pretty empty other than DependancyProperties? What about functions/methods/Commands, should they also live where the properties are defined? – Dave Dec 06 '13 at 10:38
0

First thing is that you should probably push your parent DataContext to the lower levels. This will give you "God" ViewMode shared between all nested screens.

Second is that you should probably use something like MVVMLights Messanger to have cleaner separation.

Anatolii Gabuza
  • 6,184
  • 2
  • 36
  • 54