WPF Показывает данные из нескольких DataContexts во всплывающей подсказке ItemsControl

StackOverflow https://stackoverflow.com/questions/1825765

Вопрос

Я пытаюсь отобразить всплывающую подсказку для элемента, сгенерированного 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, но любая помощь была бы очень признательна!

Это было полезно?

Решение

После часа напряженной работы я пришел к выводу, что нельзя ссылаться на другой DataContext внутри DataTemplate для всплывающей подсказки . Для других Привязок это вполне возможно, как показали другие постеры. Вот почему вы не можете использовать трюк 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;}
     }
}

Другие советы

Вторая попытка

Хорошо, в этом случае относительная привязка источника не работает . Это на самом деле работает из шаблона данных, вы можете найти много примеров этого в Интернете. Но здесь (вы были правы, Дэвид, в вашем комментарии) ToolTip - это специальный зверь, который неправильно размещен в VisualTree (это свойство, а не элемент управления как таковой), и он не имеет доступа к нужной области имен для использовать относительную привязку.

После еще одного поиска я нашел эту статью , в которой подробно описывается этот эффект и предлагает реализацию BindableToolTip.

Это может быть излишним, потому что у вас есть другие варианты - например, использование статического свойства в классе (как в ответе Dabblernl) или добавление нового свойства экземпляра в ваш Item .

Первая попытка:)

Вам следует проконсультироваться с типами относительной привязки источника (в этой шпаргалке пример):

Итак, ваша привязка будет выглядеть примерно так:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path= GlobalText}

Почти правильный Yacoder, и, как оказалось, не прав Dabblernl;)

Ваш образ мышления правильный, и можно ссылаться на DataContext вашего ItemsControl

Вам не хватает свойства 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

Вот статья с той же проблемой. Они могут ссылаться на DataContext своего родительского элемента управления с помощью свойства PlacementTarget:

<ToolTip DataContext=”{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Parent}”>

Если вы поместите DataContext на более глубокий уровень, вы не будете менять свой ItemContext

  

Второе предложение (Нил и Адам Смит) состояло в том, что мы можем использовать PlacementTarget в привязке. Это хорошо, поскольку я на самом деле наследую DataContext уже со страницы, на которой размещен DataControl, и это позволило бы всплывающей подсказке получить доступ обратно к исходному элементу управления. Однако, как заметил Адам, вы должны знать о структуре родительских / дочерних элементов вашей разметки:

Это тот случай, когда я думаю, что концептуально более целесообразно делать это в модели представления, чем в любом случае. Предоставьте информацию всплывающей подсказки представлению как свойство элемента модели представления. Это позволяет представлению делать то, что у него хорошо (представление свойств элемента), а модель представления - то, что у него получается (решать, какую информацию следует представлять).

У меня была очень похожая проблема, и я пришел к этому вопросу в поисках ответов.В конце концов я пришел к другому решению, которое сработало в моем случае и может быть полезно другим.

В моем решении я добавил свойство к дочернему элементу, которое ссылается на родительскую модель, и заполнил его при создании дочерних элементов.В 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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top