Question

J'essaie d'afficher une info-bulle pour un élément généré par un ItemsControl devant extraire des données de sources non liées conceptuellement. Par exemple, supposons que j'ai une classe Item comme suit:

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

Je peux afficher l'élément dans un ItemsControl avec une info-bulle comme suit:

<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>

Mais disons que j'ai une autre propriété accessible via le DataContext du ItemsControl . Y a-t-il un moyen de faire cela depuis l'infobulle? Par exemple,

<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>

Le code de la fenêtre de test que j'ai utilisée est le suivant:

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

Donc, dans cet exemple, je souhaite afficher la valeur de la propriété GlobalText (il s'agirait en réalité d'un autre objet personnalisé).

Pour compliquer les choses, j'utilise en fait DataTemplates et affiche deux types d'objets différents dans ItemsControl, mais toute aide serait grandement appréciée!

Était-ce utile?

La solution

Après une heure de travail, je suis convaincu que vous ne pouvez pas faire référence à un autre DataContext dans un DataTemplate pour une info-bulle . Pour d’autres reliures, c’est parfaitement possible comme d’autres affiches l’ont prouvé. C'est pourquoi vous ne pouvez pas non plus utiliser l'astuce RelativeSource. Ce que vous pouvez faire est d’implémenter une propriété statique dans votre classe d’élément et de référencer ce :

.
<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;}
     }
}

Autres conseils

Deuxième tentative

Bien, la liaison de source relative ne fonctionne pas dans ce cas . Cela fonctionne réellement à partir d'un modèle de données, vous pouvez trouver de nombreux exemples sur Internet. Mais ici (vous aviez raison, David, dans votre commentaire) ToolTip est une bête spéciale qui n'est pas placée correctement dans VisualTree (c'est une propriété, pas un contrôle en tant que tel) et elle n'a pas accès à la portée du nom approprié. utilisez la liaison relative.

Après quelques recherches supplémentaires, j'ai trouvé cet article , qui décrit cet effet en détail et propose une implémentation d'un BindableToolTip.

Cela peut être une surcharge, car vous avez d'autres options, comme utiliser une propriété statique sur une classe (comme dans la réponse de Dabblernl) ou ajouter une nouvelle propriété d'instance à votre Item .

Première tentative:)

Vous devriez consulter les types de liaison de source relative (dans cette aide-mémoire pour exemple):

Votre liaison ressemblera donc à ceci:

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

Presque corrigez Yacoder, et devinez bien, Dabblernl;)

Votre façon de penser est correcte et il est possible de référencer le DataContext de votre ItemsControl

Il vous manque la propriété DataContext dans le chemin:

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

Deuxième tentative;)

http: / /blogs.msdn.com/tom_mathews/archive/2006/11/06/binding-a-tooltip-in-xaml.aspx

Voici un article avec le même problème. Ils peuvent référencer le DataContext de leur contrôle parent par la propriété PlacementTarget:

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

Si vous souhaitez placer le DataContext à un niveau plus profond, vous évitez de modifier votre Item DataContext

.
  

Une deuxième suggestion (Neil et Adam Smith) était que nous pouvions utiliser PlacementTarget dans la liaison. C’est bien, car j’hérite déjà du DataContext de la page qui héberge le DataControl, ce qui permettrait à l’Info-bulle d’avoir accès au contrôle original. Comme Adam l’a noté, vous devez connaître la structure parent / enfant de votre balise:

C’est un cas où, à mon avis, il est plus approprié conceptuellement de faire cela dans le modèle de vue que de toute façon dans la vue. Exposez les informations de l'info-bulle à la vue en tant que propriété de l'élément de modèle de vue. Cela permet à la vue de faire ce qu’elle fait de bien (présenter les propriétés de l’article) et au modèle de vue de faire ce qu’elle est de bien (décider des informations à présenter).

J'ai eu un problème très similaire et je suis arrivé à cette question à la recherche de réponses. À la fin, j’ai trouvé une solution différente qui a fonctionné dans mon cas et qui pourrait être utile à d’autres.

Dans ma solution, j'ai ajouté une propriété à l'élément enfant qui fait référence au modèle parent et je l'ai renseignée lorsque les enfants ont été générés. Dans le code XAML de l'info-bulle, j'ai simplement référencé la propriété du modèle parent sur chaque élément et défini le DataContext sur la propriété du modèle parent.

Je me sentais plus à l'aise avec cette solution que de créer des éléments proxy en XAML et de les référencer.

En utilisant l'exemple de code pour cette question, procédez comme suit. Remarque Je n'ai pas testé ce scénario dans un compilateur, mais j'ai réussi à implémenter cette solution dans le code de mon propre scénario.

Article:

public class Item
{
    public List<Item> Parent { get; set; }
    public string ItemDescription { get; set; }
    public string ItemName { get; set; }
}

Fenêtre:

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>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top