Search code examples
wpfdata-bindingtooltipdatacontextitemscontrol

WPF Show data from multiple DataContexts in ToolTip of ItemsControl


I am trying to display a tooltip for an item generated by an ItemsControl that needs to pull data from conceptually unrelated sources. For example, say I have an Item class as follows:

public class Item
{
    public string ItemDescription { get; set; }
    public string ItemName { get; set; }
}

I can display the Item within an ItemsControl with a tooltip as follows:

<ItemsControl x:Name="itemsControl" ItemsSource="{Binding Items}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ItemName}">
                <TextBlock.ToolTip>
                    <ToolTip>
                        <TextBlock Text="{Binding ItemDescription}" />
                    </ToolTip>
                </TextBlock.ToolTip>
            </TextBlock>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

But say I have another property that can be accessed via the DataContext of the ItemsControl. Is there any way to do this from within the tooltip? E.g.,

<ItemsControl x:Name="itemsControl" ItemsSource="{Binding Items}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ItemName}">
                <TextBlock.ToolTip>
                    <ToolTip>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <TextBlock Text="{Binding ItemDescription}" />
                            <TextBlock Grid.Row="1" Text="{Bind this to another property of the ItemsControl DataContext}" />
                        </Grid>
                    </ToolTip>
                </TextBlock.ToolTip>
            </TextBlock>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The code for the test Window I used is as follows:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        List<Item> itemList = new List<Item>() {
            new Item() { ItemName = "First Item", ItemDescription = "This is the first item." },
            new Item() { ItemName = "Second Item", ItemDescription = "This is the second item." } 
        };

        this.Items = itemList;
        this.GlobalText = "Something else for the tooltip.";
        this.DataContext = this;
    }

    public string GlobalText { get; private set; }

    public List<Item> Items { get; private set; }
}

So in this example I want to show the value of the GlobalText property (in reality this would be another custom object).

To complicate matters, I am actually using DataTemplates and show two different types of objects within the ItemsControl, but any assistance would be greatly appreciated!


Solution

  • After an hour of hair pulling I have come to the conviction that you can't reference another DataContext inside a DataTemplate for a ToolTip. For other Bindings it is perfectly possible as other posters have proven. That's why you can't use the RelativeSource trick either. What you can do is implement a static property on your Item class and reference that:

    <Window x:Class="ToolTipSpike.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300"
        Name="Root"
        xmlns:ToolTipSpike="clr-namespace:ToolTipSpike">
        <Grid>
            <ItemsControl x:Name="itemsControl" ItemsSource="{Binding Items}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding ItemName}"> 
                            <TextBlock.ToolTip>
                                <ToolTip>
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition />
                                            <RowDefinition />
                                        </Grid.RowDefinitions>
                                        <TextBlock Text="{Binding ItemDescription}" />
                                        <TextBlock Grid.Row="1" 
                       Text="{Binding Source={x:Static ToolTipSpike:Item.GlobalText},
                       Path=.}"
                                        />
                                    </Grid>
                                </ToolTip>
                            </TextBlock.ToolTip>
                        </TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Grid>
    </Window>
    
    using System.Collections.Generic;
    using System.Windows;
    
    namespace ToolTipSpike
    {
        public partial class Window1 : Window
        {
    
            public List<Item> Items { get; private set; }
            public Window1()
            {
                InitializeComponent();
                var itemList = new List<Item>
                      {
                          new Item { ItemName = "First Item", ItemDescription = "This is the first item." },
                          new Item { ItemName = "Second Item", ItemDescription = "This is the second item." }
                      };
                this.Items = itemList;
                this.DataContext = this;
           }
        }
    
         public class Item
         {
             static Item()
             {
                 GlobalText = "Additional Text";
             }
             public static string GlobalText { get; set; }
             public string ItemName{ get; set;}
             public string ItemDescription{ get; set;}
         }
    }