RelativeSource binding from a ToolTip or ContextMenu

This is tricky because ToolTip is not part of the VisualTree. Here you see a cool solution for the same problem with ContextMenus. The same way you can go for the ToolTip.

UPDATE
Sadly the link is gone and I have not found the referenced article anymore.
As far as I remember, the referenced blog has shown how to bind to a DataContext of another VisualTree, which is often necessay when binding from a ToolTip, a ContextMenu or a Popup.

A nice way to do this, is to provide the desired instance (e.g. ViewModel) within the Tag-property of the PlacementTarget. The following example does this for accessing a Command-instance of a ViewModel:

<Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}">
  <Button.ContextMenu>
    <ContextMenu>
       <MenuItem Command="{Binding PlacementTarget.Tag.DesiredCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" .../>
    <ContextMenu>
  </Button.ContextMenu>
</Button>

I have not tested it and its a long time I did this the last time. Please make a comment if it does not work for you.

UPDATE 2

As the original link that this answer was written about is gone, I hit archive.org and found the original blog entry. Here it is, verbatim from the blog:

Because a ContextMenu in WPF does not exist within the visual tree of
your page/window/control per se, data binding can be a little tricky.
I have searched high and low across the web for this, and the most
common answer seems to be “just do it in the code behind”. WRONG! I
didn’t come in to the wonderful world of XAML to be going back to
doing things in the code behind.

Here is my example to that will allow you to bind to a string that
exists as a property of your window.

public partial class Window1 : Window
{
    public Window1()
    {
        MyString = "Here is my string";
    }

    public string MyString
    {
        get;
        set;

    }
}


<Button Content="Test Button" 
     Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
  <Button.ContextMenu>
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, 
          RelativeSource={RelativeSource Self}}" >
      <MenuItem Header="{Binding MyString}"/>
    </ContextMenu>
  </Button.ContextMenu>   
</Button>

The important part is the Tag on the button(although you could just as
easily set the DataContext of the button). This stores a reference to
the parent window. The ContextMenu is capable of accessing this
through it’s PlacementTarget property. You can then pass this context
down through your menu items.

I’ll admit this is not the most elegant solution in the world.
However, it beats setting stuff in the code behind. If anyone has an
even better way to do this I’d love to hear it.

Leave a Comment