Чтобы лучше разобраться в работе шаблона, попробуем внести в него свою логику. Возьмем стандартный проект и первым делом добавим в него в папку DataModel новый файл со следующими классами:
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HubApp.Data { public class Tablet { public string Id { get; set; } public string Name { get; set; } public string ImagePath { get; set; } public override string ToString() { return this.Name; } } public class Company { public string Id { get; set; } public string Name { get; set; } public ObservableCollection<Tablet> Items { get; set; } public override string ToString() { return this.Name; } } public sealed class TabletDataSource { private static TabletDataSource tabletDataSource = new TabletDataSource(); private ObservableCollection<Company> companies = new ObservableCollection<Company>(); public ObservableCollection<Company> Companies { get { return this.companies; } set { this.companies = value; } } public static IEnumerable<Company> GetCompanies() { tabletDataSource.GetTabletData(); return tabletDataSource.Companies; } public static Company GetCompany(string id) { tabletDataSource.GetTabletData(); var match = tabletDataSource.Companies.FirstOrDefault(c => c.Id.Equals(id)); return match; } public static Tablet GetTablet(string id) { tabletDataSource.GetTabletData(); var tablet = tabletDataSource.Companies.SelectMany(group => group.Items) .FirstOrDefault(t => t.Id.Equals(id)); return tablet; } private void GetTabletData() { if (this.companies.Count != 0) return; // создаем компании Company samsung = new Company { Id = "1", Name = "Samsung" }; Company lenovo = new Company { Id = "2", Name = "Lenovo" }; Company lg = new Company { Id = "3", Name = "LG" }; // создаем списки планшетов для компаний samsung.Items = new ObservableCollection<Tablet> { new Tablet {Id="Samsung1", Name="Galaxy Tab 4", ImagePath="Assets/galaxytab4.jpg"}, new Tablet {Id="Samsung2", Name="Galaxy Note 10.1", ImagePath="Assets/galaxynote10.jpg"}, }; lenovo.Items = new ObservableCollection<Tablet> { new Tablet {Id="Lenovo1", Name="Lenovo Tab A8", ImagePath="Assets/lenovotaba8.jpg"}, new Tablet {Id="Lenovo2", Name="Yoga Tablet B8000", ImagePath="Assets/yogatablet.jpg"}, }; lg.Items = new ObservableCollection<Tablet> { new Tablet {Id="LG1", Name="LG G Pad 8.0 V490", ImagePath="Assets/lggpad8.jpg"}, new Tablet {Id="LG2", Name="LG G Pag 8.3 GPE", ImagePath="Assets/lggpad83.jpg"}, }; this.Companies = new ObservableCollection<Company> { samsung, lenovo, lg }; } } }
Допустим, наше приложение будет выводить некоторые модели планшетов и их производителей. Для этого у нас здесь определены классы Company и Tablet.
Для создания коллекции объектов этих классов, а также для получения отдельных объектов по некоторому идентификатору создается класс TabletDataSource. В идеале конечно, мы вряд ли будет жестко кодировать данные в коде, а скорее загружать их либо из сети, либо из файла на устройстве, но для упрощения задачи используется модель с жестко закодированными данными.
Для каждой отдельной модели планшета я добавил в папку Assets изображения 275х183, поэтому каждой модели присваивается соответствующее
значение, например: ImagePath="Assets/lggpad8.jpg"
Теперь нам надо загрузить эти данные в приложение и отобразить. Изменим файл Hub.xaml следующим образом:
<Page x:Class="HubApp.HubPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HubApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:data="using:HubApp.Data" DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}" mc:Ignorable="d"> <Grid x:Name="LayoutRoot"> <Hub x:Name="Hub" x:Uid="Hub" Header="Планшеты" Background="{ThemeResource HubBackgroundImageBrush}"> <HubSection x:Uid="HubSection1" Header="Компании" DataContext="{Binding Companies}"> <DataTemplate> <ListView ItemsSource="{Binding}" IsItemClickEnabled="True" ItemClick="GroupSection_ItemClick" ContinuumNavigationTransitionInfo.ExitElementContainer="True"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Margin="0,0,0,27.5"> <TextBlock Text="{Binding Name}" Style="{ThemeResource ListViewItemTextBlockStyle}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </DataTemplate> </HubSection> <HubSection x:Uid="HubSection2" Header="{Binding Name}" Width="Auto" DataContext="{Binding Companies[0]}"> <DataTemplate> <GridView Margin="0,9.5,0,0" ItemsSource="{Binding Items}" AutomationProperties.AutomationId="ItemGridView" SelectionMode="None" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick" ContinuumNavigationTransitionInfo.ExitElementContainer="True"> <GridView.ItemsPanel> <ItemsPanelTemplate> <ItemsWrapGrid /> </ItemsPanelTemplate> </GridView.ItemsPanel> <GridView.ItemTemplate> <DataTemplate> <StackPanel Margin="0,0,9.5,9.5"> <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Name}" Height="183" Width="275"/> <TextBlock Text="{Binding Name}" VerticalAlignment="Bottom" Style="{ThemeResource BaseTextBlockStyle}"/> </StackPanel> </DataTemplate> </GridView.ItemTemplate> </GridView> </DataTemplate> </HubSection> <HubSection x:Uid="HubSection3" Header="{Binding Name}" DataContext="{Binding Companies[1]}"> <DataTemplate> <ListView AutomationProperties.AutomationId="ItemListViewSection3" SelectionMode="None" IsItemClickEnabled="True" ItemsSource="{Binding Items}" ItemClick="ItemView_ItemClick" ContinuumNavigationTransitionInfo.ExitElementContainer="True"> <ListView.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Grid.Column="0" HorizontalAlignment="Left"> <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Name}" Height="74" Width="110"/> </Border> <StackPanel Grid.Column="1" Margin="10,0,0,0"> <TextBlock Text="{Binding Name}" FontSize="26" /> </StackPanel> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView> </DataTemplate> </HubSection> <HubSection x:Uid="HubSection4" Header="{Binding Name}" DataContext="{Binding Companies[2]}" > <DataTemplate> <ListView AutomationProperties.AutomationId="ItemListViewSection4" SelectionMode="None" IsItemClickEnabled="True" ItemsSource="{Binding Items}" ItemClick="ItemView_ItemClick" ContinuumNavigationTransitionInfo.ExitElementContainer="True"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Margin="0,0,0,19"> <TextBlock Text="{Binding Name}" Style="{ThemeResource ListViewItemTextBlockStyle}"/> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> </DataTemplate> </HubSection> </Hub> </Grid> </Page>
Для первой секции хаба в качестве контекста данных задается список компаний: DataContext="{Binding Companies}"
. А все следующие
секции хаба работают с отдельными компаниями, например, DataContext="{Binding Companies[0]}"
, выводя все планшеты, принадлежащие компании в секцию.
Теперь в файле HubPage.xaml.cs нам надо изменить три метода:
private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e) { this.DefaultViewModel["Companies"] = TabletDataSource.GetCompanies(); } // обработка клика по элементам-компаниям private void GroupSection_ItemClick(object sender, ItemClickEventArgs e) { var groupId = ((Company)e.ClickedItem).Id; if (!Frame.Navigate(typeof(SectionPage), groupId)) { throw new Exception(this.resourceLoader.GetString("NavigationFailedExceptionMessage")); } } // обработка клика по элементам-планшетам private void ItemView_ItemClick(object sender, ItemClickEventArgs e) { var itemId = ((Tablet)e.ClickedItem).Id; if (!Frame.Navigate(typeof(ItemPage), itemId)) { throw new Exception(this.resourceLoader.GetString("NavigationFailedExceptionMessage")); } }
Чтобы работала привязка, нам надо задать объект в качестве значения свойства DefaultViewModel: this.DefaultViewModel["Companies"] = TabletDataSource.GetCompanies();
Также изменим файл Section.xaml, чтобы он был привязан к компании:
<Page x:Name="pageRoot" x:Class="HubApp.SectionPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HubApp" xmlns:data="using:HubApp.Data" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" DataContext="{Binding DefaultViewModel.Company, RelativeSource={RelativeSource Self}}" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Page.Transitions> <TransitionCollection> <NavigationThemeTransition> <NavigationThemeTransition.DefaultNavigationTransitionInfo> <ContinuumNavigationTransitionInfo/> </NavigationThemeTransition.DefaultNavigationTransitionInfo> </NavigationThemeTransition> </TransitionCollection> </Page.Transitions> <Grid> <Grid.ChildrenTransitions> <TransitionCollection> <EntranceThemeTransition/> </TransitionCollection> </Grid.ChildrenTransitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Margin="19,0,0,0"> <TextBlock x:Uid="Header" Text="Планшеты" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/> <TextBlock Text="{Binding Name}" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}"/> </StackPanel> <ListView x:Name="itemListView" AutomationProperties.AutomationId="ItemListView" TabIndex="1" Grid.Row="1" ItemsSource="{Binding Items}" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick" SelectionMode="None" IsSwipeEnabled="false" Margin="19,0,0,0"> <ListView.ItemTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Border Margin="0,9.5,0,0" Height="74" Width="110"> <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Name}"/> </Border> <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="14.5,0,0,0"> <TextBlock Text="{Binding Name}" Style="{ThemeResource ListViewItemTextBlockStyle}"/> </StackPanel> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid> </Page>
Также изменим в файле кода Section.xaml.cs следующие два метода:
private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e) { // устанавливаем модель для страницы секции this.DefaultViewModel["Company"] = TabletDataSource.GetCompany((string)e.NavigationParameter); } private void ItemView_ItemClick(object sender, ItemClickEventArgs e) { var itemId = ((Tablet)e.ClickedItem).Id; if (!Frame.Navigate(typeof(ItemPage), itemId)) { var resourceLoader = ResourceLoader.GetForCurrentView("Resources"); throw new Exception(resourceLoader.GetString("NavigationFailedExceptionMessage")); } }
Также изменим разметку для отображения отдельного элемента в файле ItemPage.xaml:
<Page x:Name="pageRoot" x:Class="HubApp.ItemPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HubApp" xmlns:data="using:HubApp.Data" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" DataContext="{Binding DefaultViewModel.Item, RelativeSource={RelativeSource Self}}" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Page.Transitions> <TransitionCollection> <NavigationThemeTransition> <NavigationThemeTransition.DefaultNavigationTransitionInfo> <ContinuumNavigationTransitionInfo/> </NavigationThemeTransition.DefaultNavigationTransitionInfo> </NavigationThemeTransition> </TransitionCollection> </Page.Transitions> <Grid x:Name="LayoutRoot"> <Grid.ChildrenTransitions> <TransitionCollection> <EntranceThemeTransition/> </TransitionCollection> </Grid.ChildrenTransitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Grid.Row="0"> <TextBlock x:Uid="Header" Text="Планшеты" FontSize="30" /> <TextBlock Text="{Binding Name}" FontSize="26"/> <Image Source="{Binding ImagePath}" /> </StackPanel> <Grid Grid.Row="1" x:Name="ContentRoot"> </Grid> </Grid> </Page>
И изменим метод NavigationHelper_LoadState
в файле ItemPage.xaml.cs:
private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e) { this.DefaultViewModel["Item"] = TabletDataSource.GetTablet((string)e.NavigationParameter); }
И у нас будут следующие результаты работы: