Поделиться через


Привязка иерархических данных и создание представления основных и подробных сведений с помощью пакета SDK для приложений Windows

Примечание.

См. также пример UWP master/detail.

Вы можете создать многоуровневое представление основных и подробных данных (также известное как список-подробности) иерархических данных путем привязки элементов управления элементами управления к экземплярам CollectionViewSource , связанным в цепочке. В этом разделе мы используем расширение разметки {x:Bind}, где это возможно, и более гибкое (но менее производительное) расширение разметки {Binding} при необходимости.

Одна из распространенных структур для приложений пакета SDK для приложений для Windows — переход к разным страницам сведений, когда пользователь делает выбор в главном списке. Это полезно, если требуется предоставить богатое визуальное представление каждого элемента на каждом уровне иерархии. Другим вариантом является отображение нескольких уровней данных на одной странице. Это полезно, если вы хотите отобразить несколько простых списков, которые позволяют пользователю быстро детализировать интересующий элемент. В этом разделе описывается, как реализовать это взаимодействие. Экземпляры CollectionViewSource отслеживают текущий выбор на каждом иерархическом уровне.

Мы создадим представление иерархии спортивной команды, которая организована в списки для лиг, подразделений и команд, и включает представление сведений о команде. При выборе элемента из любого списка последующие представления обновляются автоматически.

Представление master/details для спортивной иерархии

Необходимые компоненты

В этом разделе предполагается, что вы знаете, как создать базовое приложение пакета SDK для приложений Windows. Инструкции по созданию первого приложения пакета SDK для приложений Windows см. в статье "Создание первого проекта WinUI 3 (пакет SDK для приложений Windows).

Создание проекта

Создайте пустое приложение, упакованое (WinUI 3 в desktop). Присвойте ему имя MasterDetailsBinding.

Создание модели данных

Добавьте новый класс в проект, назовите его ViewModel.cs и добавьте в него код. Это будет класс источника привязки.

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

Создание представления

Затем предоставьте исходный класс привязки из класса, представляющего страницу разметки. Мы делаем это, добавив свойство типа LeagueList в MainWindow.

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

Наконец, замените содержимое файла MainWindow.xaml следующим разметкой, которая объявляет три экземпляра CollectionViewSource и привязывает их к цепочке. Затем последующие элементы управления могут привязаться к соответствующим CollectionViewSourceэлементам управления в зависимости от его уровня в иерархии.

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

Обратите внимание, что при привязке непосредственно к CollectionViewSource вы подразумеваете, что необходимо привязать к текущему элементу в привязках, где путь не найден в самой коллекции. Нет необходимости указывать CurrentItem свойство в качестве пути для привязки, хотя это можно сделать, если есть какая-либо неоднозначность. Например, ContentControl, представляющий представление команды, имеет свойство Content, привязанное к элементу .CollectionViewSourceTeams Однако элементы управления в DataTemplate привязываются к свойствам Team класса, так как CollectionViewSource при необходимости автоматически предоставляет выбранную команду из списка команд.

См. также