Originally published on my old Charteris blog

Richard contacted me today because he was having trouble binding a ListBox’s ContextMenu to data belonging to the SelectedItem. My initial thought was binding statement like this

<ListBox.ContextMenu>

  <ContextMenu>

    <MenuItem Header="{Binding Path=SelectedIndex,

                    RelativeSource={RelativeSource FindAncestor,

                    AncestorType={x:Type ListBox}}}" />

  </ContextMenu>

</ListBox.ContextMenu>

RelativeSource tells the binding looking for the source of the binding and the way it does this is dependent on the mode. The four, supported modes are

  • FindAncestor – This will walk up the VisualTree looking for a item of a particular type
  • PreviousData - Allows you to bind the previous data item in the list of data items being displayed. 
  • Self – This refers to the item that you are currently setting the Binding on. In the case of our Context menu it is the MenuItem
  • TemplatedParent – This refers to the item that is currently being templated, by a template, in which this binding statement exists.

The trouble with my use of FindAncestor was the way that ContextMenus are created. They are not part of the same visual tree as the ListBox and therefore any attempts to walk up from the MenuItem to the ListBox fail. Something worth noting is that these kind of binding failures are silent and the only obvious sign is that you bindings do not result in any data. No explanation seems available? not true. Many binding failures are reported a warnings to the debug window. So for instance if you are building your app using VS.NET keep an eye on the Output window for Binding error.

What I needed to do was look a little closer to home. The direct parent of the MenuItem, the ContextMenu. Once I get hold of the ContextMenu in my binding statement I can bind to the PlacementTarget of the ContextMenu which is of course the ListBox.

<ListBox Margin="5" Name="MyListBox" HorizontalAlignment="Left">

  <ListBox.ContextMenu>

    <ContextMenu>

      <MenuItem

        Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},

              Path=PlacementTarget.SelectedIndex}"/>

    </ContextMenu>

  </ListBox.ContextMenu>

 

  <ListBoxItem>

    <TextBlock Text="Item1"/>

  </ListBoxItem>

  <ListBoxItem>

    <TextBlock Text="Item2"/>

  </ListBoxItem>

  <ListBoxItem>

    <TextBlock Text="Item3"/>

  </ListBoxItem>

  <ListBoxItem>

    <TextBlock Text="Item4"/>

  </ListBoxItem>

</ListBox>