58

We have a WPF application with a standard MVVM pattern, leveraging Cinch (and therefore MefedMVVM) for View -> ViewModel resolution. This works well, and I can bind the relevant controls to properties on the ViewModel.

Within a particular View, we have an Infragistics XamGrid. This grid is bound to an ObservableCollection on the ViewModel, and displays the appropriate rows. However, I then have a specific column on this grid which I am trying to bind a TextBox text value to a property on the parent DataContext, rather than the ObservableCollection. This binding is failing.

We've gone through several options here including:

  1. Using AncestorType to track up the tree and bind to the DataContext of the parent UserControl like so (from the great answer to this question, as well as this one)...

    {Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}} 
  2. Specifying the ElementName and trying to target the top level control directly. Have a look here if you'd like to read about using ElementName.

  3. Using a 'proxy' FrameorkElement defined in the resources for the UserControl to try and 'pass in' the context as required. We define the element as below, then reference as a static resource...

    <FrameworkElement x:Key="ProxyContext" DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"></FrameworkElement> 

In this case the binding finds the FrameworkElement, but can not access anything beyond that (when specifying a Path).

Having read around, it looks quite likely that this is caused by the Infragistics XamGrid building columns outside of the tree. However, even if this is the case, at least options 2 or 3 should work.

Our last thoughts are that it is related to the V - VM binding, but even using Snoop we've yet to find what the exact issue is. I'm by no means an expert with WPF binding so any pointers would be appreciated.

EDIT: I have found some templating examples from Infragistics here that I will try.

EDIT 2: As pointed out by @Dtex, templates are the way to go. Here is the relevant snippet for use with a XamGrid:

<ig:GroupColumn Key="CurrentDate"> <ig:GroupColumn.HeaderTemplate> <DataTemplate> <TextBlock Text="{Binding Path=DataContext.CurrentDateTest, RelativeSource={RelativeSource AncestorType=UserControl}}" /> </DataTemplate> </ig:GroupColumn.HeaderTemplate> <ig:GroupColumn.Columns> 

I've left the XML open... you'd simply add the columns you wanted, then close off the relevant tags.

4
  • "Having read around, it looks quite likely that this is caused by the Infragistics XamGrid building columns outside of the tree. However, even if this is the case, at least options 2 or 3 should work". Actually i think that's incorrect, they are not in the visual tree, you can't reference anything, even using ElementName as you can see. You can work around it for example by defining a DataGridTemplateColumn and specify the binding in the cell template Commented Nov 16, 2012 at 11:38
  • @Dtex Sure, and this is where my limit of binding / tree knowledge is slowing me down. I will try a template column, but would appreciate an example if you have one. Commented Nov 16, 2012 at 12:17
  • Just IMO, but this is why I don't think user controls/custom controls should set their DataContext. It breaks stuff for the consumer! Commented Nov 16, 2012 at 13:26
  • Please do not put answers in questions. You can post a separate answer post to share your solution. Commented Nov 14, 2018 at 15:30

2 Answers 2

110

I dont know about XamGrid but that's what i'll do with a standard wpf DataGrid:

<DataGrid> <DataGrid.Columns> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=MyUserControl}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <TextBox Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType=MyUserControl}}"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> 

Since the TextBlock and the TextBox specified in the cell templates will be part of the visual tree, you can walk up and find whatever control you need.

Sign up to request clarification or add additional context in comments.

2 Comments

Bingo. Templates was the way to go. I'll update my question with the relevant example for a XamGrid. Do you have any good articles explaining the visual tree stuff @Dtex? Thanks for pointing me in the right direction.
Well for i learnt the hard way like you did :). Actually i was trying to bind a DataGridComboBoxColumn ItemsSource. You can refer to blogs.msdn.com/b/vinsibal/archive/2008/08/14/… for specific info about DataGrid
0

Because of things like this, as a general rule of thumb, I try to avoid as much XAML "trickery" as possible and keep the XAML as dumb and simple as possible and do the rest in the ViewModel (or attached properties or IValueConverters etc. if really necessary).

If possible I would give the ViewModel of the current DataContext a reference (i.e. property) to the relevant parent ViewModel

public class ThisViewModel : ViewModelBase { TypeOfAncestorViewModel Parent { get; set; } } 

and bind against that directly instead.

<TextBox Text="{Binding Parent}" />

2 Comments

Wouldn't the same issue remain? The grid is bound to a collection on the VM, and therefore the scope for the child columns is the collection, not the DataContext. In your example, the TextBox can't see the Parent, as it's scope is the collection property already bound by it's parent grid. Apologies, it was probably my loose description that didn't help here!
@Nick What this answer is saying is: give the elements of the collection (which should themselves be view models) a reference to the parent view model. Reading the question closer, though, the problem isn't that it is binding to elements of the collection, but rather the collection itself, which just seems wrong.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.