7

我正在尝试为ItemsControl需要从概念上不相关的来源提取数据的项目显示工具提示。例如,假设我有一个 Item 类,如下所示:

public class Item
{
    public string ItemDescription { get; set; }
    public string ItemName { get; set; }
}

我可以使用工具提示在 ItemsControl 中显示项目,如下所示:

<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通过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; }
}

所以在这个例子中,我想显示GlobalText属性的值(实际上这将是另一个自定义对象)。

更复杂的是,我实际上使用了 DataTemplates 并在 ItemsControl 中显示了两种不同类型的对象,但我们将不胜感激任何帮助!

4

5 回答 5

3

经过一个小时的拉扯,我确信您不能在 DataTemplate中为 ToolTip引用另一个 DataContext 。正如其他海报所证明的那样,对于其他绑定是完全可能的。这就是为什么你也不能使用 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;}
     }
}
于 2009-12-01T13:23:59.360 回答
1

第二次尝试

好的,在这种情况下,相对源绑定不起作用。它实际上是通过数据模板工作的,您可以在 Internet 上找到许多这样的示例。但是在这里(你是对的,大卫,在你的评论中)工具提示是一个特殊的野兽,它没有正确放置在 VisualTree 中(它是一个属性,而不是一个控件本身)并且它无法访问正确的名称范围使用相对绑定。

经过一番搜索,我找到了这篇文章,它详细描述了这个效果,并提出了一个 BindableToolTip 的实现。

这可能有点矫枉过正,因为您还有其他选择——比如在类上使用静态属性(如 Dabblernl 的响应中所示)或将新的实例属性添加到您的Item.

第一次尝试 :)

您应该咨询相对源绑定类型(例如在此备忘单中):

因此,您的绑定看起来与此类似:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path= GlobalText}
于 2009-12-01T12:19:56.350 回答
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}”&gt;

如果您将 DataContext 放在更深的层次上,您可以避免更改您的 Item DataContext

第二个建议(Neil 和 Adam Smith)是我们可以在绑定中使用 PlacementTarget。这很好,因为我实际上已经从承载 DataControl 的页面继承了 DataContext,这将允许 ToolTip 重新获得对原始控件的访问权限。但是,正如 Adam 所指出的,您必须了解标记中的父/子结构:

于 2009-12-01T13:48:01.060 回答
1

在这种情况下,我认为在视图模型中执行此操作比在视图中执行此操作在概念上更合适。将工具提示信息作为视图模型项的属性公开给视图。这让视图做它擅长的事情(呈现项目的属性),而视图模型做它擅长的事情(决定应该呈现什么信息)。

于 2010-02-06T19:08:51.300 回答
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>
于 2013-06-28T03:58:04.093 回答