Question

I am getting crazy about a DataContext problem in WPF. I read the comments here in StackOverflow, but I can't fixed it.

I have the following data template :

<DataTemplate  x:Key="TodoTemplate"  >
    <Grid Margin="5 10 10 5" >

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="30" MaxWidth="30"/>
            <ColumnDefinition Width="30" MaxWidth="30"/>
            <ColumnDefinition Width="30" MaxWidth="30"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Grid.ContextMenu>
            <ContextMenu>
                <MenuItem Command="{Binding Path=View}">
                    <MenuItem.Header>
                        <WrapPanel>
                            <Label Margin="30 0 0 0" Background="LightBlue">View Item</Label>
                        </WrapPanel>
                    </MenuItem.Header>
                </MenuItem>

and a Listbox where I want to reuse my template :

    <ListBox Grid.Row="4" ItemsSource="{Binding Path=Items}" Margin="10" ItemTemplateSelector="{StaticResource categoryItemSelector}" SelectedItem="{Binding Path=CurrentItem,Mode=TwoWay}" MouseDoubleClick="ListBox_MouseDoubleClick"  >

    </ListBox>

The Listbox code is embedded in a page and this page sets an DataContext for a view model instance.

  DataContext="{Binding Source={StaticResource Locator},Path=CategoryDetails}">

I've learned that the context menu is not part of the visual tree and the data context cannot be reused directly. The problem is, that I also have a MemoTemplate with the same context menu and I want to reuse my view model here. Can anyone givie me a hint to solve it?

I tried to use the ContextService parameter and also to set a proxy. But my View command is not called via the context menu.

How cam I reuse my view model instance from my page ( via the listbox ) here ?

Thanks in advance Björn

Was it helpful?

Solution

You can reference the DataContext fine even from a ContextMenu. Just got to use PlacementTarget to route your Binding's.

Not sure where you have this View command declared so I'll describe both methods.

1: View command belongs to the ItemSource type T of the ListBox (In other words, it's in the class that forms the child elements of the ListBox)

Pretty simple we set the DataContext of the ContextMenu same as it's PlacementTarget which is the Grid.

...
<Grid.ContextMenu>
  <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}">
    <MenuItem Command="{Binding Path=View}">
      <MenuItem.Header>
    ...

2: If View command is in the VM CategoryDetails as a sibling of Items property.

With this approach, We set the DataContext of the ListBox which is the CategoryDetails VM as the Tag of the Grid element which ContextMenu attaches to. Now inside the ContextMenu we bind the MenuItem.Command to the ContextMenu's PlacementTarget.Tag.View

...
<Grid Margin="5 10 10 5"
              Tag="{Binding RelativeSource={RelativeSource FindAncestor,
                                                           AncestorType={x:Type ListBox}},
                            Path=DataContext}">
          <Grid.ContextMenu>
            <ContextMenu>
              <MenuItem Command="{Binding Path=PlacementTarget.Tag.View, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}">
...

You can substitute Tag with an Attached Property if you do not want to use Tag for this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top