Приложение на основе шаблона Hub App

Последнее обновление: 31.10.2015

Чтобы лучше разобраться в работе шаблона, попробуем внести в него свою логику. Возьмем стандартный проект и первым делом добавим в него в папку 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);
}

И у нас будут следующие результаты работы:

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850