好吧,工作中的一个朋友基本上帮我解决了这个问题。这种方式超级干净,不会感觉很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 的视图模型。
请注意,我嵌入了工具提示而不是使用 StaticResource。这是我原来的问题中的一个错误。显然每个项目必须生成唯一的。另一种选择是使用 ControlTemplate 样式触发器。
一项改进可能是让 BindableToolTip.DataContext 注册有关 ToolTip 更改的通知,然后我就可以摆脱 BindableToolTip.ToolTip。另一天的任务!