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
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.
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" />
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
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)
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.
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;
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()
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}
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>
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";
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>
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.
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"/>
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);
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.
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/>
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 „&” 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ę.
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.
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).
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”
21
4. Teraz możemy dokonać wstępnej walidacji (wymagane uprawnienia administratora).
5. Zostawiamy zaznaczone wszystkie dostępne testy i klikamy „Dalej”.
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.
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).
Top Related