我正在尝试显示由ItemsControl
生成的项目的工具提示,该项目需要从概念上不相关的来源提取数据。例如,假设我有一个Item类,如下所示:
public class Item
{
public string ItemDescription { get; set; }
public string ItemName { get; set; }
}
我可以使用工具提示在ItemsControl中显示Item,如下所示:
<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>
但是说我有另一个属性可以通过DataContext
的{{1}}访问。有没有办法从工具提示中做到这一点?如,
ItemsControl
我使用的测试窗口的代码如下:
<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>
所以在这个例子中我想显示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; }
}
属性的值(实际上这将是另一个自定义对象)。
为了使问题复杂化,我实际上正在使用DataTemplates并在ItemsControl中显示两种不同类型的对象,但是非常感谢任何帮助!
答案 0 :(得分:3)
经过一个小时的拔毛后,我确信您无法在DataTemplate 中为ToolTip 引用另一个DataContext。对于其他Bindings,其他海报已经证明是完全可能的。这就是为什么你也不能使用RelativeSource技巧。你可以做的是在你的Item类上实现一个静态属性,并引用 :
<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;}
}
}
答案 1 :(得分:1)
好的,相对来源绑定在这种情况下不起作用 。它实际上来自数据模板,你可以在互联网上找到很多这方面的例子。但是在这里(你是对的,大卫,在你的评论中)ToolTip是一个特殊的野兽,没有正确放置在VisualTree中(它是一个属性,而不是一个控件本身),并且它无法访问正确的名称范围使用相对绑定。
经过一些搜索后,我找到了this article,它详细描述了这种效果,并提出了一个BindableToolTip的实现。
这可能是一种矫枉过正,因为你有其他选择 - 比如在类上使用静态属性(如在Dabblernl的响应中)或向Item
添加新的实例属性。
您应该参考相对来源绑定类型(例如,在this cheat sheet中):
所以你的绑定看起来与此类似:
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path= GlobalText}
答案 2 :(得分:1)
几乎正确的Yacoder,并且在那里猜错了Dabblernl;)
您的思维方式是正确的,可以引用ItemsControl的DataContext
您缺少路径中的DataContext属性:
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.GlobalText}
第二次尝试;)
http://blogs.msdn.com/tom_mathews/archive/2006/11/06/binding-a-tooltip-in-xaml.aspx
这是一篇有同样问题的文章。他们可以通过PlacementTarget属性引用其父控件的DataContext:
<ToolTip DataContext=”{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Parent}”>
如果要将DataContext放在更深层次上,则应避免更改Item DataContext
第二个建议(Neil和Adam Smith)是我们可以在绑定中使用PlacementTarget。这很好,因为我实际上已经从承载DataControl的页面继承了DataContext,这将允许ToolTip获得对原始控件的访问权限。但是,正如亚当指出的那样,您必须了解标记中的父/子结构:
答案 3 :(得分:1)
在这种情况下,我认为在概念上,在视图模型中执行此操作比在视图中更合适。将工具提示信息作为视图模型项的属性公开给视图。这样可以让视图完成它所擅长的功能(呈现项目的属性),并且视图模型可以做它擅长的事情(决定应该呈现哪些信息)。
答案 4 :(得分:1)
我遇到了一个非常类似的问题并且在这个问题上找到了答案。最后,我提出了一个不同的解决方案,在我的案例中起作用,可能对其他人有用。
在我的解决方案中,我向引用父模型的子项添加了一个属性,并在生成子项时填充它。在ToolTip的XAML中,我只是在每个元素的父模型中引用该属性,并将DataContext设置为父模型属性。
我觉得这个解决方案比在XAML中创建代理元素并引用它们更为舒服。
使用此问题的示例代码,您将执行以下操作。注意我没有在编译器中测试过这种情况,但是已经在我自己的场景的代码中成功实现了这个解决方案。
项目:
public class Item
{
public List<Item> Parent { get; set; }
public string ItemDescription { get; set; }
public string ItemName { get; set; }
}
窗口:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
List<Item> itemList = new List<Item>();
itemList.Add(new Item() { Parent = this, ItemName = "First Item", ItemDescription = "This is the first item." });
itemList.Add(new Item() { Parent = this, 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; }
}
XAML:
<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" DataContext={Binding Parent} Text="{Bind this to aproperty of the parent data model}" />
</Grid>
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>