Domanda

Sto cercando di visualizzare una descrizione di un elemento generato da un ItemsControl che deve estrarre dati da fonti concettualmente non correlate. Ad esempio, supponiamo che io abbia una classe Item come segue:

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

Posso visualizzare l'elemento all'interno di un ItemsControl con una descrizione comando come segue:

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

Ma supponiamo di avere un'altra proprietà a cui è possibile accedere tramite DataContext di ItemsControl . C'è un modo per farlo dall'interno della descrizione comando? Per es.,

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

Il codice per la finestra di test che ho usato è il seguente:

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

Quindi in questo esempio voglio mostrare il valore della proprietà GlobalText (in realtà questo sarebbe un altro oggetto personalizzato).

Per complicare le cose, in realtà sto usando DataTemplates e mostrerò due diversi tipi di oggetti all'interno di ItemsControl, ma qualsiasi assistenza sarebbe molto apprezzata!

È stato utile?

Soluzione

Dopo un'ora di capelli mi sono convinto che non puoi fare riferimento a un altro DataContext all'interno di un DataTemplate per una descrizione comandi . Per altri attacchi è perfettamente possibile, come hanno dimostrato altri poster. Ecco perché non puoi nemmeno usare il trucco RelativeSource. Quello che puoi fare è implementare una proprietà statica sulla tua classe Item e fare riferimento a che :

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

Altri suggerimenti

Secondo tentativo

Ok, il binding della fonte relativa non funziona in questo caso . Funziona in realtà da un modello di dati, puoi trovarne molti esempi su Internet. Ma qui (avevi ragione, David, nel tuo commento) ToolTip è una bestia speciale che non è posizionata correttamente in VisualTree (è una proprietà, non un controllo in sé) e non ha accesso all'ambito del nome corretto per usa l'associazione relativa.

Dopo qualche altra ricerca ho trovato questo articolo , che descrive questo effetto in dettaglio e propone un'implementazione di un BindableToolTip.

Potrebbe essere eccessivo, perché hai altre opzioni - come usare una proprietà statica su una classe (come nella risposta di Dabblernl) o aggiungere una nuova proprietà di istanza al tuo Item .

Primo tentativo :)

Dovresti consultare i tipi di Binding delle fonti relative (in questo cheat sheet per esempio):

Quindi la tua rilegatura sarà in qualche modo simile a questa:

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

Quasi corretto Yacoder, e indovinato in modo sbagliato lì Dabblernl;)

Il tuo modo di pensare è corretto ed è possibile fare riferimento al DataContext del tuo ItemsControl

Manca la proprietà DataContext nel percorso:

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

Secondo tentativo;)

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

Ecco un articolo con lo stesso problema. Possono fare riferimento a DataContext del controllo Parent mediante la proprietà PlacementTarget:

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

Se si posizionasse DataContext a un livello più profondo, si eviterebbe di modificare il DataContext dell'articolo

  

Un secondo suggerimento (Neil e Adam Smith) era che potevamo usare PlacementTarget nella rilegatura. Questo è carino, dato che in realtà sto ereditando DataContext già dalla pagina che ospita DataControl, e ciò consentirebbe a ToolTip di accedere nuovamente al controllo originale. Come ha notato Adam, però, devi essere consapevole della struttura genitore / figlio al di fuori del tuo markup:

Questo è un caso in cui penso che concettualmente sia più appropriato farlo nel modello di visualizzazione di quanto non lo sia comunque nella vista. Esporre le informazioni del suggerimento alla vista come proprietà dell'elemento del modello di vista. Ciò consente alla vista di fare ciò che è buono (presentando le proprietà dell'articolo) e il modello di vista di fare ciò che è buono (decidere quali informazioni devono essere presentate).

Ho avuto un problema molto simile e sono arrivato a questa domanda in cerca di risposte. Alla fine ho trovato una soluzione diversa che ha funzionato nel mio caso e può essere utile per gli altri.

Nella mia soluzione, ho aggiunto una proprietà all'elemento figlio che fa riferimento al modello principale e la ho popolata quando sono stati generati i figli. In XAML per la descrizione comandi, ho semplicemente fatto riferimento alla proprietà del modello principale su ciascun elemento e impostato DataContext sulla proprietà del modello principale.

Mi sono sentito più a mio agio con questa soluzione rispetto alla creazione di elementi proxy in XAML e al loro riferimento.

Usando il codice di esempio per questa domanda, faresti quanto segue. Nota Non ho testato questo scenario in un compilatore, ma ho implementato con successo questa soluzione nel codice per il mio scenario.

Articolo:

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

Finestra:

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>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top