24
Programowanie aplikacji internetowych 2015/2016 Instrukcja laboratoryjna cz.4 Aplikacje na Windows 8.x Store (C# i XAML) Prowadzący: Tomasz Goluch Wersja: 1.1

Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

Programowanie aplikacji internetowych

2015/2016

Instrukcja laboratoryjna cz.4

Aplikacje na Windows 8.x Store (C# i XAML)

Prowadzący: Tomasz Goluch

Wersja: 1.1

Page 2: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

1

I. Wprowadzenie1

Cel: Przekazanie podstawowych informacje o laboratorium.

Laboratorium odbywa się na maszynach fizycznych które posiadają zainstalowany system

Windows 8.x i IDE Visual Studio 2012 (tylko aplikacje Windows 8.0) lub wyższe (również

aplikacje Windows 8.1).

II. Tworzenie aplikacji Windows Store (C# i XAML) Cel: Utworzenie aplikacji Windows Store, zamiana wyświetlania domyślnych przykładowych z szablonu rzeczywistymi oraz dostosowanie wyglądu interfejsu użytkownika.

Podczas uruchamiania programu lub próby użycia debuggera może pojawić się monit o

odnowienie licencji developera systemu Windows 8.1.

Zgoda wymaga uprawnień administratora (login i hasło podane przez prowadzącego) oraz

aktywnego konta email w domenie Windows (hotmail.com albo outlook.com). Nazwa i hasło

do konta również zostaną podane przez prowadzącego. Do wyrejestrowania licencji

deweloperskiej służy w PowerShell’u polecenie: Unregister-

WindowsDeveloperLicense. Proszę uruchomić PowerShell’a w trybie administratora.

1 Instrukcja przygotowana na podstawie laboratorium Hands-On lab: Building your first App for Windows 8.1

and publishing it to the Windows Store.

Page 3: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

2

1. Utwórz nowy: Store Apps → Windows Apps → BlankApp(Visual c#) projekt.

2. Do folderu Assets dodaj pliki zasobów. Należy je ściągnąć ze strony przedmiotu (pliki:

Logo.scale-100.png, SmallLogo.scale-100.png, SplashScreen.scale-

100.png, StoreLogo.scale-100.png i YouTube_Channel_Logo.png).

3. W pliku MainPage.xaml wewnątrz elementu Grid umieść kod reprezentujący główne

okno naszej aplikacji składające się kontrolki Hub zawierającej nagłówek i trzy sekcje.

Pierwsza sekcja zawiera grafikę a kolejne kontrolki ProgressRing i ListView, które

będą reprezentować kolejno: posortowane alfabetycznie i najwcześniej opublikowane

filmy na naszym kanale. Wklej poniższy kod zaznaczony na szaro.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Hub> <Hub.Header> <Grid> <TextBlock x:Name="textTitle" Text="Title" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" VerticalAlignment="Top" IsHitTestVisible="false" TextWrapping="NoWrap" /> </Grid> </Hub.Header> <HubSection Width="600" Margin="0,0,80,0"> <HubSection.Background> <ImageBrush ImageSource="Assets/YouTube_Channel_Logo.png" Stretch="UniformToFill" /> </HubSection.Background> </HubSection> <HubSection Width="600" Header="Aktualne"> <DataTemplate> <Grid x:Name="gridRecent"> <ProgressRing x:Name="progressRingRecent" IsActive="False" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Width="100" Height="100" Foreground="Red" /> <ListView x:Name="listViewRecent" SelectionMode="None" IsItemClickEnabled="True" Margin="-10,0"/> </Grid> </DataTemplate> </HubSection> <HubSection Width="600" Header="Najnowsze"> <DataTemplate> <Grid x:Name="gridRecent"> <ProgressRing x:Name="progressRingPopular" IsActive="False" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Width="100" Height="100" Foreground="Red" />

Page 4: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

3

<ListView x:Name="listViewPopular" SelectionMode="None" IsItemClickEnabled="True" Margin="-10,0"/> </Grid> </DataTemplate> </HubSection> </Hub> </Grid>

4. Dodaj do projektu folder Classes i dodaj do niego plik BindableBase.cs (do

ściągnięcia ze strony przedmiotu).

5. Dodaj do projektu folder DataModel i dodaj do niego nowy plik klasy

YouTubeVideo.cs.

6. Dodaj poniższy kod klasy do nowego pliku. Pamiętaj o dodaniu dostępu do wymaganej

przestrzeni nazw System.Xml.Linq i folderu Classes.

public class YouTubeVideo : BindableBase { private const string YoutubeWatchBaseUrl = "http://www.youtube.com/watch?v="; private string _title; /// <summary> /// Gets/Sets the title of the YouTube video. /// </summary> public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private string _videoUrl; /// <summary> /// Gets/Sets the video URL of the YouTube video. /// </summary> public string VideoUrl { get { return _videoUrl; } set { SetProperty(ref _videoUrl, value); } } private string _videoImageUrl; /// <summary> /// Gets/Sets the video image URL of the YouTube video. /// </summary> public string VideoImageUrl { get { return _videoImageUrl; } set { SetProperty(ref _videoImageUrl, value); } } private string _videoId; /// <summary> /// Gets/Sets the identifier of the YouTube video. /// </summary> public string VideoId

Page 5: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

4

{ get { if (!string.IsNullOrEmpty(VideoUrl)) { var parsed = VideoUrl.Split('/'); _videoId = parsed[parsed.Length - 1]; } return _videoId; } set { SetProperty(ref _videoId, value); } } public string ExternalUrl { get { return YoutubeWatchBaseUrl + VideoId; } } private string _summary; /// <summary> /// Gets/Sets the summary of the YouTube video. /// </summary> public string Summary { get { return _summary; } set { SetProperty(ref _summary, value); } } public YouTubeVideo() { } public YouTubeVideo(Google.Apis.YouTube.v3.Data.SearchResult ytvideo) { Title = ytvideo.Snippet.Title; VideoId = ytvideo.Id.VideoId; VideoImageUrl = ytvideo.Snippet.Thumbnails.Default__.Url; Summary = ytvideo.Snippet.Description; }

}

7. Dodaj do folderu DataModel nowy plik klasy YouTubeChannel.cs.

8. Dodaj poniższy kod klasy do nowego pliku. Pamiętaj o dodaniu dostępu do wymaganej

przestrzeni nazw System.Collections.ObjectModel.

public class YouTubeChannel { private string _q; private string _orderBy; private const int maxResults = 50; public YouTubeChannel(string query, string orderBy) { _q = query; _orderBy = orderBy; } public async Task<ObservableCollection<YouTubeVideo>> LoadData(int page = 0)

Page 6: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

5

{ var youtubeService = new YouTubeService(new BaseClientService.Initializer() { ApiKey = "AIzaSyCZCr7d3QzRnHzzcWf5dAQ6GR7h1bH5zNg", ApplicationName = this.GetType().ToString() }); var searchListRequest = youtubeService.Search.List("snippet"); searchListRequest.Q = _q; // Replace with your search term. searchListRequest.MaxResults = 50; // Call the search.list method to retrieve results matching the specified query term. var searchListResponse = await searchListRequest.ExecuteAsync(); var items = new List<YouTubeVideo>(); foreach (var searchResult in searchListResponse.Items) { if (searchResult.Id.Kind == "youtube#video") { items.Add(new YouTubeVideo(searchResult)); } } switch (_orderBy) { case "title": { items.Sort(delegate(YouTubeVideo x, YouTubeVideo y) { if (x.Title == null && y.Title == null) return 0; else if (x.Title == null) return -1; else if (y.Title == null) return 1; else return x.Title.CompareTo(y.Title); }); break; } case "published": { throw new NotImplementedException("zaimplementuj sortowanie malejąco po dacie opublikowania"); break; } default: { } break; } return items != null ? new ObservableCollection<YouTubeVideo>(items) : new ObservableCollection<YouTubeVideo>(); } }

9. Aby skorzystać z obiektu reprezentującego serwis YouTube należy dodać referencje do

następujących bibliotek: Google.Apis, Google.Apis.Auth,

Google.Apis.Auth.PlatformServices, Google.Apis.Core, Google.Apis.PlatformServices

i Google.Apis.YouTube.v3. Najlepiej w tym celu wykorzystać managera pakietów:

NuGet.

Page 7: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

6

10. Następnie należy dodać wymagane przestrzenie nazw: Google.Apis.Auth.OAuth2,

Google.Apis.Services, Google.Apis.Upload, Google.Apis.Util.Store,

Google.Apis.YouTube.v3, Google.Apis.YouTube.v3.Data

11. Dodaj do folderu DataModel nowy plik klasy Settings.cs.

12. Dodaj poniższy kod klasy do nowego pliku i uzupełnij: słowo kluczowe np.: „board

game”, nazwę kanału (ChannelName) oraz jego opis (Description).

static class Settings { public const string Query = "..."; public const string ChannelName = "... Channel"; public const string Description = "... Channel on YouTube."; }

13. Dodaj do folderu DataModel nowy plik klasy YouTubeDataSource.cs.

14. Dodaj poniższy kod klasy do nowego pliku. Pamiętaj o dodaniu dostępu do wymaganej

przestrzeni nazw System.Collections.ObjectModel i folderu Classes.

public class YouTubeDataSource : BindableBase { public ObservableCollection<YouTubeVideo> RecentItems { get; set; } public ObservableCollection<YouTubeVideo> SortedByTitleItems { get; set; } private string _channelName; public string ChannelName { get { return _channelName; } set { SetProperty(ref _channelName, value); } } private bool _isLoadingData; public bool IsLoadingData { get { return _isLoadingData; } set { SetProperty(ref _isLoadingData, value); } } private bool _isLoadingError; public bool IsLoadingError { get { return _isLoadingError; } set { SetProperty(ref _isLoadingError, value); } } private YouTubeChannel _popularChannel;

Page 8: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

7

private YouTubeChannel _recentChannel; public YouTubeDataSource() { IsLoadingError = false; RecentItems = new ObservableCollection<YouTubeVideo>(); SortedByTitleItems = new ObservableCollection<YouTubeVideo>(); _popularChannel = new YouTubeChannel(Settings.Query, "title"); _recentChannel = new YouTubeChannel(Settings.Query, "published"); } public async Task LoadData() { ChannelName = Settings.ChannelName; IsLoadingData = true; Task taskRecent = LoadRecent(); Task taskPopular = LoadPopular(); await taskRecent; await taskPopular; IsLoadingData = false; } private async Task LoadRecent() { for (int page = 0; page < 10; page++) { var loadedRecentItems = await _recentChannel.LoadData(page); foreach (var item in loadedRecentItems) { RecentItems.Add(item); } } } private async Task LoadPopular() { for (int page = 0; page < 10; page++) { var loadedSortedByTitleItems = await _popularChannel.LoadData(page); foreach (var item in loadedSortedByTitleItems) { SortedByTitleItems.Add(item); } } } }

15. Dodaj do pliku MainPage.xaml.cs poniższy kod. Pamiętaj o dodaniu dostępu do

wymaganej przestrzeni nazw Windows.UI.ApplicationSettings i folderu

DataModel.

public sealed partial class MainPage : Page { private static YouTubeDataSource _dataSource; public MainPage()

Page 9: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

8

{ this.InitializeComponent(); if (_dataSource == null) _dataSource = new YouTubeDataSource(); DataContext = _dataSource; } protected override async void OnNavigatedTo(NavigationEventArgs e) { Application.Current.Resuming += Current_Resuming; await LoadData(); } private async void Current_Resuming(object sender, object e) { await LoadData(); } private bool _alreadyLoading = false; private async Task LoadData() { if (_alreadyLoading) return; _alreadyLoading = true; if (_dataSource.SortedByTitleItems.Count == 0 || _dataSource.RecentItems.Count == 0) { try { await _dataSource.LoadData(); } catch { _dataSource.IsLoadingData = false; _dataSource.IsLoadingError = true; _dataSource.SortedByTitleItems.Clear(); _dataSource.RecentItems.Clear(); } } _alreadyLoading = false; } }

16. W pliku MainPage.xaml dodaj wiązanie (binding) atrybutu Text z właściwością

(property) ChannelName zadeklarowaną w klasie YouTubeDataSource.

Text="{Binding ChannelName}"

17. Podobnie ustaw wiązania atrybutu IsActive kontrolek ProgressRing z właściwością

IsLoadingData również zadeklarowaną w klasie YouTubeDataSource.

IsActive="{Binding IsLoadingData}

Page 10: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

9

18. Do kontrolek ListView dodaj atrybuty ItemsSource i powiąż je z właściwościami

RecentItems i SortedByTitleItems również zadeklarowanymi w klasie

YouTubeDataSource.

ItemsSource="{Binding RecentItems}"

19. Po kompilacji powinniśmy zobaczyć działające kontrolki ProgressRing (podczas

ładowania danych) oraz wypełnione kontrolki ListViews, niestety będą one wyświetlały

jedynie domyślną reprezentację w postaci stringu.

20. Dodaj sekcję Page.Resources w pliku MainPage.xaml.

<Page x:Class="BGYTChannelApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:BGYTChannelApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <DataTemplate x:Key="VideoItemTemplate"> <Grid Margin="10" Height="120"> <Grid.ColumnDefinitions> <ColumnDefinition Width="160"/> <ColumnDefinition Width="320"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions>

Page 11: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

10

<Rectangle Grid.RowSpan="2" Grid.ColumnSpan="2" /> <Image Source="{Binding VideoImageUrl}" Stretch="UniformToFill" Margin="0" Grid.RowSpan="2" Height="120"/> <TextBlock Text="{Binding Title, Margin="20,0,-10,0" Grid.Column="1" Grid.Row="0" FontSize="18" TextWrapping="WrapWholeWords" /> <TextBlock Text="{Binding Summary, Margin="20,10,0,0" Grid.Column="1" Grid.Row="1" FontSize="14" TextWrapping="WrapWholeWords" /> </Grid> </DataTemplate> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

Dodaj w kontrolkach ListView poniższy atrybut.

ItemTemplate="{StaticResource VideoItemTemplate}"

III. Informacja o braku połączenia z Internetem. Cel: Zapoznanie z konwerterem wartości dla XAML.

1. W przypadku problemu z połączeniem internetowym należy poinformować o tym

użytkownika. W tym celu dodaj na końcu pliku MainPage.xaml, za kontrolką Hub

poniższy kod.

</Hub> <Grid x:Name="gridProblem" Visibility="{Binding IsLoadingError, Converter={StaticResource Converter_Visibility}}"> <StackPanel Orientation="Vertical" Background="Orange" HorizontalAlignment="Stretch" VerticalAlignment="Center" > <TextBlock TextWrapping="Wrap" Foreground="Black" Text="Connection failed" FontSize="40" TextAlignment="Center" Padding="0,10,0,0"/> <TextBlock TextWrapping="Wrap" Foreground="Black" Text="Check your Internet connection" FontSize="20" TextAlignment="Center"/> <TextBlock TextWrapping="Wrap" Foreground="Black" Text="or try again later" FontSize="20" TextAlignment="Center" Padding="0,0,0,10"/> </StackPanel> </Grid> </Grid>

2. Ponieważ właściwość IsLoadingError przyjmuje wartości ze zbioru {true, false}

należy je odpowiednio przekonwertować na napisy zrozumiałe dla atrybutu Visibility

czyli Visible albo Collapsed. W tym celu dodaj do folderu Classes nowy plik klasy

VisibilityConverter i dodaj do niego poniższy kod. Pamiętaj o dodaniu dostępu do

wymaganej przestrzeni nazw Windows.UI.Xaml.Data.

public sealed class VisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { if ((bool)value) return "Visible"; else return "Collapsed";

Page 12: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

11

} public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }

3. Dodaj konwerter Converter_Visibility do pliku MainPage.xaml. Pamiętaj o

dodaniu przestrzeni nazw: xmlns:local="using:<nazwa_projektu>".

<converters:VisibilityConverter x:Key="Converter_Visibility"/>

4. Rozłącz połączenie sieciowe i sprawdź czy aplikacja odpowiednio zareagowała.

IV. Dodawanie przycisku odświeżającego zawartości list. Cel: Zapoznanie z paskiem poleceń oraz dodawaniem do niego przycisku wraz z jego obsługą.

1. Aby umożliwić użytkownikowi ręczne odświeżanie wyświetlanych list należy dodać

odpowiedni przycisk. W tym celu wystarczy do pliku MainPage.xaml dodać poniższy

kod.

</Grid> <Page.BottomAppBar> <CommandBar> <CommandBar.PrimaryCommands> <!-- These commands appear on the right --> <AppBarButton Icon="Refresh" Label="Refresh" Tapped="AppBarButtonRefresh_Tapped"/> </CommandBar.PrimaryCommands> </CommandBar> </Page.BottomAppBar>

Page 13: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

12

</Page>

2. W celu utworzenia pustej funkcji obsługi zdarzenia „Tapped” kliknij na przypisanej jej

nazwie AppBarButtonRefresh_Tapped i naciśnij przycisk F12.

3. Dodaj do nowo powstałej funkcji obsługi zdarzenia następujący kod.

_dataSource.IsLoadingData = true; _dataSource.IsLoadingError = false; _dataSource.SortedByTitleItems.Clear(); _dataSource.RecentItems.Clear(); LoadData();

4. Funkcja LoadData() jest funkcją nieblokującą należy zatem zaczekać na jej wykonanie

wykorzystując słowo kluczowe await. Jego użycie wymaga poinformowania

kompilatora że nowo powstała funkcja obsługi zdarzenia „Tapped” będzie zawierać

asynchroniczne elementy kodu. Robimy to oznaczając ją słowem kluczowym async.

5. Przycisk odświeżania będzie widoczny na pasku poleceń po kliknięciu gdziekolwiek na

ekranie prawym przyciskiem myszy.

V. Dodanie strony odtwarzacza. Cel: Zapoznanie z procesem dodawania nowej strony do aplikacji nowej strony XAML oraz obsługą odtwarzacza Windows Player.

1. Do kontrolek ListView dodaj atrybuty ItemClick i przy pomocy przycisku F12 utwórz

uchwyty do obsługi klinięcia.

Page 14: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

13

ItemClick="ListView_ItemClick"

2. Dodaj do nowej metody następujący kod.

var _video = (YouTubeVideo)e.ClickedItem; this.Frame.Navigate(typeof(PlaybackPage), _video);

3. Dodaj do projektu nowy element Blank Page o nazwie PlaybackPage.

4. Dodaj layout do pliku XAML nowo dodanej strony.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="120"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!-- Back button and page title --> <Grid x:Name="gridTop"> <Grid.ColumnDefinitions> <ColumnDefinition Width="120"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Button x:Name="buttonBack" Style="{StaticResource NavigationBackButtonNormalStyle}" Margin="40,40,0,0" VerticalAlignment="Top" Click="ButtonBack_Click"/> <TextBlock x:Name="textTitle" Margin="0,40,0,0" Text="Title" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" VerticalAlignment="Top" IsHitTestVisible="false" TextWrapping="NoWrap" /> </Grid> <Grid x:Name="gridProblem" Grid.RowSpan="2" Visibility="Collapsed"> <StackPanel Orientation="Vertical" Background="Orange" HorizontalAlignment="Stretch" VerticalAlignment="Center" > <TextBlock TextWrapping="Wrap" Foreground="Black" Text="Connection failed" FontSize="40" TextAlignment="Center" Padding="0,10,0,0"/> <TextBlock TextWrapping="Wrap" Foreground="Black" Text="Check your Internet connection" FontSize="20" TextAlignment="Center"/>

Page 15: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

14

<TextBlock TextWrapping="Wrap" Foreground="Black" Text="or try again later" FontSize="20" TextAlignment="Center" Padding="0,0,0,10"/> </StackPanel> </Grid> <ProgressRing x:Name="progressRingLoading" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="1" Width="100" Height="100" Foreground="Red" IsActive="True"/> </Grid>

5. Aby umożliwić powrót ze strony odtwarzacza na stronę główną dodaj implementację

atrybutu Click="ButtonBack_Click" w elemancie buttonBack.

this.Frame.GoBack();

6. Pobierz i zainstaluj odtwarzacz Microsoft Player Framework (wymagane prawa

administratora).

7. Dodaj referencję do Microsoft Player Framework SDK.

8. W pliku XAML odtwarzacza umieść, wewnątrz kontrolki Grid kontrolkę odtwarzacza

MadiaPlayer.

<mpf:MediaPlayer x:Name="mediaPlayer" DoubleTapped="MediaPlayer_DoubleTapped" Grid.Row="1" IsFullScreenVisible="True" IsScrubbingEnabled="True" />

9. Jego definicja znajduje się w przestrzeni nazw Microsoft.PlayerFramework.

xmlns:mpf="using:Microsoft.PlayerFramework"

10. Dodaj do pliku zawierającego kod C# strony odtwarzacza prywatną zmienną typu

YouTubeVideo przechowywującą film przekazany z głównej strony aplikacji. Dodaj

także przeciążoną metodę OnNavigatedTo ładującą wspomniany film, aktualizującą

nazwę strony oraz aktywującą na czas ładowania filmu kontrolkę ProgressRing.

private static YouTubeVideo _video; protected override async void OnNavigatedTo(NavigationEventArgs e) { if (e.Parameter == null) _video = new YouTubeVideo(); else _video = ((YouTubeVideo)e.Parameter);

Page 16: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

15

textTitle.Text = _video.Title; progressRingLoading.IsActive = true; try { YouTubeUri url = await YouTube.GetVideoUriAsync(_video.VideoId, YouTubeQuality.Quality1080P); mediaPlayer.Source = url.Uri; } catch (Exception) { gridProblem.Visibility = Visibility.Visible; mediaPlayer.Visibility = Visibility.Collapsed; } progressRingLoading.IsActive = false; }

11. W celu obsługi nowo dodanych klas YouTube… wymagane jest dodanie projektu

MyToolkit.Extended, najlepiej przy pomocy menedżera pakietów NuGet. Pamiętaj o

dodaniu dostępu do wymaganej przestrzeni nazw MyToolkit.Multimedia i folderu

DataModel.

12. Dodaj implementację uchwytu MediaPlayer_DoubleTapped z pliku XAML

odtwarzacza pozwalającą na przełączanie pomiędzy pełnym ekranem a oknem.

mediaPlayer.IsFullScreen = !mediaPlayer.IsFullScreen;

13. Sama zmiana wartości IsFullScreen niestety nie wystarczy, musimy jaszcze

zdefiniować i podpiąć odpowiednią metodę do zdarzenia IsFullScreenChanged

obiektu mediaPlayer.

public PlaybackPage() { this.InitializeComponent(); mediaPlayer.IsFullScreenChanged += mediaPlayer_IsFullScreenChanged; } private void mediaPlayer_IsFullScreenChanged(object sender, RoutedPropertyChangedEventArgs<bool> e) { if (e.NewValue) { Grid.SetRow(mediaPlayer, 0); Grid.SetRowSpan(mediaPlayer, 2); gridTop.Visibility = Visibility.Collapsed; } else { Grid.SetRow(mediaPlayer, 1); Grid.SetRowSpan(mediaPlayer, 1); gridTop.Visibility = Visibility.Visible; }

}

VI. Wyświetlanie polityki prywatności.

Page 17: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

16

Cel: Zapoznanie ze sposobem automatycznego generowania strony dotyczącej polityki prywatności.

1. Stronę wyświetlającą politykę prywatności można wygenerować automatycznie

korzystając z witryny: http://w8privacy.azurewebsites.net/.

2. Podaj Nazwę Wyświetlaną Wydawcy (znajdziesz ją w ustawieniach twojego konta

developerskiego), adres email oraz nazwę właśnie tworzonej aplikacji.

3. Skopiuj wygenerowany link z pola adresu przeglądarki

4. Dodaj do projektu nowy element „Settings Flyout”.

5. Dodaj do nowego pliku XAML poniższy kod.

<!-- Content Section 1--> <StackPanel Style="{StaticResource SettingsFlyoutSectionStyle}"> <!-- Section 1 header --> <TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="About the use of personal data." /> <!-- Section 1 body --> <TextBlock Style="{StaticResource BodyTextBlockStyle}" Margin="0,20,0,0" TextWrapping="Wrap" FontFamily="Global User Interface"> <Run> This app uses your internet connection only to download and update content. </Run> <LineBreak/> <LineBreak/> <Run> This application does not: </Run> <LineBreak/> <LineBreak/>

Page 18: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

17

<Run> - Collect and use any personal information. </Run> <LineBreak/> <Run FontFamily="Global User Interface"> - Store any personal data. </Run> <LineBreak/> <Run FontFamily="Global User Interface"> - Share any personal data to third parties. </Run> </TextBlock> <HyperlinkButton Margin="0,20,0,0" Content="Online Privacy Policy" NavigateUri="Your Privacy Policy URL here." /> </StackPanel> <!-- Define more Content Sections below as necessary -->

6. W miejscu „Your Privacy Policy URL here.” Podaj skopiowany wcześniej link

URL. Należy zastąpić wszystkie znaki „&” na „&amp;” ponieważ są niezgodne ze

specyfikacją XML a w szczególności z XAML. W oknie designera powinna pojawić na

się podobna strona.

7. W pliku MainPage.cs należy dodać poniższy kod do konstruktora, uczyni to naszą

stronę dostępną.

SettingsPane.GetForCurrentView().CommandsRequested += MainPage_CommandsRequested;

8. Oczywiście musimy jeszcze zaimplementować odpowiednią metodę.

Page 19: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

18

SettingsCommand privacyCommand = new SettingsCommand("privacy", "Privacy Policy", (handler) => { PrivacyFlyout privacyFlyout = new PrivacyFlyout(); privacyFlyout.Show(); }); args.Request.ApplicationCommands.Add(privacyCommand);

9. Oraz przeciążyć metodę OnNavigatedFrom wyrejestrowującą nasz uchwyt.

protected override void OnNavigatedFrom(NavigationEventArgs e) { base.OnNavigatedFrom(e); SettingsPane.GetForCurrentView().CommandsRequested -= MainPage_CommandsRequested; }

10. Strona w akcji:

VII. Finalizacja aplikacji. Cel: Zapoznanie z ostatnimi czynnościami wymaganymi przed opublikowaniem aplikacji.

1. Należy jeszcze zmienić jeszcze kilka ustawień w pliku manifestu. W sekcji „Application”

dodaj wyświetlaną nazwę oraz opis aplikacji.

Page 20: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

19

2. W zakładce „Visual Assets” wypełnij pola podobnie jak na poniższym rysunku. Ponownie

użyj wyświetlanej nazwy aplikacji.

3. Na koniec w zakładce „Packaging” sprawdź wyświetlaną nazwę oraz wyświetlaną nazwę

wydawcy.

VIII. Utworzenie pliku aplikacji gotowego do umieszczenia w sklepie. Cel: Zapoznanie z kolejnymi krokami wymaganymi do utworzenia i wstępnej walidacji pliku aplikacji.

1. Aby utworzyć plik aplikacji należy zapisać zmiany w projekcie i przebudować projekt

(Rebuild).

Page 21: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

20

2. Wybrać „PROJECT” → „Store” → „Create App Packages…” → „Yes” → „Next” →

(należy się zalogować do konta developerskiego w celu automatycznego podpisania

aplikacji naszym certyfikatem developera). Następnie w poniższym oknie należy wybrać

opcję „Next”.

3. W kolejnym oknie zostawiamy domyślne wartości i klikamy „Create”

Page 22: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

21

4. Teraz możemy dokonać wstępnej walidacji (wymagane uprawnienia administratora).

5. Zostawiamy zaznaczone wszystkie dostępne testy i klikamy „Dalej”.

Page 23: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

22

6. Czekamy z nadzieją, że wszystkie testy zostaną zaliczone, i zobaczymy poniższe okno.

IX. Publikowanie aplikacji w Windows Store. Cel: Zapoznanie z czynnościami wymaganymi do opublikowania aplikacji w Windows Store.

1. Zaloguj się do własnego pulpitu developera. Wybierz aplikację do publikacji. W sekcji

„Submissions” wybierz „Pricing and availability”.

2. Ustal „Base price” na „Free” i zatwierdź przyciskiem „Save”. Domyślnie aplikacja będzie

dostępna na 242 rynkach, należy uważać jeśli zawiera ona kanał powiązany tematycznie z

hazardem, alkoholem, nieodpowiednim humorem lub treściami dla dorosłych może nie

przejść certyfikacji na pewnych rynkach zachodnich.

3. Następnie w „App properties” wybierz kategorię do której aplikacja będzie się zaliczać

oraz wymagania wiekowe. Dla „normalnych” aplikacji 12+ jest optymalnym wyborem.

Page 24: Instrukcja laboratoryjna cz - stos.eti.pg.gda.pl

23

4. W sekcji „Packages” należy wybrać opcję „browse to files” i dodać pliki utworzonej

aplikacji. W tym przypadku pliki z rozszerzeniem *.appxupload z folderu AppPackages.

5. W menu „Descriptions” musimy dodać przynajmniej opis i po jednym zrzucie ekranu

działającej aplikacji dla wersji desktopowej i mobilnej. Dla wersji mobilnej należy

skorzystać z symulatora.

6. Sekcja „Notes for certification” jest opcjonalna. Jeśli chcemy – możemy poinformować

testerów o szczegółach naszej aplikacji. W naszym przypadku nie jest to wymagane.

7. Po wykonaniu wymaganych 4 kroków nasza aplikacja jest gotowa do wysłania do sklepu.

Proszę potwierdzić klikając „Submit to the store”.

8. Na koniec przypominam o wyrejestrowaniu konta developerskiego z komputera

laboratoryjnego. Informacja jak to zrobić podana została na początku 2 rozdziału –

Tworzenie aplikacji Windows Store (C# i XAML).