Разработка приложений для Windows 8

Контекстное масштабирование и альтернативные шаблоны

Показывать лекцию целиком

HTML + JS: Практическое занятие №4

Задание: продолжая проект, полученный в результате выполнения третьего практического задания, добавьте поддержку контекстного масштабирования на главной странице (groupedItems) и определите альтернативное представления для одной из групп контента на главной странице (groupedItems) и странице группы (groupDetails).

  • В качестве подтверждения выполнения лабораторной работы от вас потребуется предоставить скриншот страницы группы (groupTwitterDetails) из приложения, отображающей применение альтернативного шаблона представления данных.
  • ЗАМЕЧАНИЕ: напоминаем, что ваше приложение должно быть уникальным:

  • Использовать в качестве источников данных источники, отличные от тех, которые приводятся в инструкциям к практическим занятиям
  • Внешний вид приложения должен соответствовать выбранной вами тематике приложения (для всех страниц приложения).
  • Политика конфиденциальности (Privacy Policy) должна соответствовать вашему приложению и быть доступна внутри приложения.
  • Контекстное масштабирование

    Как вы уже наверняка, знаете из лекций, контекстное масштабирование – это способ показать еще одно, -- более высокоуровневое, -- представление отображаемых данных. На практике контекстное масштабирование (Semantic Zoom) применяется, прежде всего, для предоставления возможности быстрого перемещения по длинным коллекциям данных.

    В нашем практическом упражнении мы добавим поддержку этого механизма на главной странице (groupedItems) приложения, на которой у нас выводится отображение свежего контента из нескольких источников.

    Для реализации контекстного масштабирования необходимы два элемента, реализующие интерфейс IZoomableView, для нас такими элементами будут ListView. Один элемент управления ListView мы уже используем в нашем приложении:

    <div class="groupeditemslist win-selectionstylefilled" aria-label="List of groups" 
    data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }"></div>

    Второй важной составляющей является наличие коллекции данных, реализующей интерфейс IListDataSource и предоставляющей сведения о группировке контента. Такая коллекция у нас также уже есть – все наши данные сгруппированы в соответствии с источниками:

    groupedItems = Data.items.createFiltered(function (item) {
        return item.index < tilesLimit;
    
    }).createGrouped(
        function groupKeySelector(item) { return item.group.key; },
        function groupDataSelector(item) { return item.group; }
    );

    В списке WinJS.Binding.List для этого доступен метод createGrouped, принимающий на входе функции, описывающие способ группировки на основании имеющихся данных.

    Чтобы добавить поддержку контекстного масштабирования в свое приложение, сделайте описанные ниже шаги.

    Первым делом, на странице groupedItems.html добавьте шаблон для общего представления заголовков (в режиме масштабирования):

    <div id="semanticZoomTemplate" data-win-control="WinJS.Binding.Template">
        <div class="semanticZoomItem">
            <h1 class="semanticZoomItem-Text" data-win-bind="textContent: title"></h1>
        </div>	
    </div>

    В данном случае содержание шаблона очень похоже на содержание описанного в этом же файле шаблона headerTemplate – нам также нужно извлечение названия заголовка (для начала).

    Далее необходимо добавить еще один элемент ListView, с которым мы будем связывать данные в "сжатом" состоянии:

    <!-- Сжатое представление -->
        <div class="zoomeditemslist win-selectionstylefilled" aria-label="Zoomed List of groups" 
             data-win-control="WinJS.UI.ListView" 
             data-win-options="{ selectionMode: 'none', tapBehavior: 'invoke', itemTemplate: select('#semanticZoomTemplate') }"></div>

    Кстати, обратите внимание, что в данном случае используемый шаблон для представления данных мы прописали непосредственно при объявлении элемента управления. Это можно делать как декларативно, так и в коде.

    Наконец, надо обернуть это все в один элемент управления Semantic View:

    <div id="semanticZoomDiv" data-win-control="WinJS.UI.SemanticZoom">    
        <!-- Детальное представление -->
        <div class="groupeditemslist win-selectionstylefilled" aria-label="List of groups" 
             data-win-control="WinJS.UI.ListView" 
             data-win-options="{ selectionMode: 'none' }"></div>
    
        <!-- Сжатое представление -->
        <div class="zoomeditemslist win-selectionstylefilled" aria-label="Zoomed List of groups" 
             data-win-control="WinJS.UI.ListView" 
             data-win-options="{ selectionMode: 'none', tapBehavior: 'invoke', itemTemplate: select('#semanticZoomTemplate') }"></div>
    
    </div> 

    Важно: порядок следования элементов (сначала детальное, потом сжатое) имеет значение!

    Следующим шагом осталось прописать наши данные с используемыми шаблонами. Для этого перейдите в файл groupedItems.js и найдите функцию ready. После объявления переменной listView и ее инициализации добавьте еще одну переменную:

    var zoomedListView = element.querySelector(".zoomeditemslist").winControl;

    Далее замените вызов функции _initializeLayout на такой:

    this._initializeLayout(listView, zoomedListView, appView.value);

    Перейдите к функции _initializeLayout и поменяйте соответствующим образом ее сигнатуру:

    _initializeLayout: function (listView, zoomedListView, viewState) { ... }

    Внутри функции найдите блок выбора настройки данных в зависимости от режима представления if (…) {…} else {…} и внутри конструкции else {…} добавьте инициализацию zoomedListView группированными данными:

    zoomedListView.itemDataSource = groupedItems.groups.dataSource;
    zoomedListView.layout = new ui.GridLayout();

    Попробуйте запустить приложение:

    Контекстное масштабирование работает, но верстка "поехала". Чтобы все поправить, перейдите в файл groupedItems.css. Первым делом необходимо отменить поведение по умолчанию для контейнера semanticZoomDiv, для этого пропишите соответствующее правило, растягивающее его на все доступное пространство:

    #semanticZoomDiv {
        height: 100%;
        width: 100%;
    }

    Теперь в обычном представлении все встало на свои места:

    Далее, необходимо определить стили для сжатого представления:

    .groupeditemspage .zoomeditemslist .win-horizontal.win-viewport .win-surface {
        margin: 128px 115px 60px 120px;
    }
    
        .groupeditemspage .zoomeditemslist .semanticZoomItem {
            -ms-grid-columns: 1fr;
            -ms-grid-rows: 1fr 90px;
            display: -ms-grid;
            height: 250px;
            width: 250px;
            background-color: rgb(161, 38, 161);
    
            background-position: 50% 50%;
            background-repeat: no-repeat;
            background-size: cover;
        }
    
         .groupeditemspage .zoomeditemslist .semanticZoomItem .semanticZoomItem-Text {
               font-size: 1.6em; 
               line-height: 1.2;
               font-family: 'Segoe UI Light';
               color: white;
               text-transform: uppercase;
               margin: 20px;
         }

    Запустите проект и перейдите в режим контекстного масштабирования:

    Попробуйте самостоятельно ввести на плитку дату (можно попробовать сделать связывание с полем ‘updated’) или картинку из последнего поста.

    Теперь, если вы попробуете перейти в Snapped-режим, вы увидите, что все работает неправильно. И, в общем-то, если посмотреть в код, понятно, почему. Внутри функции updateLayout у нас есть еще один вызов функции инициализации отображения, но со старой сигнатурой:

    this._initializeLayout(listView, viewState);

    Исправьте это, добавив в начале объявление дополнительной переменной, как мы это делали в функции ready:

    var zoomedListView = element.querySelector(".zoomeditemslist").winControl;

    И поменяв соответствующим образом вызов функции initializeLayout:

    this._initializeLayout(listView, zoomedListView, viewState);

    Остался последний штрих: в режиме Snapped View нам не нужно контекстное масштабирование, так как согласно устройству шаблона, мы уже там показываем только заголовки групп:

    Перейдите в функию _initializeLayout и добавьте перед if:

    var semanticZoom = document.querySelector("#semanticZoomDiv").winControl;

    Здесь мы получаем доступ к нашему элементу SemanticZoom, после чего внутри if (для snapped-режима) необходимо его отключить:

    semanticZoom.enableButton = false;
    semanticZoom.zoomedOut = false;
    semanticZoom.locked = true;

    А внутри else (для full и filled) наоборот разрешить:

    semanticZoom.enableButton = true;
    semanticZoom.zoomedOut = false;
    semanticZoom.locked = false;

    Готово!

    Дополнительные шаблоны

    К текущему моменту мы научились настраивать внешний вид приложения на разных экранах и даже добавили контекстное масштабирование. Однако при этом весь контент у нас выглядит абсолютно одинаково независимо от сути самого контента.

    Например, если мы добавим в список источников поток из Twitter, то он будет отображаться точно также, как и большие новости через RSS:

    Это плохо, потому что внешний вид должен соответствовать содержимому. В этой части мы посмотрим, как можно поменять внешний вид для главной страницы и добавим новый шаблон для страницы описания группы.

    Главная страница

    Первым делом надо научиться различать разные типы данных. Проще всего это сделать непосредственно при описании данных. Откройте файл с заданием источников данных и добавьте к каждому источнику поле ‘type’:

    [{ "key": "ATwitter", "type": "twitter", "url": "https://api.twitter.com/1/statuses/user_timeline.rss?screen_name=windows", 
    "title": "@windows", "rsstitle": "tbd", "updated": "tbd" }, { "key": "CBlogging", "type": "blog", "url": 
    "http://blogs.windows.com/windows/b/bloggingwindows/rss.aspx", "title": "Blogging Windows", 
    "rsstitle": "tbd", "updated": "tbd" }, { "key": "BExperience", "type": "blog", "url": 
    "http://blogs.windows.com/windows/b/windowsexperience/rss.aspx", 
    "title": "Windows Experience", "rsstitle": "tbd", "updated": "tbd" }, 
    { "key": "DExtreme", "type": "blog", "url": "http://blogs.windows.com/windows/b/extremewindows/rss.aspx", 
    "title": "Extreme Windows", "rsstitle": "tbd", "updated": "tbd" }] 

    Напомню, что в вашем случае это будут другие данные. Здесь мы также добавили новый тип источника – Twitter, для чего можно использовать Twitter API, подставив в запрос название твиттера (в нашем случае это @windows).

    Теперь поле ‘type’ доступно для связывания в шаблонах для каждого элемента через свойство group.type. Наиболее оптимальный способ указать этот тип в шаблоне – прописать его в css-класс элемента. Это можно сделать двумя способами:

    1. В шаблоне элемента (groupedItems.html) сделать связывание с классом, например так:

    <div class="itemtemplate" data-win-control="WinJS.Binding.Template">
            <div data-win-bind="className: group.type">
                <div class="item" data-win-bind="style.backgroundImage: backgroundImage;">               
                    <div class="item-title-container">
                        <h4 class="item-title" data-win-bind="textContent: title"></h4>
                    
                    </div>
                    <div class="item-overlay">                
                        <h6 class="item-date win-type-ellipsis">
                            <span data-win-bind="textContent: day"></span>
                            <span data-win-bind="textContent: month"></span>
                        </h6>
                    </div>            
                </div>
            </div>
    </div>

    Здесь мы добавили вокруг элемента с классом "item" еще один контейнер, в котором прописали нужный нам класс, связав его со свойством group.type.

    2. Из кода при инициализации listView вывести выбор шаблона в отдельную функцию, которая будет применять тот или иной класс и самостоятельно прописывать связывание.

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

    К этому моменту, вы, надеемся, уже обновили шаблон, как указано в примере выше, добавив в нему класс, завязанный на тип данных. Теперь давайте добавим стили.

    Перейдите в groupedItems.css, найдите описание (они описаны отдельно, а не внутри media-query для snapped-режима):

    .groupeditemspage .groupeditemslist .item {
        …
    }

    и последующие правила для содержимого ‘item’-элемента. Скопируйте эти правила отдельно, добавив перед .item класс .twitter. Настройте внешний вид на свое усмотрение (достаточно указать только те свойства, ко торые вы хотите поменять):

    /* Twitter */
     .groupeditemspage .groupeditemslist .twitter .item {
    }
    
    .groupeditemspage .groupeditemslist .twitter .item .item-title-container {
    }
    
        .groupeditemspage .groupeditemslist .twitter .item .item-title-container .item-title {
        }
    
    .groupeditemspage .groupeditemslist .twitter .item .item-overlay {
    }
    
        .groupeditemspage .groupeditemslist .twitter .item .item-overlay .item-date {
        }

    Например, если вы хотите, чтобы, чтобы цвет плитки для Twitter-контента был темным, а цвет текста соответствовал цвету логотипа социальной сети, это можно указать так:

    .groupeditemspage .groupeditemslist .twitter .item {
               background-color: #012f41;
     }
    
         .groupeditemspage .groupeditemslist .twitter .item .item-title-container {
             background-image: none;
         }
    
             .groupeditemspage .groupeditemslist .twitter .item .item-title-container .item-title {
                 color: #00aced;
             }

    Дальше можно увеличить размер заголовка и убрать верхний регистр для текста:

    /* Twitter */
    .groupeditemspage .groupeditemslist .twitter .item {
               background-color: #012f41;
     }
    
         .groupeditemspage .groupeditemslist .twitter .item .item-title-container {
             background-image: none;
             height: 100%;
         }
    
             .groupeditemspage .groupeditemslist .twitter .item .item-title-container .item-title {
                 color: #00aced;
                 text-transform:none;
             }
    
         .groupeditemspage .groupeditemslist .twitter .item .item-overlay {
         }
         
             .groupeditemspage .groupeditemslist .twitter .item .item-overlay .item-date {
                 color: white;
             }

    В результате отображение будет примерно таким:

    Попробуйте самостоятельно добавить к плиткам логотип Twitter. Или используя задание элементов сетки разным размером (см. статью http://msdn.microsoft.com/ru-ru/library/windows/apps/jj657974.aspx), привести отображение к примерно такому виду:

    Теперь давайте перейдем к шаблону деталей отдельной группы.

    Детали группы

    Прежде всего, стоит отметить, что во всех внутренних страницах (groupDetail и itemDetail) нам также доступна информация о типе исходных данных. Поэтому можно совершенно аналогичным образом добиться кастомизации отображения средствами CSS.

    Ниже мы посмотрим другой вариант настройки, задав для этого отдельную страницу в проекте для контента из твиттера.

    Замечание. Выбор между двумя этими вариантами как правило диктуется сложностью получаемого решения. Если всю настройку можно сделать через CSS и это не сильно усложняет весь проект, проще поступить именно таким образом. В данной практической работе мы намеренно в учебных целях рассматриваем второй вариант.

    Чтобы понять, каким образом происходит переход к той или иной странице, откройте файл gropedItems.js. Найдите строчки:

    navigateToGroup: function (key) {
        nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: key });
    },

    Функция на входе получает уникальных идентификатор группы (ключ) и далее делается переход на страницу groupDetails.html с передачей этого ключа в качестве параметра.

    Давайте создадим новую страницу. Для простоты манипуляций (можно создать все файлы вручную, но так проще) скопируйте в проекте целиком папку groupDetails, поменяйте название новой папки и файлов на groupTwitterDetails.

    Вернитесь в функцию navigateToGroup и поменяйте внутренний код на такой:

    var group = Data.resolveGroupReference(key);
    
    if (group.type === "twitter") {
        nav.navigate("/pages/ groupTwitterDetail/groupTwitterDetail.html", { groupKey: key });
    } else {
        nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: key });
    }   

    Здесь мы через объект Data вытаскиваем по ключу информацию о группе (нам нужен тип) и далее в зависимости от типа переключаем пользователя на одну или другую страницу.

    Замечание: обратите внимание, что вызов самой функции navigateToGroup прописан в нескольких местах, включая html-страницу – в событии onclick заголовка.

    Теперь вернитесь к созданным страницам. Для начала, откройте groupTwitterDetail.html и поменяйте в заголовке ссылки на соответствующие файлы:

    <link href="/pages/groupTwitterDetail/groupTwitterDetail.css" rel="stylesheet" />
    <script src="/pages/groupTwitterDetail/groupTwitterDetail.js"></script>

    Далее откройте groupTwitterDetail.js и обновите определение страницы с учетом переименования:

    ui.Pages.define("/pages/groupTwitterDetail/groupTwitterDetail.html", {

    Попробуйте запустить проект. Сейчас все группы выглядят по-прежнему одинаково, однако, группа для твиттера уже использует другие файлы.

    Настройте внешний вид страницы на свое усмотрение, поменяв соответствующим образом стили и шаблон страницы:

    Самостоятельно также создайте индивидуальную страницу для отдельного сообщения из твиттера. Не забудьте про настройку Snapped-режима.

    XAML+C#. Практическое занятие №4

    Задание: продолжая проект, полученный в результате выполнения третьего практического задания, добавьте поддержку контекстного масштабирования на главной странице (GroupDetailPage.xaml) и определите альтернативное представления для одной из групп контента на странице группы (GroupDetailPage.xaml).

  • В качестве подтверждения выполнения лабораторной работы от вас потребуется предоставить скриншот страницы группы (GroupDetailPage.xaml) из приложения, отображающей применение альтернативного шаблона представления данных.
  • ЗАМЕЧАНИЕ: напоминаем, что ваше приложение должно быть уникальным:

  • Использовать в качестве источников данных источники, отличные от тех, которые приводятся в инструкциям к практическим занятиям
  • Внешний вид приложения должен соответствовать выбранной вами тематике приложения (для всех страниц приложения).
  • Политика конфиденциальности (Privacy Policy) должна соответствовать вашему приложению и быть доступна внутри приложения.
  • Контекстное масштабирование

    Начнем с достаточно простой задачи – добавления контекстного масштабирования. В XAML для этого существует специальный компонент SemanticZoom, который позволяет определить 2 состояния просмотра: детальное и выскоуровневое.

    Итак, детальное представление на нашей главной странице GroupedItemsPage.xaml – это собственно сам уже существующий модернизированный GridVew: VariableSizeGridView. Определим у SemanticZoom его свойство ZoomedInView элемента управления SimanticZoom, поместив в ZoomedOutView в качестве заготовки пустой GridView:

    Если теперь запустить приложение, можно будет выполнить переход в состояние ZoomedOut путем нажатия специальной копки внизу экрана мышкой или пальцами или Ctrl с управляющими клавишами. Обратно, правда, перейти не удастся, так как у нас пока не определено представление для ZoomedOut.

    Давайте определим, как будут выглядеть наши RSS потоки при уменьшении. Классический вариант – некие прямоугольники с названиями. Понятно, что нам нужно где-то взять эти названия. Брать мы их будем из того же самого источника данных, который мы используем и при отображении полного представления.

    Итак, для начала дополним GridView в ZoomedOutView шаблонами для отображения нашего представления групп:

    <SemanticZoom.ZoomedOutView>
        <GridView 
            x:Name="zommedOutView"
            Grid.RowSpan="2" 
            Padding="116,137,40,46"
            SelectionMode="None">
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapGrid Margin="0,0,80,0" ItemWidth="400" ItemHeight="400" 
                     MaximumRowsOrColumns="1" VerticalAlignment="Center"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>
            <GridView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Group.Title}" Style="{StaticResource HeaderTextStyle}" />                            
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </SemanticZoom.ZoomedOutView>

    Итак, давайте посмотрим, что мы добавили. Мы спозиционировали GridView и дали ему имя, чтобы обращаться из кода. Мы определили контейнер для наших данных, а также определили шаблон для отображения самого элемента данных.

    Так как для связывания мы будем использовать группы из уже используемого groupedItemsViewSource, мы указываем, что нужно взять title-группы для отображения.

    Теперь осталось в коде в файле GroupedItemsPage.xaml.cs добавить источник данных для отображения нашего представления. Для этого, в функции LoadState, после загрузки данных для RSS в цикле добавьте строчку:

    zommedOutView.ItemsSource = groupedItemsViewSource.View.CollectionGroups;

    В результате код будет выглядеть аналогично:

    protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
    {
        if (NetworkInformation.GetInternetConnectionProfile() != null  NetworkInformation.GetInternetConnectionProfile()
        .GetNetworkConnectivityLevel() != NetworkConnectivityLevel.InternetAccess)
        {
            //получаем папку с именем Data в локальной папке приложения
            var localFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync
              ("Data", CreationCollisionOption.OpenIfExists);
     
            //получаем список файлов в папке Data
            var cachedFeeds = await localFolder.GetFilesAsync();
     
            //получаем список всех файлов, имя которых config.xml
            var feedsToLoad = from feeds in cachedFeeds
                                where feeds.Name.EndsWith(".rss")
                                select feeds;
     
            //нам возращается IEnumrable - а он гарантирует тольок один проход
            //копируем в массив                
            var feedsEntries = feedsToLoad as StorageFile[] ?? feedsToLoad.ToArray();
     
            if (feedsEntries.Any())
            {
                this.DefaultViewModel["Groups"] = RSSDataSource.AllGroups;
                        
                        
                foreach (var feed in feedsEntries)
                {
                    await RSSDataSource.AddGroupForFeedAsync(feed);
                }
     
                zommedOutView.ItemsSource = groupedItemsViewSource.View.CollectionGroups;
     
                OfflineMode.Visibility = Visibility.Visible;
            }
            else
            {
                var msg = new MessageDialog("The program need an internet connection to work. 
                Please check it and restart the porgram.");
                await msg.ShowAsync();
            }
     
        }
        else
        { 
                
            this.DefaultViewModel["Groups"] = RSSDataSource.AllGroups;
            OfflineMode.Visibility = Visibility.Collapsed;
     
            var feeds = await App.ReadSettings();
     
            foreach (var feed in feeds)
            {
                await RSSDataSource.AddGroupForFeedAsync(feed.url, feed.id);
            }
     
            zommedOutView.ItemsSource = groupedItemsViewSource.View.CollectionGroups;
     
        }
                
    }

    Если теперь запустить приложение и использовать SemanticZoom, приложение будет выглядеть приблизительно так:

    Выполняем контекстное масштабирование:

    Выбираем крайнее справа название, детальное представление автоматически прокрутится на соответствующую группу:

    Итак, как вы видите, реализовать контекстное масштабирование достаточно просто. Перейдем к тому, как сделать другое отображение страницы группы.

    Альтернативные шаблоны

    Зачем могут потребоваться альтернативные шаблоны? Ответ очень прост. Если вы делаете тематическое приложение, например "все о том, как прокачать мышцу", вы, скорее всего, захотите включить разные представления как группового представления на главной странице, так и для представления самой группы, не говоря уже о представлении элемента.

    Для того, чтобы было понятнее, я добавил в приложение RSS поток твиттера bash.im: https://api.twitter.com/1/statuses/user_timeline.rss?screen_name=b_o_r

    Понятно, что нам абсолютно бессмысленно стандартное представление из шаблона Grid приложения:

    Нам нужен другой шаблон! При XAML/C# разработке проще всего создать дополнительную страницу для этого представления.

    Уже знакомым нам способом – правой копкой по проекту, Add, New Item …., и выбираем Items Page, которую назовем TwitterPage.xaml

    Сразу же перейдем в TwitterPage.xaml и удалим строчку:

    <!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
    <x:String x:Key="AppName">My Application</x:String>

    Эта переменная у нас уже определена на глобальном уровне.

    Собственно, в первом приближении – все что нужно сделать со страницей мы уже сделали. Теперь нужно добавить дополнительную логику на основную страницу GroupedItemsPage.xaml в метод, который обрабатывает нажатие на заголовок группы:

    void Header_Click(object sender, RoutedEventArgs e)

    Все очень просто, в зависимости от того, на заголовок какой группы был выполнен щелчок, мы будем выбирать страницу для перехода. Добавим соответствующий код (проверка на содержание слова "Twitter" в название группы используется только в качестве примера внутри этого примера, чтобы упросить логику, хотя является вполне рабочим вариантом):

    void Header_Click(object sender, RoutedEventArgs e)
    {
        // Determine what group the Button instance represents
        var group = (sender as FrameworkElement).DataContext;
     
        //проверяем, что группа отображает сообщения из twitter-а
        //мы точно значем, что из 3-х групп, только у одной есть это слово в названии
        //у той, которая относится к твиттеру
        if (((RSSDataGroup)group).Title.Contains("Twitter"))
        {
            //переходим на странцу для отображения списка твитов и передаем ID группы
            this.Frame.Navigate(typeof(TwitterPage), ((RSSDataGroup)group).UniqueId);
        }
        else
        { 
        // Navigate to the appropriate destination page, configuring the new page
        // by passing required information as a navigation parameter
        this.Frame.Navigate(typeof(GroupDetailPage), ((RSSDataGroup)group).UniqueId);
        }
     
    }

    Теперь нам надо вернуться в код страницы TwitterPage.xaml - TwitterPage.xaml.cs в метод LoadPage и добавить обработку входящего параметра и указание странице, откуда брать данные для отображения:

    protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
    {
        
        var group = RSSDataSource.GetGroup((String)navigationParameter);
     
        this.DefaultViewModel["Group"] = group;
        this.DefaultViewModel["Items"] = group.Items;
    }

    Чтобы проект собирался, не забудьте додавить в using:

    using MyReader.Data;

    Соберите и запустите проект. Убедитесь, что теперь при выборе группы, которая отображает Twitter у вас используется специальная страница:

    Как видно, странице еще не до конца готова к отображению Twitt-ов. Самостоятельно, используя свои знания о том, где и как можно переопределить шаблон отображения, сделайте эту страницу более привлекательно.

    Вернуться к учебному плану