Home > Posts > HowTo: Bind cell to row data in DataGrid DataTemplate for MVVM control

HowTo: Bind cell to row data in DataGrid DataTemplate for MVVM control

When using MVVM design style for a Silverlight or WPF control, it is common to use the control’s DataContext to keep the associated ViewModel instance, so that in the XAML file for the control one can use simple binding statements from the UI to the view model (and back if TwoWay binding mode is specified) of the form:
Text=”{Binding Comments}”
or
Text=”{Binding Comments, Mode=TwoWay}”

However, if you use that pattern you will fall into trouble when using your control inside a DataTemplate for a DataGrid Cell, when you use the same simple binding statements to bind properties of your control to a row cell of data (passed to you by DataGrid, which gets them from its [bound] data source).

The reason is that binding statements inside DataTemplates seem to be resolved at the context of your control and not at the context of say the DataGrid, which, combined with the fact that your control won’t be inheriting its parent’s (the DataGrid Cell’s that is) DataContext, since it has a non-null DataContext value of its own (where it keeps its ViewModel instance), results in the binding expression not working properly.

You can set a breakpoint in the XAML at the row of the data binding expression and examine the binding context at runtime via the locals window in Visual Studio, but if it happens that you have the same property name at your control, at its ViewModel and also at the row of data from the datasource (as I am doing with “Audio” used at the ResourceDictionary XAML excerpt from ClipFlair shown below), then it’s hard to spot that you’ve been binding your control’s dependency property to a field of its own ViewModel, instead of binding it to the DataGrid source’s row cell data.

The best workaround is to use a RelativeSource Binding like below (compare the Audio and the Comments templates there – note that at the Audio we don’t need a separate edit template, our control is live and “editing” [recording/playing audio] at any time)

  <!-- Audio -->
  
  <DataTemplate x:Key="AudioCellTemplate">
    <audio:AudioRecorderControl 
Audio="{Binding RelativeSource={RelativeSource
AncestorType=FrameworkElement},
Path=DataContext.Audio, Mode=TwoWay}" />
<!-- AudioRecorderControl sets its DataContext to its ViewModel,
so it doesn't inherit its parent's DataContext -->
</DataTemplate> <!-- Comments --> <DataTemplate x:Key="CommentsCellTemplate"> <TextBlock Margin="4" Text="{Binding Comments}" /> </DataTemplate> <DataTemplate x:Key="CommentsCellEditTemplate"> <TextBox Margin="4" AcceptsReturn="True"
Text="{Binding Comments, Mode=TwoWay,
ValidatesOnExceptions=True, NotifyOnValidationError=true}" /> </DataTemplate>

Note that the “{Binding … }” strings above need to be in a single line in the XAML file

References:

for WPF: http://stackoverflow.com/questions/3404707/access-parent-datacontext-from-datatemplate/13554039

for Silverlight: http://www.wintellect.com/cs/blogs/sloscialo/archive/2011/07/26/where-s-my-datacontext.aspx

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: