views:

1672

answers:

1

I've got a datagrid column as below:

<toolkit:DataGridTemplateColumn>
                        <toolkit:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Path=LabelName}" Background="{Binding Path=Color}">
                                    <TextBlock.ContextMenu>
                                        <ContextMenu>
                                            <MenuItem x:Name="Assign" Header="Assign"
                                                      mvvm:CommandBehavior.Event="Click"
                                                      mvvm:CommandBehavior.Command="{Binding Path=DataContext.EditLabelCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}, AncestorLevel='1'}}"
                                                      mvvm:CommandBehavior.CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=DataContext}"/>
                                        </ContextMenu>
                                    </TextBlock.ContextMenu>
                                </TextBlock>
                            </DataTemplate>
                        </toolkit:DataGridTemplateColumn.CellTemplate>

I'm trying to get to the DataContext's EditLabelCommand, but I cannot find the binding source. What should I do to access my DataContext's commands?

+3  A: 

DataContext changes as you move down the visual tree when you either a) bind DataContext to something else, or b) use something like an items control (or in your case a grid), which repeats your data template once per item in a collection, setting the data context for each item.

In your example, your menu item has the same DataContext as your TextBlock. This will be the object bound to each row of your data grid.

Based on your code, I think you have one EditLabelCommand available in the DataContext set for your entire UserControl. This is likely the parent of the collection you are binding to the grid. (Please correct me if any of these assumptions are wrong.)

If this is the case, there are several things you can do:

  • You can continue to use relative binding. This is complex and error prone, as you have seen, and does not lead to good reuse of your data templates or other XAML. I recommend you avoid this technique.

  • A simpler way to keep the command in the overall datacontext is to use a CommandReference from the WPF Model-View-ViewModel Toolkit. This allows you to reference the command as a resource and use resource binding to access it. Like this:

    <UserControl.Resources>
        <mvvmToolkit:CommandReference x:Key="EditLabelCommandReference" Command="{Binding EditLabelCommand}" />
    </UserControl.Resources>

    <!-- Your command binding then looks much simpler -->
    mvvm:CommandBehavior.Command="{StaticResource EditLabelCommandReference}"
  • Another (probably better) technique is to refactor to use the MVVM pattern for each row. This way, you would use a simple ViewModel per row of your grid. This allows each row to maintain its own state. Because you can move the Command implementation into this ViewModel, you have a command per row and no need to pass an argument. This makes it possible to edit more than one row's label at a time. (If this a requirement.)
Jerry Bullard