Binda hierarkiska data och skapa en huvud-/informationsvy med WinUI

Lär dig hur du skapar en huvud-/informationsvy på flera nivåer av hierarkiska data i WinUI genom att binda objektkontroller till CollectionViewSource-instanser . Den här artikeln beskriver hur du använder markeringstillägget {x:Bind} för bättre prestanda och {Binding}-markeringstillägget när det behövs flexibilitet.

En vanlig struktur för WinUI-appar är att navigera till olika informationssidor när en användare gör ett val i en huvudlista. Den här strukturen är användbar när du vill tillhandahålla en omfattande visuell representation av varje objekt på varje nivå i en hierarki. Ett annat alternativ är att visa flera datanivåer på en enda sida. Den här strukturen är användbar när du vill visa några enkla listor som gör att användaren snabbt kan öka detaljnivån till ett objekt av intresse. I den här artikeln beskrivs hur du implementerar den här interaktionen. CollectionViewSource-instanserna håller koll på det aktuella valet i varje hierarkiskt skikt.

Du skapar en vy över en sportlagshierarki som är organiserad i listor för ligor, divisioner och lag och innehåller en gruppinformationsvy. När du väljer ett objekt från en lista uppdateras efterföljande vyer automatiskt.

Skärmbild av en huvud-/informationsvy över en sporthierarki. Vyn innehåller ligor, divisioner och lag.

Tips/Råd

Se även UWP-exemplet master/detail.

Förutsättningar

Den här artikeln förutsätter att du vet hur du skapar en grundläggande WinUI-app. Anvisningar om hur du skapar din första WinUI-app finns i Skapa en WinUI-app.

Skapa projektet

Skapa en ny tom app, paketerad (WinUI 3 i Desktop) projekt. Ge den namnet "MasterDetailsBinding".

Skapa datamodellen

Lägg till en ny klass i projektet, ge det namnet ViewModel.cs och lägg till den här koden i det. Den här klassen är din bindningskälla.

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

Skapa vyn

Exponera sedan bindningskällans klass från klassen som representerar din sida med kod. Lägg till en egenskap av typen LeagueListi MainWindow.

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

Ersätt slutligen innehållet i filen MainWindow.xaml med följande markering. Den här markeringen deklarerar tre CollectionViewSource-instanser och binder dem samman i en kedja. De följande kontrollerna kan sedan binda till den lämpliga CollectionViewSource, beroende på dess nivå i hierarkin.

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

När du binder direkt till CollectionViewSource antyder du att du vill binda till det aktuella objektet i bindningar där sökvägen inte kan hittas i själva samlingen. Du behöver inte ange CurrentItem egenskapen som sökväg för bindningen, även om du kan lägga till den om det finns tvetydigheter. Till exempel har ContentControl- som representerar teamvyn sin egenskap Content som är bunden till TeamsCollectionViewSource. Kontrollerna i DataTemplate binder dock till egenskaperna för klassen Team, eftersom CollectionViewSource automatiskt tillhandahåller det för närvarande valda teamet från teamlistan när det behövs.

Se även