如何设置一个WPF工具提示PlacementTarget没有搞乱DataContext的? [英] How to set a PlacementTarget for a WPF tooltip without messing up the DataContext?

查看:210
本文介绍了如何设置一个WPF工具提示PlacementTarget没有搞乱DataContext的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有列表框和VM + DataTemplate中和项目虚拟机的典型MVVM设置。该数据模板工具提示,其中有绑定到项目VM的元素。所有的伟大工程。

I have a typical MVVM setup of Listbox and vm + DataTemplate and item vm's. The data templates have tooltips, which have elements bound to the item vm's. All works great.

现在,我想有提示置于相对于列表框本身。这是相当大的时候随便鼠标放在列表框的方式获得。所以,我想我会做这样的事情在DataTemplate中:

Now, I'd like to have the tooltip placed relative to the listbox itself. It's fairly large and gets in the way when casually mousing over the listbox. So I figured I'd do something like this in the DataTemplate:

<Grid ...>
    <TextBlock x:Name="ObjectText"
        ToolTipService.Placement="Left"
        ToolTip="{StaticResource ItemToolTip}"
        ToolTipService.PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}">
    </TextBlock>
...



...与静态资源...

...with the static resource...

<ToolTip x:Key="ItemToolTip">
    <StackPanel>
        <TextBlock Text="{Binding DisplayName.Name}"/>
        <TextBlock Text="{Binding Details}" FontStyle="Italic"/>
        ...
    </StackPanel>
</ToolTip>

下面是我的问题。当我使用PlacementTarget我得到一个绑定错误的DisplayName.Name和细节不具有约束力。 。它试图绑定到的对象不是该项目的VM但总体列表框虚拟机

Here's my problem. When I use that PlacementTarget I get a binding error that the DisplayName.Name and Details are not binding. The object it's trying to bind to is not the item vm but the overall Listbox vm.

所以我的问题是:如何可以设置ToolTipService.PlacementTarget了还提示保持在DataContext从它的主人遗传吗?

So my question is: how can I set the ToolTipService.PlacementTarget for a tooltip yet keep the DataContext inherited from its owner?

推荐答案

好吧,一个朋友在工作大多是想通了我。这种方法是超洁净,不觉得哈克

Ok, a friend at work mostly figured it out for me. This way is super clean, doesn't feel hacky.

下面是基本的问题:作为user164184所说,提示是弹出窗口,因此不可视树的一部分。因此,有一些神奇的WPF一样。为弹出在DataContext来自PlacementTarget,这是绑定是如何工作的大部分时间,尽管弹出不是该树的一部分。但是,当你改变PlacementTarget这将覆盖默认的,现在的DataContext从新PlacementTarget,不管它可能是未来。

Here's the basic problem: as user164184 mentioned, tooltips are popups and therefore not part of the visual tree. So there's some magic that WPF does. The DataContext for the popup comes from the PlacementTarget, which is how the bindings work most of the time, despite the popup not being part of the tree. But when you change the PlacementTarget this overrides the default, and now the DataContext is coming from the new PlacementTarget, whatever it may be.

完全不直观。这将是很好,如果MSDN了,而不是花费数小时建筑物的不同工具提示出现,所有这些漂亮的图表,说什么用的DataContext发生一句话。

Totally not intuitive. It would be nice if MSDN had, instead of spending hours building all those pretty graphs of where the different tooltips appear, said one sentence about what happens with the DataContext.

不管怎样,到解决方案!如同所有的乐趣WPF招数,附加属性前来救援。我们要增加两个附加属性,所以我们可以直接设置时的产生的它提示的DataContext的。

Anyway, on to the SOLUTION! As with all fun WPF tricks, attached properties come to the rescue. We're going to add two attached properties so we can directly set the DataContext of the tooltip when it's generated.

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:

And then in the 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>
...



只是切换工具提示 BindableToolTip.ToolTip 代替,然后添加一个新的 BindableToolTip.DataContext 这点,任何你想要的。我只是将它设置为当前DataContext的,所以它最终继承绑定到DataTemplate中的视图模型。

Just switch the ToolTip over to BindableToolTip.ToolTip instead, then add a new BindableToolTip.DataContext that points at whatever you want. I'm just setting it to the current DataContext, so it ends up inheriting the viewmodel bound to the DataTemplate.

请注意,我的嵌入式工具提示而不是使用静态资源的。那是在我原来的问题的错误。显然已经将要生成每个项目是唯一的。另一种选择是使用控件模板样式触发啄。

Note that I embedded the ToolTip instead of using a StaticResource. That was a bug in my original question. Obviously has to be generated unique per item. Another option would be to use a ControlTemplate Style trigger thingy.

一个改进可能是有BindableToolTip.DataContext有关工具提示变化通知注册,那么我可以摆脱BindableToolTip.ToolTip。一种新的一天的任务!

One improvement could be to have BindableToolTip.DataContext register for notifications on the ToolTip changing, then I could get rid of BindableToolTip.ToolTip. A task for another day!

这篇关于如何设置一个WPF工具提示PlacementTarget没有搞乱DataContext的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆