如何在 XAML ListView 的复杂工具提示中定义 DataContext
How to define the DataContext in a complex tooltip on a XAML ListView
我想在 WPF ListView 中显示项目列表,并使用工具提示显示列表中项目的其他详细信息。
我制作了一个示例项目,您可以从 http://www.jollans.com/WpfTooltipTest.zip
下载
对于示例,我制作了一个具有某些属性的 class:
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; }
}
以及包含这些项目列表的模型
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" } ) ;
}
}
主要window只是实例化模型并将其设置为DataContext
public partial class MainWindow : Window
{
private Model _model ;
public MainWindow()
{
InitializeComponent();
_model = new Model() ;
this.DataContext = _model ;
}
}
基本的ListView是这样的:
<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>
但这没有任何工具提示。
我知道一种方法是添加如下内容:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding Path=detailProperty_1}" />
</Style>
</ListView.ItemContainerStyle>
它显示了 ItemClass 中的单个 属性,但我想要更详细的东西。
我定义了一个包含网格作为工具提示的样式资源:
<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>
我用一个 TextBlock 向网格添加了第三列,它使用了这个工具提示。
<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>
(我真的不想要 TextBlock,但这不是这个问题的主题。)
显示工具提示并显示网格,但绑定不起作用,因为我还没有设置 DataContext。我在网格中定义了四行,它们应该显示 ItemClass 中的字段。
如何在工具提示中设置 DataContext,以便我可以绑定到显示工具提示的网格中项目的属性?
如果我没看错您的示例,ListView
位于 Window.Resources
中 DataTemplate
的 Grid
的第三列内。如果是这种情况并且您想访问 Grid 的 DataContext
,您应该可以使用 TemplatedParent
。在 GridViewColumn.CellTemplate
对于 ListView
:
<DataTemplate>
<TextBlock DataContext={Binding RelativeSouce={RelativeSource TemplatedParent}} Text="{Binding Path=mainProperty_2}">
<TextBlock.ToolTip>
<ToolTip Style="{StaticResource ItemTooltip}" />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
...或类似的东西。
工具提示 属性 是一个对象,因此您可以只使用 Setter.Value 语法:
<Setter Property="ToolTip">
<Setter.Value>
<Grid...>
</Grid>
</Setter.Value>
</Setter>
工具提示将通过 ContentPresenter 呈现,因此其中的任何内容都会正确显示。
感谢@sledgehammer。
我已将网格的定义从 Window.Resources 移到 ListView 定义中:
<ListView ItemsSource="{Binding Items}">
<!-- This way of making a tooltip works, but it isn't really what I want -->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip">
<Setter.Value>
<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>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<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>
太棒了。这符合我最初的要求。
如果样式被定义为资源,我仍然会感兴趣是否有办法做到这一点,但这只是学术上的。
当您只是盲目地定位工具提示时,绑定将不起作用,因为 {Binding} 将指向工具提示本身,而不是 ListViewItem。您的 Style 解决方案将起作用,但您需要使用 RelativeSource 绑定来追踪 ListViewItem ...或者对于某些语法糖,您可以将样式中工具提示的 DataContext 绑定到具有 RelativeSource 绑定的 ListViewItem,然后{Binding} 将在整个样式中起作用,但您将失去绑定到工具提示属性的能力。
我想在 WPF ListView 中显示项目列表,并使用工具提示显示列表中项目的其他详细信息。
我制作了一个示例项目,您可以从 http://www.jollans.com/WpfTooltipTest.zip
下载对于示例,我制作了一个具有某些属性的 class:
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; }
}
以及包含这些项目列表的模型
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" } ) ;
}
}
主要window只是实例化模型并将其设置为DataContext
public partial class MainWindow : Window
{
private Model _model ;
public MainWindow()
{
InitializeComponent();
_model = new Model() ;
this.DataContext = _model ;
}
}
基本的ListView是这样的:
<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>
但这没有任何工具提示。
我知道一种方法是添加如下内容:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip" Value="{Binding Path=detailProperty_1}" />
</Style>
</ListView.ItemContainerStyle>
它显示了 ItemClass 中的单个 属性,但我想要更详细的东西。
我定义了一个包含网格作为工具提示的样式资源:
<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>
我用一个 TextBlock 向网格添加了第三列,它使用了这个工具提示。
<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>
(我真的不想要 TextBlock,但这不是这个问题的主题。)
显示工具提示并显示网格,但绑定不起作用,因为我还没有设置 DataContext。我在网格中定义了四行,它们应该显示 ItemClass 中的字段。
如何在工具提示中设置 DataContext,以便我可以绑定到显示工具提示的网格中项目的属性?
如果我没看错您的示例,ListView
位于 Window.Resources
中 DataTemplate
的 Grid
的第三列内。如果是这种情况并且您想访问 Grid 的 DataContext
,您应该可以使用 TemplatedParent
。在 GridViewColumn.CellTemplate
对于 ListView
:
<DataTemplate>
<TextBlock DataContext={Binding RelativeSouce={RelativeSource TemplatedParent}} Text="{Binding Path=mainProperty_2}">
<TextBlock.ToolTip>
<ToolTip Style="{StaticResource ItemTooltip}" />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
...或类似的东西。
工具提示 属性 是一个对象,因此您可以只使用 Setter.Value 语法:
<Setter Property="ToolTip">
<Setter.Value>
<Grid...>
</Grid>
</Setter.Value>
</Setter>
工具提示将通过 ContentPresenter 呈现,因此其中的任何内容都会正确显示。
感谢@sledgehammer。
我已将网格的定义从 Window.Resources 移到 ListView 定义中:
<ListView ItemsSource="{Binding Items}">
<!-- This way of making a tooltip works, but it isn't really what I want -->
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ToolTip">
<Setter.Value>
<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>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<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>
太棒了。这符合我最初的要求。
如果样式被定义为资源,我仍然会感兴趣是否有办法做到这一点,但这只是学术上的。
当您只是盲目地定位工具提示时,绑定将不起作用,因为 {Binding} 将指向工具提示本身,而不是 ListViewItem。您的 Style 解决方案将起作用,但您需要使用 RelativeSource 绑定来追踪 ListViewItem ...或者对于某些语法糖,您可以将样式中工具提示的 DataContext 绑定到具有 RelativeSource 绑定的 ListViewItem,然后{Binding} 将在整个样式中起作用,但您将失去绑定到工具提示属性的能力。