Condividi tramite


Eseguire il binding di dati gerarchici e creare una visualizzazione master/dettagli con SDK per app di Windows

Nota

Vedi anche l'esempio UWP master/dettagli.

Puoi creare una visualizzazione master/dettagli multilivello (anche nota come elenco/dettagli) di dati gerarchici associando controlli elementi a istanze CollectionViewSource associate in una catena. In questo argomento viene usata l'estensione di markup {x:Bind} quando possibile e l'estensione di markup {Binding}, più flessibile ma con prestazioni inferiori, quando necessario.

In base a un modello comune delle app con SDK per app di Windows, quando un utente effettua una selezione in un elenco master vengono visualizzate pagine dei dettagli differenti. Questo è utile per offrire una rappresentazione visiva dettagliata dei vari elementi inclusi in ogni livello di una gerarchia. Un'altra opzione consiste nel visualizzare più livelli di dati in una singola pagina. Questa modalità è consigliabile se vuoi visualizzare alcuni elenchi semplici per consentire agli utenti di eseguire rapidamente il drill-down in un elemento di interesse. Questo argomento descrive come implementare l'interazione. Le istanze CollectionViewSource tengono traccia della selezione corrente a ogni livello gerarchico.

Creeremo una visualizzazione di una gerarchia per una squadra sportiva organizzata in elenchi per serie, divisioni e squadre, con una visualizzazione dettagliata delle squadre. Quando si seleziona un elemento in un elenco, le visualizzazioni successive vengono aggiornate automaticamente.

visualizzazione master/dettagli di una gerarchia sportiva

Prerequisiti

In questo argomento si presuppone che si sappia come creare una semplice app con SDK per app di Windows. Per istruzioni su come creare la prima app con SDK per app di Windows, vedere Creare il primo progetto WinUI 3 (SDK per app di Windows).

Creare il progetto

Creare un nuovo progetto App vuota, pacchetto (WinUI 3 in Desktop). Denominarla "MasterDetailsBinding".

Creare il modello di dati

Aggiungere una nuova classe al progetto, denominarla ViewModel.cs e aggiungere questo codice. Questa sarà la classe dell'origine di binding.

using System.Collections.Generic;
using System.Linq;

namespace MasterDetailsBinding
{
    public class Team
    {
        public string Name { get; set; }
        public int Wins { get; set; }
        public int Losses { get; set; }
    }

    public class Division
    {
        public string Name { get; set; }
        public IEnumerable<Team> Teams { get; set; }
    }

    public class League
    {
        public string Name { get; set; }
        public IEnumerable<Division> Divisions { get; set; }
    }

    public class LeagueList : List<League>
    {
        public LeagueList()
        {
            AddRange(GetLeague().ToList());
        }

        public IEnumerable<League> GetLeague()
        {
            return from x in Enumerable.Range(1, 2)
                   select new League
                   {
                       Name = "League " + x,
                       Divisions = GetDivisions(x).ToList()
                   };
        }

        public IEnumerable<Division> GetDivisions(int x)
        {
            return from y in Enumerable.Range(1, 3)
                   select new Division
                   {
                       Name = string.Format("Division {0}-{1}", x, y),
                       Teams = GetTeams(x, y).ToList()
                   };
        }

        public IEnumerable<Team> GetTeams(int x, int y)
        {
            return from z in Enumerable.Range(1, 4)
                   select new Team
                   {
                       Name = string.Format("Team {0}-{1}-{2}", x, y, z),
                       Wins = 25 - (x * y * z),
                       Losses = x * y * z
                   };
        }
    }
}

Creare la visualizzazione

Esporre quindi la classe dell'origine di binding dalla classe che rappresenta la pagina del markup. È possibile eseguire questa operazione aggiungendo una proprietà di tipo LeagueList a MainWindow.

namespace MasterDetailsBinding
{
    public sealed partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            ViewModel = new LeagueList();
        }
        public LeagueList ViewModel { get; set; }
    }
}

Infine, sostituire il contenuto del file MainWindow.xaml con il markup seguente, che dichiara tre istanze CollectionViewSource e le associa in una catena. I controlli successivi possono quindi associare l'oggetto CollectionViewSource corretto a seconda del relativo livello nella gerarchia.

<Window
    x:Class="MasterDetailsBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MasterDetailsBinding"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.Resources>
            <CollectionViewSource x:Name="Leagues"
                Source="{x:Bind ViewModel}"/>
            <CollectionViewSource x:Name="Divisions"
                Source="{Binding Divisions, Source={StaticResource Leagues}}"/>
            <CollectionViewSource x:Name="Teams"
                Source="{Binding Teams, Source={StaticResource Divisions}}"/>
    
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="15"/>
                <Setter Property="FontWeight" Value="Bold"/>
            </Style>
            <Style TargetType="ListBox">
                <Setter Property="FontSize" Value="15"/>
            </Style>
            <Style TargetType="ContentControl">
                <Setter Property="FontSize" Value="15"/>
            </Style>
        </Grid.Resources>

        <StackPanel Orientation="Horizontal">

            <!-- All Leagues view -->
            <StackPanel Margin="5">
                <TextBlock Text="All Leagues"/>
                <ListBox ItemsSource="{Binding Source={StaticResource Leagues}}" 
                         DisplayMemberPath="Name"/>
            </StackPanel>

            <!-- League/Divisions view -->
            <StackPanel Margin="5">
                <TextBlock Text="{Binding Name, Source={StaticResource Leagues}}"/>
                <ListBox ItemsSource="{Binding Source={StaticResource Divisions}}" 
                         DisplayMemberPath="Name"/>
            </StackPanel>

            <!-- Division/Teams view -->
            <StackPanel Margin="5">
                <TextBlock Text="{Binding Name, Source={StaticResource Divisions}}"/>
                <ListBox ItemsSource="{Binding Source={StaticResource Teams}}" 
                         DisplayMemberPath="Name"/>
            </StackPanel>

            <!-- Team view -->
            <ContentControl Content="{Binding Source={StaticResource Teams}}">
                <ContentControl.ContentTemplate>
                    <DataTemplate>
                        <StackPanel Margin="5">
                            <TextBlock Text="{Binding Name}" 
                                       FontSize="15" FontWeight="Bold"/>
                            <StackPanel Orientation="Horizontal" Margin="10,10">
                                <TextBlock Text="Wins:" Margin="0,0,5,0"/>
                                <TextBlock Text="{Binding Wins}"/>
                            </StackPanel>
                            <StackPanel Orientation="Horizontal" Margin="10,0">
                                <TextBlock Text="Losses:" Margin="0,0,5,0"/>
                                <TextBlock Text="{Binding Losses}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ContentControl.ContentTemplate>
            </ContentControl>
        </StackPanel>
    </Grid>
</Window>

Si tenga presente che eseguendo il binding direttamente a CollectionViewSource, si sta implicando che si vuole associare l'elemento corrente nei binding in cui non è possibile trovare il percorso nella raccolta stessa. Non è necessario specificare la proprietà CurrentItem come percorso per il binding, ma è possibile farlo se esiste un'ambiguità. Ad esempio, ContentControl che rappresenta la visualizzazione team ha la proprietà Content associata a Teams CollectionViewSource. Tuttavia, i controlli in DataTemplate si associano a proprietà della classe Team perché CollectionViewSource fornisce automaticamente il team attualmente selezionato nell'elenco, quando necessario.

Vedi anche