好的,工作中的一位朋友主要为我解决了这个问题。这种方式超级干净,不会觉得hacky。
这是基本问题:正如 user164184 所提到的,工具提示是弹出窗口,因此不是可视化树的一部分。因此,WPF 有一些魔力。弹出窗口的 DataContext 来自 PlacementTarget,这是绑定大部分时间的工作方式,尽管弹出窗口不是树的一部分。但是,当您更改 PlacementTarget 时,它会覆盖默认值,现在 DataContext 来自新的 PlacementTarget,无论它是什么。
完全不直观。如果 MSDN 有,而不是花费数小时构建所有那些显示不同工具提示出现位置的漂亮图表,而是说出关于 DataContext 发生了什么的一句话,那就太好了。
不管怎样,继续解决!与所有有趣的 WPF 技巧一样,附加属性可以提供帮助。我们将添加两个附加属性,以便在生成工具提示时直接设置工具提示的 DataContext。
public static class BindableToolTip
{
public static readonly DependencyProperty ToolTipProperty = DependencyProperty.RegisterAttached(
"ToolTip", typeof(FrameworkElement), typeof(BindableToolTip), new PropertyMetadata(null, OnToolTipChanged));
public static void SetToolTip(DependencyObject element, FrameworkElement value) { element.SetValue(ToolTipProperty, value); }
public static FrameworkElement GetToolTip(DependencyObject element) { return (FrameworkElement)element.GetValue(ToolTipProperty); }
static void OnToolTipChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
{
ToolTipService.SetToolTip(element, e.NewValue);
if (e.NewValue != null)
{
((ToolTip)e.NewValue).DataContext = GetDataContext(element);
}
}
public static readonly DependencyProperty DataContextProperty = DependencyProperty.RegisterAttached(
"DataContext", typeof(object), typeof(BindableToolTip), new PropertyMetadata(null, OnDataContextChanged));
public static void SetDataContext(DependencyObject element, object value) { element.SetValue(DataContextProperty, value); }
public static object GetDataContext(DependencyObject element) { return element.GetValue(DataContextProperty); }
static void OnDataContextChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
{
var toolTip = GetToolTip(element);
if (toolTip != null)
{
toolTip.DataContext = e.NewValue;
}
}
}
然后在 XAML 中:
<Grid ...>
<TextBlock x:Name="ObjectText"
ToolTipService.Placement="Left"
ToolTipService.PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
mystuff:BindableToolTip.DataContext="{Binding}">
<mystuff:BindableToolTip.ToolTip>
<ToolTip>
<StackPanel>
<TextBlock Text="{Binding DisplayName.Name}"/>
<TextBlock Text="{Binding Details}" FontStyle="Italic"/>
...
</StackPanel>
</ToolTip>
</mystuff:BindableToolTip.ToolTip>
</TextBlock>
...
只需将ToolTip 切换到BindableToolTip.ToolTip,然后添加一个新的BindableToolTip.DataContext,它指向你想要的任何东西。我只是将它设置为当前的 DataContext,所以它最终继承了绑定到 DataTemplate 的视图模型。
请注意,我嵌入了工具提示,而不是使用静态资源。这是我原来的问题中的一个错误。显然必须为每个项目生成唯一的。另一种选择是使用 ControlTemplate Style 触发器。
一项改进可能是让 BindableToolTip.DataContext 注册以获取有关 ToolTip 更改的通知,然后我可以摆脱 BindableToolTip.ToolTip。改天的任务!