Search code examples
wpfxamllistviewtooltipdatacontext

How to define the DataContext in a complex tooltip on a XAML ListView


I want to show a list of items in a WPF ListView and use a tooltip to show additional details of an item in the list.

I have made a sample project which you can download from http://www.jollans.com/WpfTooltipTest.zip

For the sample I have made a class with some properties:

class ItemClass
{
  public String    mainProperty_1 { get; set; }
  public String    mainProperty_2 { get; set; }
  public String    detailProperty_1 { get; set; }
  public String    detailProperty_2 { get; set; }
}

and a model which contains a list of these items

class Model
{
  public   ObservableCollection<ItemClass>  Items { get; private set; }

  public Model()
  {
    Items = new ObservableCollection<ItemClass>() ;
    Items.Add ( new ItemClass { mainProperty_1 = "One",   mainProperty_2 = "First item",  detailProperty_1="A", detailProperty_2 = "1" } ) ;
    Items.Add ( new ItemClass { mainProperty_1 = "Two",   mainProperty_2 = "Second item", detailProperty_1="B", detailProperty_2 = "2" } ) ;
    Items.Add ( new ItemClass { mainProperty_1 = "Three", mainProperty_2 = "Third item",  detailProperty_1="C", detailProperty_2 = "3" } ) ;
    Items.Add ( new ItemClass { mainProperty_1 = "Four",  mainProperty_2 = "Fourth item", detailProperty_1="D", detailProperty_2 = "4" } ) ;
    Items.Add ( new ItemClass { mainProperty_1 = "Five",  mainProperty_2 = "Fifth item",  detailProperty_1="E", detailProperty_2 = "5" } ) ;
    Items.Add ( new ItemClass { mainProperty_1 = "six",   mainProperty_2 = "Sixth item",  detailProperty_1="F", detailProperty_2 = "6" } ) ;
  }
}

The main window just instantiates the model and sets it as the DataContext

public partial class MainWindow : Window
{
  private Model   _model ;

  public MainWindow()
  {
    InitializeComponent();

    _model = new Model() ;
    this.DataContext = _model ;
  }
}

The basic ListView is something like this:

<ListView ItemsSource="{Binding Items}">
  <ListView.View>
    <GridView>
      <GridViewColumn Width="100" Header="Main Property 1" DisplayMemberBinding="{Binding Path=mainProperty_1}"/>
      <GridViewColumn Width="200" Header="Main Property 2" DisplayMemberBinding="{Binding Path=mainProperty_2}"/>
    </GridView>
  </ListView.View>
</ListView>

but this doesn't have any tooltips.

I know that one way is to add something like:

<ListView.ItemContainerStyle>
  <Style TargetType="{x:Type ListViewItem}">
    <Setter Property="ToolTip" Value="{Binding Path=detailProperty_1}" />
  </Style>
</ListView.ItemContainerStyle>

which shows a single property from the ItemClass, but I want something much more elaborate.

I have defined a style resource containing a grid as a tooltip:

<Window.Resources>

  <Style x:Key="ItemTooltip" TargetType="ToolTip">
    <Setter Property="ContentTemplate">
      <Setter.Value>
        <DataTemplate>

          <Grid Margin="5">
            <Grid.RowDefinitions>
              <RowDefinition/>
              <RowDefinition/>
              <RowDefinition/>
              <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="113"/>
              <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0">Main property 1:</TextBlock>
            <TextBlock Grid.Row="1" Grid.Column="0">Main property 2:</TextBlock>
            <TextBlock Grid.Row="2" Grid.Column="0">Detail property 1:</TextBlock>
            <TextBlock Grid.Row="3" Grid.Column="0">Detail property 2:</TextBlock>
            <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=mainProperty_1}" />
            <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=mainProperty_2}" />
            <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=detailProperty_1}" />
            <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding Path=detailProperty_2}" />
          </Grid>

        </DataTemplate>
      </Setter.Value>
    </Setter>
  </Style>

</Window.Resources>

I have added a third column to the grid with a TextBlock, which uses this tooltip.

<ListView ItemsSource="{Binding Items}">
  <ListView.View>
    <GridView>
      <GridViewColumn Width="100" Header="Main Property 1" DisplayMemberBinding="{Binding Path=mainProperty_1}"/>
      <GridViewColumn Width="200" Header="Main Property 2" DisplayMemberBinding="{Binding Path=mainProperty_2}"/>

      <GridViewColumn Width="200" Header="Main Property 2 again" >
        <GridViewColumn.CellTemplate>
          <DataTemplate>
            <TextBlock Text="{Binding Path=mainProperty_2}">
              <TextBlock.ToolTip>
                <ToolTip Style="{StaticResource ItemTooltip}" DataContext="{Binding}" />
              </TextBlock.ToolTip>
            </TextBlock>
          </DataTemplate>
        </GridViewColumn.CellTemplate>
      </GridViewColumn>

    </GridView>
  </ListView.View>
</ListView>

(I don't really want the TextBlock, but that is not the subject of this question.)

The tooltip is displayed and shows the grid, but the bindings don't work, because I haven't set up the DataContext. I have defined four rows in the grid which should display fields from the ItemClass.

How can I set up the DataContext in the tooltip, so that I can bind to properties of the item in the grid where the tooltip is shown?


Solution

  • The ToolTip property is an object, so you can just use Setter.Value syntax:

    <Setter Property="ToolTip">
      <Setter.Value>
         <Grid...>
         </Grid>
      </Setter.Value>
    </Setter>
    

    The tooltip will be rendered via a ContentPresenter, so anything in there will show correctly.