Будьте добры сообщите какой срок проверки заданий и каким способом я буду оповещен! |
Контекстное масштабирование и альтернативные шаблоны
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-ов. Самостоятельно, используя свои знания о том, где и как можно переопределить шаблон отображения, сделайте эту страницу более привлекательно.