View
2.075
Download
1
Category
Preview:
DESCRIPTION
Podstawy tworzenia aplikacji dla Windows 8 (Modern UI) w XAML, C# i komponentach WinRT.
Citation preview
Programowanie Windows 8
Bartłomiej ZassTechnical EvangelistMicrosoft Polska
Na czym się skupimy?
Trochę o pisaniu w HTML 5 XAML i Windows 8 ASP.NET (czasem trochę) - C# (jeśli zdążymy) - Windows Phone
MS-DOS Executive, 1985 r.
Niepełny OS – tylko warstwa na MS-DOS
Windows 95
Win32 – uzupełnianie granicy między 16-biti 32-bit
Hello, world w C++
#include<iostream.h>int main(){ cout << "Hello World" << endl; return 0;}
Hello, World w Win32 (MFC)#include <afxwin.h>class HelloApplication : public CWinApp{public:virtual BOOL InitInstance();};HelloApplication HelloApp;class HelloWindow : public CFrameWnd{CButton* m_pHelloButton;public:HelloWindow();};BOOL HelloApplication::InitInstance(){m_pMainWnd = new HelloWindow();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;}HelloWindow::HelloWindow(){Create(NULL,"Hello World!",WS_OVERLAPPEDWINDOW|WS_HSCROLL,CRect(0,0,140,80));m_pHelloButton = new CButton();m_pHelloButton->Create("Hello World!",WS_CHILD|WS_VISIBLE,CRect(20,20,120,40),
COM – od 1993
Model komponentowy Wygodniej i łatwiej w VB
Komunikacja między procesami C -> brak obiektów C++ -> współdzielenie kodu między programistami COM -> komunikacja między procesami SOA -> komunikacja między usługami, systemami
.NET Framework
Prace od 1990 r. Next Generation Windows Services (NGWS) Pierwsza beta – 2000 r. MSIL, CLR, CTS, Garbage Collector, … Windows Forms
GDI/GDI+ - bezpośredni dostęp do hardware’u 2006 r. - .NET Framework 3.0
WPF – Windows Presentation Foundation XAML
NUI
iPad – 2010 r. 15 milionów urządzeń w pierszym roku
Natural User Interface (NUI) Historia maszyny do pisania (1870 r.) – Christopher Sholes Mysz – 1960r., Xerox
Kiedy jedno kliknięcie, kiedy dwa, … iPhone (2007 r.), Nintendo Wii, … Kinect – 2009 r. Obecnie – konsumeryzacja IT (Gartner), BYOD
Windows Store Application
WinRT
W przeciwieństwie do Win32 – object oriented Wiele języków COM, projekcje DirectX zamiast GDI Application Container i zamrażanie (w desktop przesłonięte działa) Bezpośrednie wywołania do kernela lub brokered call
WinRT
WinRT – c.d.
Oparte o COM Zgodne z Application Binary Interface (ABI) – interface między
systemem i komponentami Iinspectable, Iunknown
Reference counting Javascript – własny garbage collector .NET – COM Interop, komunikacja przy pomocy Runtime Callable
Wrapper (RCW)
Wiele typów urządzeń
DemoWindows 8
Modern UI
Windows Store
Duży zasięg
Integracja z przeglądarką
Transparentny proces
Różne modele biznesowe
Wysoki zysk dla programistów
Windows Store
Integracja z IE
Get the app / switch to the app <meta name="msApplication-ID"content="microsoft.build.App"/> <meta name="msApplication-PackageFamilyName"content="microsoft.build_8wekyb3d8bbwe"/>
Pinned sites Badges Polling
<META name="msapplication-badge" content="frequency=30; polling-uri=http://mysite.com/id45453245/polling.xml"/>
Ręczne odświeżenie z JS window.external.msSiteModeRefreshBadge();
<badge value = "1-99" | "none" | "activity" | "alert" | "available" | "away" | ... version? = integer />
Link previews (share) - thumbnail Direct invoke
Sideloading Warunki
Windows 8 Enterprise lub Windows Server 2012 Dołączenie do domeny
Windows 8 Pro, Windows RT lub nie dołączony do domeny Zakupiony Sideloading Product Activation Key
Visual Studio Express ;) Uwaga: teoretycznie monitorowane
Instalacja Per user – skrypty powershell Przygotowany obraz przez IT
Podpisanie aplikacji zaufanym certyfikatem Group Policy
Wymagane: Allow all trusted applications to install Dostęp do Windows Store i aktualizacji (np. zablokowanie)
Sideloading - group policy
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Appx\AllowAllTrustedApps = 1
Sideloading – c.d.
Wgranie certyfikatu użytego do podpisania aplikacji PowerShell
import-module appx add-appxpackage \\udziałsieciowy\app1.appx Get-AppxPackage –AllUsers (listuje pakiety) Remove-AppxPackage Package1
DISM /Online /Add-ProvisionedAppxPackage /PackagePath:C:\App1.appx /SkipLicense (przygotowanie obrazu)
Windows Store
Domyślny trial + zakupy – odblokowane dla wszystkich kont GetAppReceiptAsync – per device, per user
AppReceipt ProductReceipt Signature https://go.microsoft.com/fwlink/?
LinkId=246509&cid=b809e47cd0110a4db043b3f73e83acd917fe1336
Receipt<Receipt Version="1.0" ReceiptDate="2012-08-28T22:11:33Z" CertificateId="b809e47cd0110a4db043b3f73e83acd917fe1336"
ReceiptDeviceId="4e362949-acc3-fe3a-e71b-89893eb4f528">
<AppReceipt Id="8ffa256d-eca8-712a-7cf8-cbf5522df24b" AppId="55428GreenlakeApps.CurrentAppSimulatorEventTest_z7q3q7z11crfr" PurchaseDate="2012-06-04T23:07:24Z" LicenseType="Full" />
<ProductReceipt Id="2559fa9a-9f86-0525-e655-536a6c96fac6" ProductId="Product1" PurchaseDate="2012-06-04T23:07:50Z" ExpirationDate="2012-06-07T23:07:49Z" ProductType="Durable" AppId="55428GreenlakeApps.CurrentAppSimulatorEventTest_z7q3q7z11crfr" />
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> <Reference URI=""> <Transforms> <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> <DigestValue>npmBq7pdtq9FkfILSsHuVyD+QWiZg6J/klBKsyWhrw8=</DigestValue> </Reference> </SignedInfo>
<SignatureValue>LKZSHmk6XjLaEHoJPFBB1GxVsFf2(...) 9PiVyBEOlZw==</SignatureValue></Signature>
Windows 8 PlatformWindows Store Apps
HTMLJavaScript
CC++
C#VB
Desktop Apps
Win32 .NET / SL
Internet Explorer
Communication & Data
Application Model
Devices & Printing
WinRT APIs
Graphics & Media
Syst
em S
ervi
ces
JavaScript(Chakra)
CC++
C#VB
XAML HTML / CSSView
Mod
el
Cont
rolle
r
Windows Core OS ServicesCore
WinRT API z bliska
Fundamentals
Application Services Threading/Timers Memory Management Authentication Cryptography Globalization
DevicesGeolocation Portable Sensors NFC
User Interface
SVG Tiles Input Accessibility Printing
HTML5/CSS XAML DirectX Controls Data Binding
Communications & Data
Memory Management XML Networking SMS
Notifications Streams
Contracts Local & Cloud Storage Web
MediaPlayback Capture PlayTo Visual Effects
WinRT
Aplikacja jest też komponentem HKEY_CURRENT_USER→Software→Classes→Activatable
Classes→Package Dane paczki, host uruchomieniowy
HKEY_CURRENT_USER→Software→Classes→Extensions→ContractId Kontrakty Tile – tak naprawdę Launch contract
Kilka przykładów użycia Javascript...
Aplikacje dla Windows 8 Gry – np. Cut The Rope, Angry Birds PhoneGap Node.js Sharepoint Rozszerzenia Office 2013 Azure Mobile Services Inne ciekawostki
http://jscriptlinq.codeplex.com/ - LINQ w JS http://bellard.org/jslinux/ - implementacja Linux w JS
DemoTypescript
HTML 5 i Windows 8
Windows 8 – akcelerowana platforma HTML
CSS 2D Transforms
CSS 3D Transforms
CSS Animations
CSS Backgrounds & Borders
CSS Color
CSS Flexbox
CSS Fonts
CSS Grid Alignment
CSS Hyphenation
CSS Image Values (Gradients)
CSS Media Queries
CSS multi-column Layout
CSS Namespaces
CSS OM Views
CSS Positioned Floats (Exclusions)
CSS Selectors
CSS Transitions
CSS Values and Units
Data URI
DOM Element Traversal
DOM HTML
DOM Level 3 Core
DOM Level 3 Events
DOM Style
DOM Traversal and Range
DOMParser and XMLSerializer
ECMAScript 5
File APIs
FormData
HTML5 Application Cache
HTML5 async
HTML5 Canvas
HTML5 Drag and drop
HTML5 Forms and Validation
HTML5 Geolocation
HTML5 History API
HTML5 Parser
HTML5 Sandbox
HTML5 Selection
HTML5 semantic elements
HTML5 video and audio
ICC Color Profiles
IndexedDB
Page Visibility
Pointer (Mouse, Pen, and Touch) Events
Selectors API Level 2
Filter Effects
SVG, standalone and in HTML
Timing callbacks
Web Messaging
Web Sockets
Web Workers
XHTML/XML
XMLHttpRequest (Level 2)
Najpopularniejsze cechy HTML5Web Sockets
Web Workers
IndexedDB
Ecmascript 5
File API & Blobs
Geolocation
Audio tag
Video tag
Touch-first
Pointer events
Zoom regions
Snap Points
Forms
Validation
Input types
Spell checking
DemoIE 10 i HTML 5, CSS 3
WinJS
Helpers for Namespaces, Constructor Definition
Promises
App Model
Navigation
Page & User controls
Data binding
Controls
Animations
Templates
Utilities
Default CSS Styles
jQuery, XHR i local context
jQuery xhr robi cross-domain check (wer. > v1.6) W kontekście lokalnym, jesteśmy w “ms-wwa://{something}” Błąd przy cross domain check
Workaround Skorzystaj z WinJS XHR Powiedz jQuery aby pominąć weryfikację
$.support.cors = true; http://api.jquery.com/jQuery.support/
Zabezpieczenia hosta
Zabezpieczenie przed wstrzykiwaniem “złego” HTMLa Skrypty, iframes, event handlers, itp.
Wywyływane gdy korzystamy z innerHTML outerHTML setAdjacentHTML
Atrybuty “data-” również nie są dozwolone Specyficzne dla WinJS są OK
Wyłączenie zabezpieczeń
toStaticHTML method DOM creation APIs WinJS.Utilities.setInnerHTMLUnsafe msWWA.execUnsafeLocalFunction
DemoWindows 8 i HTML
XAML - podstawy
XAML - podstawy
Dialekt XML Wprowdzony przez WPF, następnie Silverlight, Windows Phone,
Windows 8 Także inne technologie (składniowo) – np. WF Drzewo kontrolek Style, animacje, bindingi
Zdarzenia
W WPF różne – routed, bubbling, tunnel, … W Silverlight / Windows Phone / Windows 8 – routed
Zdarzenie wędruje w górę drzewa Można je zatrzymać – e.Handled = true
Hierarchia klas
Dependency Object (dependency property system) UIElement (klawiatra, touch, …)
FrameworkElement (layout, loaded / unloaded, binding, style)
Dependency Property
public static readonly DependencyPropertyMyNumberProperty = DependencyProperty.Register("MyNumber",typeof (int),typeof (MyDependencyObject),new PropertyMetadata(2, OnMyNumberPropertyChange));
Attached Property
Doklejanie swoich atrybutów do innych kontrolek Wszystkie inne zalety DP (style, animacje, itp.)
var row = ValueText.GetValue(Grid.RowProperty);
Opakowanie jakiejś funkcjonalności
Wspierane przez designer
Attached Property
public static readonly DependencyProperty IsShareButtonProperty =DependencyProperty.RegisterAttached("IsShareButton",typeof(Boolean),typeof(MagicButton),new PropertyMetadata(false,new PropertyChangedCallback(Changed)));
<Grid.DataContext><local:MyDependencyObject/>
</Grid.DataContext>
Bindowanie
POCO WinRT + BindbleAttribute lub ICustomPropertyProvider
<TextBlock Text="{Binding ElementName=Slider, Path=Value}"/><TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=FontSize}"/>
Two-way binding
Dependency Properties INotifyPropertyChanged
Zdarzenie PropertyChanged Czasem łączenie z CallerMemberName Model danych nie powinien być z UI – często konieczna implementacja
Binding - inne
Konwertery Statyczne zasoby
Lokalne Globalne
Style
Globalne / lokalne Resource Dictionaries
<ResourceDictionary Source="Common/StandardStyles.xaml"/>
var firstOne = (Storyboard)MainGrid.Resources["FirstOneAnimation"];
foreach (var storyboard in MainGrid.Resources.Values.OfType<Storyboard>()){
storyboard.Begin();}
Dzień 2Programowanie Windows 8
Przypomnienie
Windows 8, Windows Store, sideloading, itp. Trochę o HTML 5, TypeScript i Windows 8 + Blend XAML - wprowadzenie
Dependency properties, attached property User control Binding, datacontext, konwertery Style, zasoby Blend + edycja template’u
Demo
Animacje
StoryBoard Wykorzystywany w wielu miejscach – np. stany i szablony kontrolek 2 typy – klasyczny i keyframe (object.property).(object.property)
<Storyboard x:Name="FirstOneAnimation"Storyboard.TargetName="FirstOne">
<DoubleAnimation Duration="0:0:5"Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.X)"From="-300" To="300"/>
</Storyboard>
Timeline (klasa bazowa)
Storyboard – c.d.
ColorAnimation DoubleAnimation PointAnimation ObjectAnimationUsingKeyFrames
Layout Główny element – Frame Wewnątrz Frame – Page Komponowanie ekranu z różnych layoutów
Canvas Grid StackPanel VirtualizingStackPanel WrapGrid VariableSizedWrapGrid ContentControl ItemsControl ScrollViewer ViewBox
Podstawowe kontenery na dane
GridView ListView ListBox FlipView
Źródło danych - CollectionViewSource
AppBar
<Page.BottomAppBar><AppBar x:Name="AppBar" Margin="10,0,10,0">
<local:ApplicationCommand x:Name=”AppBarCommands”/>
</AppBar></Page.BottomAppBar>
Demo
Windows 8 i XAML
Wywoływanie kodu natywnego z C#[DllImport("avicap32.dll", EntryPoint="capCreateCaptureWindow")]static extern int capCreateCaptureWindow( string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);
[DllImport("avicap32.dll")] static extern bool capGetDriverDescription( int wDriverIndex, [MarshalAs(UnmanagedType.LPTStr)] ref string lpszName, int cbName, [MarshalAs(UnmanagedType.LPTStr)] ref string lpszVer, int cbVer);
// więcej i więcej w podobny sposób...
...a w Windows 8
using Windows.Media.Capture;
var ui = new CameraCaptureUI();ui.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
var file = await ui.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (file != null) { var bitmap = new BitmapImage() ;
bitmap.SetSource(await file.OpenAsync(FileAccessMode.Read)); Photo.Source = bitmap;
}
Integralna część komponentu WinRT – metadane (tzw. WinMD) Standard zgodny z ECMA-355 (.NET) CLR wiąże definicje z implementacją automatycznie
Visual Studio 2012 „patrzy” na WinRT przez pryzmat WinMD Natywny dla danego języka sposób wywoływania komponentu
C:\Windows\System32\WinMetadata
Projekcje językowe
Projekcje językowe
WindowsRuntime
Object(or Component)
Writtenin C++, C#, VB
Windows Metadata
C++ App
Projection
CLR
C#/VB App
ProjectionHTML AppChakra
Projection
ImageEncodingProperties^ imageProperties = ref new ImageEncodingProperties();imageProperties->Subtype = „JPEG”;imageProperties->Width = 320;imageProperties->Height = 240;
auto opCapturePhoto = m_mediaCaptureMgr->CapturePhotoToStorageFileAsync(imageProperties,this->m_photoStorageFile);
ImageEncodingProperties imageProperties = new ImageEncodingProperties();imageProperties.Subtype = „JPEG”;imageProperties.Width = 320;imageProperties.Height = 240;await mediaCaptureMgr.CapturePhotoToStorageFileAsync(imageProperties, photoStorageFile);
var photoProperties = new Windows.Media.MediaProperties.ImageEncodingProperties();photoProperties.subtype = „JPEG”;photoProperties.width = 320;photoProperties.height = 240;mediaCaptureMgr.capturePhotoToStorageFileAsync(photoProperties, photoStorage).then(…
C++
C#
JavaScript
Bezpośrednie mapowania
Primitives(strings, numbers,
etc) Interfaces Enums Structs Delegates Classes
Constructors Static Members Methods Properties Events
.NET i Windows Runtime
IReadOnlyDictionary<K,V>IMapView<K,V>
IEnumerable<T>IIterable<T>
IList<T>IVector<T>
IReadOnlyList<T>IVectorView<T>
IDictionary<K,V>IMap<K,V>
Konwersje typów
FileOpenPicker picker = new FileOpenPicker();picker.FileTypeFilter.Add("*");
StorageFile file = await picker.PickSingleFileAsync();
Windows.Storage.Streams.IInputStream inputStream = await file.OpenForReadAsync();
System.IO.Stream stream = inputStream.AsStream();System.IO.StreamReader reader = new StreamReader(stream);
string contents = reader.ReadToEnd();
String – nie może być null Przy próbie przekazania do komponentu WinRT – exception Nigdy nie otrzymamy null od komponentu WinRT
Tablice, kolekcje - read-only lub write-only void PassArray([In] int[] array); void FillArray([Out] int[] array, out int size);
Interfejs, nie implementacja List<string> vs IList<string>
Virtual - nie Uri – tylko absolute DateTime – tracimy informację o strefie czasowej
Kiedy należy uważać
Możesz tworzyć własne komponenty WinRT Logika wywoływana przez C# / JS / C++
2 typy komponentów Natywne – C++ .NET – C# / VB
Własne komponenty WinRT
Sygnatury API muszą wykorzystywać typy WinRT Tylko dla publicznych typów i właściwości Część typów ma sposoby na konwersję – np. extension methods
Struktury mogą mieć tylko publiczne pola Wszystkie typy muszą być oznaczone jako sealed
(oprócz kontrolek XAML) Tylko systemowe typy ogólne
Własne komponenty WinRT – zasady
Pod spodem klasyczny .NET (aplikacje pisane w C#) Specjalny profil dla aplikacji Windows Store Sztuczki z Reflection – nie przejdą przez certyfikację Windows Store Class Libraries lub Portable Class Libraries
Dozwolone niektóre API COM i Win32 Lista dozwolonych API
Dozwolone API
Dystrybucja komponentów WinRT
Nie mogą być dystrybuowane w sklepie samodzielnie Nie mogą być współdzielone pomiędzy aplikacjami Mogą być sprzedawane developerom
DemoWłasny komponent WinRT, integracja z HTML
Interfejs ma być „Fast & Fluid” Wszystkie API trwające >50 ms muszą być asynchroniczne
API bazują na Task<T>
Asynchroniczność
var data = DownloadData(...);ProcessData(data);
var future = DownloadDataAsync(...); future.ContinueWith(data => ProcessData(data));
DownloadDataAsync
ProcessData
STOP
ProcessDataDownloadData
private void DownloadPage(){ WebClient client = new WebClient(); client.DownloadStringCompleted += (o, e) => { if (e.Error == null) { WebClient client2 = new WebClient(); client2.DownloadStringCompleted += (o, e) => { if (e.Error == null) { ... } }; client2.DownloadStringAsync(new Uri("http://www.microsoft.com")); } }; client.DownloadStringAsync(new Uri("http://www.bing.com"));}
Asynchroniczność - trudności
private async void DownloadPage() { HttpClient client = new HttpClient(); string bing = await client.GetStringAsync("http://www.bing.com"); string ms = await client.GetStringAsync("http://www.microsoft.com");
naszTextbox.Text = ms; }
Asynchroniczność w Windows 8 – C#
Asynchroniczność w C#
Task<T> async, await
Automatyczna transformacja na callbackową maszynę stanów Asynchroniczne metody
Oznaczone nowym słowem kluczowym “async” Muszą zwracać void lub Task<T> Wykorzystują operator “await” do przekazania kontroli Wskrzeszane, kiedy operacje zostają zakończone Łączone z klasycznymi konstrukcjami językowymi Wygląda jak stary, prosty kod synchroniczny!
Inne Windows Phone 7 – async CTP Silverlight 5 i .NET 4 - Async Targeting Pack
Automatyczna transformacja na callbackową maszynę stanów
Asynchroniczne metody Oznaczone nowym słowem kluczowym “async” Muszą zwracać void lub Task<T> Wykorzystują operator “await” do przekazania kontroli Wskrzeszane, kiedy operacje zostają zakończone Łączone z klasycznymi konstrukcjami językowymi
Wygląda jak stary, prosty kod synchroniczny!
Async, await
Task t, t1, t2 = ...
// Task chainingTask t3 = t.ContinueWith( () => { ... } );
Task[] taskCollection = new Task[] { client.GetStringAsync("http://www.bing.com"), client.GetStringAsync("http://www.bing.com"),};
// Task, który wykona się po zakończeniu tasków t1 i t2Task t4 = t.WhenAll(taskCollection);
// Oczekiwanie na zakończenie taskówTask.WaitAll(taskCollection);Task.WaitAny(taskCollection);
Taski - łączenie
// Wywołanie kodu w innym wątku z ThreadPool – jako Task
int result = await Task.Run(async () => { // Tu długotrwałe przetwarzanie danych w innym wątku... // ...
await Task.Delay(1000); return 42; });
Dowolny kod jako Task
Przykłady
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
Button b = (Button) sender;
await Task.Run(() => {
b.Content += ".";
});
}
private async void Button_Click_2(object sender, RoutedEventArgs e)
{
Button b = (Button) sender;
await b.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => {
b.Content += ".";
});
}
Przykłady
Windows.Media.Capture.CameraCaptureUI ccui;
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
ccui = new Windows.Media.Capture.CameraCaptureUI();
await Task.Run(() => {
ccui.PhotoSettings.AllowCropping = true;
});
}
Windows.Media.Capture.CameraCaptureUI ccui;
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
ccui = new Windows.Media.Capture.CameraCaptureUI();
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() => {
ccui.PhotoSettings.AllowCropping = true;
});
}
public Task<string> GetStringAsync(Uri uri) { var tcs = new TaskCompletionSource<string>(); // .....długotrwała operacja asynchroniczna
var wc = new WebClient(); Wc.DownloadCompleted += (s, e) => { if (e.Error != null) { tcs.TrySetException(e.Error); } else if (e.Cancelled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(e.Result); } }; return tcs.Task; }
Opakowanie kodu w Task<T>
// tzw. Promises
WinJS.xhr({ url:"http://www.example.org/somedata.json"}).then(function (response) { updateDisplay( JSON.parse(response.responseText));}, function (ex) { reportXhrError(ex);});
Asynchroniczność w Windows 8 - Javascript
Asynchroniczność
Każde wywołanie API, które zajmuje powyżej 50 ms Dotychczas uciążliwe pisanie wielu callbacków
JavaScript .then .done (tzw. Promise)
C# async await CancellationToken, TPL, Task<T>, …
C++ Różne biblioteki Klasa task, metoda .then
Promises - asynchroniczność
Obietnica dostarczenia wartości w przyszłości Wiązane przez metodę then()
then(completion, error, progress) then() zwraca kolejny obiekt promise Implementacja w base.js: WinJS.Promise
Promise
WinJS.xhr({ url:"http://www.example.org/somedata.json"}).then(function (response) { updateDisplay( JSON.parse(response.responseText));}, function (ex) { reportXhrError(ex);});
DemoAsync w Windows 8
Cykl życia aplikacji
Uruchomionaaplikacja Zawieszona
zawieszanie Zamknięta
aplikacjaBrak pamięci
Kod jest wywoływany Kod wstrzymany Aplikacja wyłączona
wznawianie
App gets 5s to handle suspend
App is not notified before termination
Apps are notified when they have been resumed
Użytkownik uruchamia
Splash screen
Cykl życia aplikacji – c.d.
Wstrzymanie aplikacji Fizycznie pozostaje w pamięci
Zamknięcie Zamknięta przez użytkownika System potrzebuje pamięci Przełączenie użytkownika Wyłączenie komputera Wyjątek Brak notyfikacji!
Zapis stanu - najlepsze praktyki
Scenariusz Powinniśmy….
Użytkownik pracuje z aplikacją
Inkrementalny zapis stanu
Aplikacja wstrzymywanaZapisanie informacji gdzie jest użytkownik (np. aktywna strona)
Aktywacja wyłączonej aplikacji
Odczyt sesji tak, aby aplikacja sprawiała wrażenie nie zamkniętej
Aktywacja zawieszonej aplikacji
Nic nie rób
Aktywacja
// Override App’s OnLaunched
protected async override void OnLaunched(LaunchActivatedEventArgs args){ if (args.PreviousExecutionState == ApplicationExecutionState.Terminated) { // Do an asynchronous restore await SuspensionManager.RestoreAsync(); }
if (args.Kind == ActivationKind.Launch) { if ( !string.IsNullOrEmpty ( args.Arguments ) { // handle arguments } } else if ( args.Kind == ActivationKind.ShareTarget ) { } // … }
Wznawianie
App.Current.Suspending += OnSuspending;
void OnSuspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e){} App.Current.Resuming += OnResuming;
void OnResuming(object sender, object e)}// Z reguły nie potrzebne
Splash screen
Domyślnie – grafika w manifest 15 sekund na wyświetlenie pierwszej strony Extended Splash Screen
Przekierownie na inną stronę od razu (progress bar) Doczytywanie na drugiej stronie
DemoTask switchingSplash screen
Podstawowy szablon projektu
SuspensionManager Zarządzanie stanem aplikacji (lokalny dla stron, globalny)
Serializuje wynik pracy do: %userprofile%\appdata\local\packages\...\LocalState\_sessionState.xml
LayoutAwarePage Klasa bazowa dla wszystkich stron
Przełączanie Visual State (dla snapped, filled, itp.)
Nawigacja
Zarządzanie stanem
DefaultViewModel
Konwertery, style (przycisk wstecz, itp.), klasa bazowa (INotifyPropertyChanged)
SuspensionManager RegisterFrame - rejestruje do automatycznego zapisywania / przywracania historii nawigacji Dependency property dla klasy Frame
FrameSessionStateKeyProperty FrameSessionStateProperty
Stan globalny - SuspensionManager.SessionState[„MojKlucz”] Uwaga na zarejestrowne „Frames”!
Sesja – struktura MojFrame1 (z reguły tylko jeden)
[„Navigation”, string] [„page-1”, Dictionary<string, object>]
[„GodzinaUruchomienia”, ...] ...
[„page-2”, Dictionary<string, object>] ...
[MojFrame2, ...] [MojKlucz, ...]
LayoutAwarePage – stan lokalny stron Automatyczne zapisywanie / wczytywanie stanu lokalnego
LoadState – przekazany stan oraz parametr nawigacyjny SaveState – przekazany kontener do uzupełnienia
Usuwanie stanu, kiedy nawigujemy na nową stronę
Stan lokalnyprotected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState){
var group = SampleDataSource.GetGroup((String)navigationParameter);this.DefaultViewModel["Group"] = group;this.DefaultViewModel["Items"] = group.Items;
if (pageState != null && pageState.ContainsKey("Date")){
pageTitle.Text = (String)pageState["Date"];}
}
protected override void SaveState(Dictionary<string, object> pageState){
pageState["Date"] = pageTitle.Text;base.SaveState(pageState);
}
DemoZarządzanie stanem
LayoutAwarePage - nawigacja
GoBack, GoHome, GoForward Mysz - wstecz / dalej Klawiatura – wstecz / dalej
Domyślnie – zawsze nowa instancja po back (inaczej niż w WP) Możliwość zmiany NavigationCacheMode – zachowanie jak w WP
Zarządzanie stanem wizualnym
WindowSizeChanged Zmiana stanu (filled / snapped, itp.) Zmiana orientacji ekranu
Visual States FullScreenLandscape Filled FullScreenPortrait Snapped
DemoLayoutAwarePage – c.d.Binding
Środowisko uruchomieniowe i uprawnienia Paczka aplikacyjna
App Manifest Blockmap – hashe wszystkich plików Podpis – sprawdza spójność
Model uprawnień App Container i System Broker Capabilities Permissions
Izolacja procesów
DemoCapabilities
Klient bliski Silverlightowi czy Windows Phone Obecnie brak WCF RIA Services
Obsługiwane typy komunikacji HttpClient (JSON, XML, ...) Usługi ASMX WCF ODATA Sockets
Bindingi WCF BasicHttpBinding NetTcpBinding NetHttpBinding CustomBinding
Windows 8 i usługi
Komunikacja
HttpClient (brak WebClient) DownloadOperation / BackgroundDownloader – kiedy potrzebny
progress XmlDocument.LoadFromUriAsync – kiedy wczytujemy XML WCF – specjalne proxy dla async/await
public async Task<string> MakeWebRequest(){ HttpClient http = new System.Net.Http.HttpClient(); HttpResponseMessage response = await http.GetAsync("http://www.example.com"); return await response.Content.ReadAsStringAsync();}
// Parse the JSON datavar array = JsonArray.Parse(result);
foreach (var item in array){
var obj = item.GetObject(); RecipeDataItem recipe = new RecipeDataItem();
foreach (var key in obj.Keys) { IJsonValue val; if (!obj.TryGetValue(key, out val)) continue;
switch (key) { case "key": recipe.UniqueId = val.GetNumber().ToString(); break; case "title": recipe.Title = val.GetString(); break;
case "ingredients": var ingredients = val.GetArray(); var list = (from i in ingredients select i.GetString()).ToList(); recipe.Ingredients = new ObservableCollection<string>(list); break;
}}
Json - serializacja [DataContract] internal class Person { [DataMember] internal string name;
[DataMember] internal int age; }
// Klasycznie (DataContractJsonSerializer)MemoryStream stream1 = new MemoryStream();DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Person));stream1.Position = 0;Person p2 = (Person)ser.ReadObject(stream1);
// Newtonsoft Json (nuGet) – szybciej i bardziej elastycznieMyObject obj = JsonConvert.DeserializeObject<MyObject>(jsonEncodedString);
Live Connect Single sign on (SSO) Możliwe wykorzystanie kontekstu użytkownika
WebAuthenticationBroker Integracja z innymi usługami OAUTH 2.0 Bezpieczny, gotowy mechanizm logowania Facebook, Google, Flickr, Twitter, Live
Uwierzytelnienie – zewnętrzne usługi
await WebAuthenticationBroker.AuthenticateAsync()
DemoWCF, ASP.NET MVC Web API
Baza relacyjnaJetAPI C++, JetCreateDatabase2 itp. (to samo co AD, Exchange itp.)
IndexedDBHTML5, ale..
IDBDatabase
SQLite (wersja Release by przeszła WACK!)
SQLiteExtension + biblioteka kliencka z Nuget
Kompilować w Release – inaczej nie przejdzie WACK
DemoBaza danych
Semantic zoom
Zmiana „kontekstu” listy na bardziej ogólny Ctrl + rolka, ctrl +/-, przycisk
Kontrolka SemanticZoom ZoomedInView ZoomedOutView
ISemantizZoomInformation ListView GridView
Źródło dla zoomin i zoomout musi być powiązane CollectionViewSource - this.groupedItemsViewSource.View.CollectionGroups;
<CollectionViewSource x:Name="groupedItemsViewSource" Source="{Binding Groups}" IsSourceGrouped="true" ItemsPath="TopItems"/>
// ItemsPath – dla grup LINQ nie jest potrzebne
List<Activity> Activities = new List<Activity>(); Activities.Add(new Activity() { Name = "Activity 1", Complete = true, DueDate = startDate.AddDays(4), Project = "Project 1" }); Activities.Add(new Activity() { Name = "Activity 2", Complete = true, DueDate = startDate.AddDays(5), Project = "Project 1" }); Activities.Add(new Activity() { Name = "Activity 3", Complete = false, DueDate = startDate.AddDays(7), Project = "Project 1" }); Activities.Add(new Activity() { Name = "Activity 4", Complete = false, DueDate = startDate.AddDays(9), Project = "Project 1" }); Activities.Add(new Activity() { Name = "Activity 5", Complete = false, DueDate = startDate.AddDays(14), Project = "Project 1" });
var result = from act in Activities group act by act.Project into grp orderby grp.Key select grp;
// Dla zoom incvsActivities.Source = result;
// Dla zoomoutthis.groupGridView.ItemsSource = this.cvsActivities.View.CollectionGroups;
DemoSemantic Zoom
Kontrakty, integracja z systemem
Proces share’owaniaAplikacja docelowaShare Broker
Użytkownik wybiera “Share”, zdarzenie w app
Aktywowana do share’owania
Rejestracja w DataTransfer Manager
Aplikacja źródłowa
Filtrowanie listy target i quick links
Użytkownik wybiera aplikację lub quick link
Przetwarzanie zawartości DataPackage
Zgłasza koniec
Kończy Async call i kończy pracę
Otrzymuje event i wypełnia DataPackage
DataPackage żyje w aplikacji źródłowej
Aktywacja docelowej aplikacji (kind: shareTarget)
Share
Share target Konieczne deklaracje w manifeście typu obsługiwanych danych
Share source – zdarzenie DataTransferManager OnDataRequested (args.Data – paczka z wymienianymi danymi) Właściwości (description, title, itp.) – Title wymagany DataTransferManager.ShowShareUI(); - programowe wywołane
Lista aplikacji docelowych filtrowana na podstawie tego co umieścimy w paczce (np. SetText, SetHTML, ...)
Możliwe umieszczenie danych w kilku „szufladach” jednocześnie (np. tekst i HTML)
np. Poczta szuka w kolejności Html -> Link -> Tekst
Share source - przykład
DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;
void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args) { var request = args.Request; var item = (ModelItem)this.flipView.SelectedItem; request.Data.Properties.Title = item.Title; request.Data.Properties.Description = „Something to share";
// Share text var textToShare = „Text to share";
request.Data.SetText(textToShare); request.Data.SetHtmlFormat(textToShare);
}
Data Package
Zwykły tekst (SetText) Sformatowany tekst (SetRtf) URI (SetUri) HTML (SetHtmlFormat) Pliki (SetStorageItems) Zdjęcia (SetBitmap)
Zalecane dodatkowo SetStorageItems Własne formaty danych (SetData)
Własne formaty
Zalecane sprawdzenie czy typ nie jest już publicznie udokumentowany http://schema.org/ (np. http://schema.org/Book) Obsługa wyjątków podczas wczytywania
Obsługiwane typy Skalary (integer, string, DateTime, itp.) poprzez IPropertyValue. IRandomAccessStream, IRandomAccessStreamReference - np. własna klasa i
DataContractSerializer IUri IStorageItem Kolekcje powyższych
Data Provider
Zalecane, kiedy długotrwałe przetwarzanie danych Np. pomniejszenie zdjęcia przed udostepnieniem
Deferral providerRequest.GetDeferral();
Standardowe typy (StandardDataFormats) lub własne
requestData.SetDataProvider(StandardDataFormats.Bitmap, providerRequest => this.OnDeferredImageRequestedHandler(providerRequest, this.selectedImage));
DemoShare source
Share target Konieczna deklaracja w manifeście
Formaty danych Formaty plików
OnShareTargetActivated(ShareTargetActivatedEventArgs args) args.ShareOperation Zalecane pobranie ShareOperation i przetwarzanie asynchroniczne
ShareOperation Data – obiekt DataPackageView (praktycznie r/o DataPackage) QuickLinkId
await Task.Factory.StartNew(async () =>
{
// Przetwarzamy Data Package
}
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
// Wracamy do wątku UI
}
Długie przetwarzanie shareOperation.ReportStarted();
Od tego momentu brak interakcji z aplikacją share’ującą Użytkownik może zamknąć okno share i wrócić do aplikacji
shareOperation.ReportDataRetreived(); (opcja) Po pobraniu danych z DataPackage Zgłasza mozliwość uśpienia / zamknięcia aplikacji źródłowej - optymalizacja Może być wywołany przed ReportStarted() – np. Task po aktywacji Share, ale przed kliknięciem „wyślij” w celu
przyspieszenia procesu shareOperation.ReportSubmittedBackgroundTask(); (opcja)
Sugerowane zgłoszenie, kiedy korzystamy z BackgroundTransfer – optymalizacja shareOperation.ReportCompleted([quicklink]);
Zgłoszenie zakończenia Zapisanie quicklinka i (samodzielnie) identyfikatora np. w bazie
shareOperation.ReportError(txt); Przerwanie operacji, toast + komunikat o błędzie
QuickLink quickLinkInfo = new QuickLink{
Id = QuickLinkId.Text,Title = QuickLinkTitle.Text,
SupportedFileTypes = { "*" },SupportedDataFormats =
{StandardDataFormats.Text,StandardDataFormats.Uri,StandardDataFormats.Bitmap,StandardDataFormats.StorageItems,StandardDataFormats.Html,dataFormatName
}};
Quick Link
Formaty i typy plików niezależne od manifestu Czyszczone / wyłączane z panelu sterowania (share -> clear list)
DemoShare target
Search
Wpis w deklaracjach manifestu OnSearchActivated
Kiedy search wywołany gdy aplikacja była zamknięta, OnLaunched NIE WYWOŁYWANY
Konieczne ręczne zainicjalizowanie aplikacji (jak w OnLaunched) ShowOnKeyboardInput – automatyczne otwieranie charms bar
Podpowiedzi
Wcześniej aktywowanie aplikacji (wybranie jej z listy charms) SearchPane.GetForCurrentView().SuggestionsRequested
args.QueryText args.Request.SearchSuggestionCollection.AppendQuerySuggestion(...);
SetLocalContentSuggestionSettings - pliki Separatory – AppendSearchSeparator Rezultaty (ze zdjęciem i opisem) - AppendResultSuggestion
Łącznie 5 elementów (sugestie, rezultaty, separatory)
DemoSearch contract
Ustawienia
Domyślnie tylko Permissions – na podstawie capabilities SettingsPane.GetForCurrentView().CommandsRequested
Komendy obsługiwane przez daną stronę Flyout – najprościej z Callisto
Najlepiej w App.xaml.cs W przeciwnym wypadku trzymanie referencji do strony (GC)
Flyout Zwykła kontrolka Popup odpowiednio wypozycjonowana Transitions 346 lub 646 pikseli
Ustawienia - kodSettingsPane.GetForCurrentView().CommandsRequested += onCommandsRequested;
void onCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs eventArgs){
UICommandInvokedHandler handler = new UICommandInvokedHandler(onSettingsCommand);
SettingsCommand generalCommand = new SettingsCommand("generalSettings", "General", handler);eventArgs.Request.ApplicationCommands.Add(generalCommand);
}
// To samo z flyout (callisto) void OnCommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args) { // Add an About command var about = new SettingsCommand("about", "About", (handler) => { var settings = new SettingsFlyout(); settings.Content = new AboutUserControl(); settings.HeaderBrush = new SolidColorBrush(_background); settings.Background = new SolidColorBrush(_background); settings.HeaderText = "About"; settings.IsOpen = true; });
args.Request.ApplicationCommands.Add(about); }
DemoUstawienia
Zapisywanie danych
Katalog instalacyjny App data
Ustawienia lokalne – ApplicationData.Current.LocalSettings Kontenery - proste grupowanie ustawień Composite ms-appdata://local //roaming //temp
Pliki, sesja – ApplicationData.Current.LocalFolder User data
Dokumenty, zdjęcia, muzyka, filmy Roaming
Roaming Settings ApplicationData.Current.RoamingSettings Dostępne nawet, kiedy brak sieci / nie połączone konto LiveID Max 100 KB
ApplicationData.Current.RoamingStorageQuota;
Synchronizacja, kiedy system zadecyduje Typ połączenia z siecią, obciążenie, itp. Brak możliwości wymuszenia synchronizacji
Composite settings dla „atomowych” zmian (konflikty) ApplicationDataCompositeValue
Ustawienie HighPriority dla bardzo istotnych Może być composite
ApplicationData.Current.SetVersion – aby uniknąć problemów z wersjonowaniem DataChangedHandler
DemoUstawienia
Devices
Drukowanie NFC DLNA
Tylko Windows Certified (podzbiór „Play To”) Obecnie m.in. najnowsze Samsung Smart TV, amplitunery Onkyo, Sony, PlayTo
API, Windows Media Player, ...
DemoDrukowanie
Play To
Strumieniowanie z naszej aplikacji MediaElement – muzyka, film Image (może zdalny PowerPoint?)
Dostęp do danych z Media Serwerów Aplikacja jako odbiorca Play To
Teoretycznie do wykorzystania dla dowolnego strumienia
Implementacja Play To
<MediaElement x:Name="videoplayer" Source = "http://www.contoso.com/clip.mp4" AutoPlay="true" />
// Krok 1: PlayToManager dla widoku.
PlayToManager ptm = Windows.Media.PlayTo.PlayToManager.GetForCurrentView();
// Krok 2: Zdarzenie SourceRequested (użytkownik wskazał urządzenie).
ptm.SourceRequested += (PlayToManager sender, PlayToSourceRequestedEventArgs e) => {
request = e.SourceRequest;
// Krok 3: określenie mediów do strumieniowania
PlayToSourceDeferral deferral = request.GetDeferral();
request.SetSource(videoplayer.PlayToSource);
deferral.Complete();
}
// Media strumieniowane do urządzenia
DemoPlay to
Shareowanie z osobami w pobliżu
// Rejestrujemy w klasyczny sposób kontrakt do share’owaniafunction setupShare() { var dtm = Windows.appModel.DataTransfer.DataTransferManager.getForCurrentView(); dtm.addEventListener("datarequested", function (e) { onDataRequested(e); });}
// Obsługujemy tak jak lokalne żądanie do share’owania function onDataRequested(e) {
var dp = new Windows.appModel.DataTransfer.DataPackage(); dp.properties.title = "Our Test Text"; // required dp.properties.description = "Test Description"; // required dp.setUri(new Windows.Foundation.Uri("http://www.oddfellows.com")); e.request.data = dp;}
App To App pickers
App To App pickers
DemoContacts picker
Własne protokoły
mojprotokol://jakies/parametry Z przeglądarki (zarówno Metro jak i Desktop) Przekazywane parametry do OnActivated Działa także jako link w aplikacji Jeśli kilka aplikacji zarejestrowanych – wybór za pierwszym razem
DemoWłasny protokół
Touch
Proste gesty Tap
Nie to samo co mouse_down W przypadku myszki – dowolny czas, bez ruchu W przypadku ekranu dotykowego – max. pół sekundy
DoubleTap, Holding, ...
Pointer events PointerPressed, PointerReleased, PointerMoved Dla palca, myszki, rysika, ... Unikalne identyfikatory
DemoTouch
Praca w tle
Background Audio Kilka niezależnych typów (komunikator, media, gra,itp.) Jeden typ strumienia na raz
Background Transfer Upload / download danych w tle
Execution = Trigger + [Condition]
Trigger Condition
InternetAvailable, InternetNotAvailable, SessionConnected, SessionDisconnected, UserNotPresent, UserPresent
SystemEventTriggerControlChannelReset #InternetAvailableLockScreenApplicationAdded/RemovedNetworkStateChange OnlineIdConnectedStateChangeServicingCompleteSessionConnected/Disconnected #SmsReceivedTimeZoneChangeUserAway/UserPresent #
ControlChannelTrigger # (**)TimeTrigger #PushNotificationTrigger # (**)MaintenanceTrigger # wymaga lock permission
**może być in-proc (nie BackgroundTaskHost.exe)
„Condition latching”Maintenance trigger – na zasilaniu
Rejestracja - manifest
<Extensions> <Extension Category="windows.backgroundTasks" EntryPoint="Tasks.SampleBackgroundTask"> <BackgroundTasks> <Task Type="systemEvent" /> <Task Type="timer" /> </BackgroundTasks> </Extension> <Extension Category="windows.backgroundTasks" EntryPoint="Tasks.ServicingComplete"> <BackgroundTasks> <Task Type="systemEvent" /> </BackgroundTasks> </Extension></Extensions>
Rejestracja – c.d.
string BackgroundTaskName = "SampleBackgroundTask";string BackgroundTaskEntryPoint = "BackgroundTask.SampleBackgroundTask";
void RegisterBackgroundTask(){ var taskBuilder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder(); var systemTrigger = new SystemTrigger(SystemTriggerType.InternetAvailable , false); var userPresentCondition = new SystemCondition(SystemConditionType.UserPresent);
taskBuilder.SetTrigger(systemTrigger); taskBuilder.AddCondition(userPresentCondition); taskBuilder.Name = BackgroundTaskName; taskBuilder.TaskEntryPoint = BackgroundTaskEntryPoint;
var task = taskBuilder.Register(); task.Progress += task_Progress; task.Completed += task_Completed; }
Aplikacje Lock Screen
Aplikacje, które mogą działać w tleZwłaszcza aplikacje komunikacyjne (poczta, komunikator, VoIP)
Okresowe uruchamianieUruchamianie kodu w odpowiedzi na zdarzenia systemowe
Zarządzane przez użytkownika (max 7)
Przydzielanie zasobów
CPU quota Odświeżanie
Z lock screen 2 sekundy CPU 15 minut
Bez lock screen 1 sekunda CPU 2 godziny
Tylko kiedy naprawdę „background” (przy uruchomionej aplikacji brak ograniczeń) Dotyczy tylko faktycznej pracy CPU!!!
Ograniczenia dla połączeń
Tylko kiedy praca na baterii
Okres odświeżania 15 min 2 godziny dziennie
Limit na dane (lock) 0.469 MB n/a 45 MB
Limit na dane (nie lock) n/a 0.625 MB 7.5 MB
Krytyczne zadania
Np. VOIP Triggery: Control Channel, notyfikacje Push PUSH
Brak SLA Backend musi być przystosowany
Control Channel Triggery: Control Channel lub Keep-alive (co 15 minut podtrzymanie połączenia) Przetwarzanie komunikatów, kiedy aplikacja zawieszona Software i hardware slot (dla ARM) Nieco więcej pracy Podtrzymywane połączenie
Gwarantowane zasoby dla poszczególnych zadań (takie same jak dla aplikacji)
Globalna pula Dodatkowe zasoby współdzielone między aplikacjami
Co 15 minut uzupełniana Wielkość zasobów zależy od wielu czynników
Nie należy na niej polegać
Lepiej wyłączyć podczas testów HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\BackgroundModel\Policy\CpuEnableGlobalPool HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\BackgroundModel\Policy\NetEnableGlobalPool
Może mimo wszystko nie wystarczyć… Event log BackgroundTaskInstnce.SuspendedCount
DemoPraca w tle
Live Tiles – wrażenie aktywności
Dostarczają informacji, kiedy aplikacja jest wyłączona
Wrażenie, że aplikacja działa w tle i zaproszenie do powrotu
Dwa mechanizmy do aktualizacjiLokalne APINotyfikacje PUSH
Tiles
2 rozmiary 150x150 px 310x150 px (opcja)
Wide – konieczne ustawienie w manifeście
var tile = new SecondaryTile( item.UniqueId, // Tile ID item.ShortTitle, // Tile short name item.Title, // Tile display name item.UniqueId, // Activation argument TileOptions.ShowNameOnLogo, // Tile options uri // Tile logo URI );
await tile.RequestCreateAsync();
Live Tiles
Wiele możliwości prezentacyjnych
Aktualizowane przy pomocy predefiniowanych szablonów
Tekstowe, graficzne lub mix
JPEG lub PNG, max rozmiar 150KB
Opcjonalna animacja “peek”
Lokalna lub zdalna aktualizacja
Kolejkowanie notyfikacji
Opcjonalnie rotowanie między 5 ostatnimi notyfikacjami
Domyślnie tylko ostatnia wyświetlana
Secondary Tiles
„Pinowanie” zawartości z wewnątrz aplikacji Proste wywołanie API Użytkownik potwierdza (systemowe UI) Personalizowana przestrzeń aplikacji Takie same możliwości jak główne kafelki
Tylko lokalne obrazy Uruchomienie przekierowuje do określonej sekcji aplikacji
DemoLive tiles / secondary tiles
Notyfikacje Toast
Podobna struktura do kafelków (oparta o szablony) Różne możliwości wizualne
DemoNotyfikacje Toast
Notyfikacje PUSH - WNS
Zdalne zmiany kafelków i notyfikacje Toast (Internet) Także, kiedy aplikacja jest wyłączona
Skalowalne, bezpłatne
PUSH – schemat działaniaWindows 8 Usługa w
chmurze
Windows Notification
Service
Aplikacja Metro Style
NotificationClient
Platform
2
3
1 3
1. Żądamy URI kanału PUSH
2. Rejestracja w naszej usłudze
3. Uwierzytelnienie i wysłanie notyfikacji
Notyfikacje – c.d.
Komunikaty: Tile, Badge, Toast, Raw Raw wymaga locked screen!
Wygasają po 30 dniach Wznowienie podczas uruchamiania aplikacji Maintenance trigger
Azure Toolkit for Windows 8
Azure Mobile Services
Bardzo prosty back-end w Azure Storage PUSH Uwierzytelnienie Live Connect
Bezpłatnie (obecnie preview) Do 10 instancji 165 MB Reserved – kiedy jest potrzeba
Dodatkowe opłaty 100 usług Transfer pay-as-you-go
DemoAzure Mobile Services
Windows Store
Podział zysków 70:30 lub 80:20 Reklamy – dowolnie Trial In-app purchase Rejestracja
49 lub 99 USD / rok Dreamspark, MSDN, Bizspark – bezpłatnie 1 rok!
Od strony dewelopera Pełne dane na temat licencji Recipes (przypomnienie) Symulator
Konwersja z Trialprivate async void ConvertTrial(){ var licenseInformation = CurrentApp.LicenseInformation;
licenseInformation.LicenseChanged += licenseInformation_LicenseChanged;if (licenseInformation.IsTrial)
await CurrentApp.RequestAppPurchaseAsync(); }
void licenseInformation_LicenseChanged(){
if (CurrentApp.LicenseInformation.IsActive) { //Enable features..
} }
In-app purchasevar licenseInformation = CurrentApp.LicenseInformation;var productLicense = licenseInformation.ProductLicenses["product1"];if (!productLicense.IsActive && licenseInformation.IsActive ) {
try { await CurrentAppSimulator.RequestProductPurchaseAsync("product1“, false);
// No exception: enable product1 }catch (Exception){
//product 1 was not purchased }
}
Symulator
CurrentAppSimulator.ReloadSimulatorAsync(file);
DemoIntegracja ze sklepem
DPI
System automatycznie przeskalowuje w zależności od DPI Elementy wektorowe – bez problemu Grafika – może być gorsza jakość
Grafika i DPI
Modern Resource Technology (MRT) Automatycznie, na podstawie nazw Uwaga – nie zmieni się w runtime <img src=„projector.jpg” width=80px height=80px /> Konwencja nazewnicza
...\projector.scale-100.jpg ...\projector.scale-140.jpg ...\projector.scale-180.jpg
Manualnie (zdarzenie)
Grid i typografia
Jedno z UX Guidelines Zaprojektowany, aby skalował się bez zaokrągleń
DemoHigh DPI
Zasoby i lokalizacja
Automatyczne rozpoznawanie języka (ustawienia) systemowe Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride
Katalogi i pliki *.resw Domyślny – Resources.resw x:Uid
Wybór zdjęć na podstawie kontrastu, skali, języka Pierwszeństwo zasobów nad zapisaną wartością w XAML Ręcznie
var resourceLoader = new ResourceLoader([ew. plik resw]);this.tb.Text = resourceLoader.GetString("string1");
Manifest - ms-resource:appDescription
Zadania MAT• Pomaga weryfikować zasoby, wykryć nowe
nieprzetłumaczone.• UI do wyboru języka.• Wykorzystuje standard XLIFF file format.
• OASIS XML Localisation Interchange File Format (XLIFF) TC• https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff
• Dostarcza motor pseudo-języka, co pomaga zidentyfikować problemy podczas developmentu
• Pozwala wykorzystać Microsoft Translator (sugestie, może tłumaczenie).
• Nie pomaga w „uresourceowieniu” aplikacji – to robota programisty!
• Wsparcie korekty
Skórki
<ResourceDictionary.ThemeDictionaries> <ResourceDictionary x:Key="Default"> <x:String x:Key="BackButtonGlyph"></x:String> <x:String x:Key="BackButtonSnappedGlyph"></x:String> </ResourceDictionary>
<ResourceDictionary x:Key="HighContrast"> <x:String x:Key="BackButtonGlyph"></x:String> <x:String x:Key="BackButtonSnappedGlyph"></x:String> </ResourceDictionary> </ResourceDictionary.ThemeDictionaries>
DemoZasoby
Animacje
Animacje Nowe elementy StoryBoardów Np. Popin/PopoutAnimation
Content Transitions Popup Page Content Control (kontenery typu Grid, StackPanel, itp.)
DemoAnimacje
MVVM – po co?
Separacja warstw Testowanie Wsparcie Blend
Model-View-ViewModel
Widok Jak wyświetlić informację?
View Model Którą informację wyświetlić? Interakcja, przepływ
Model Obiekty reprezentujące dane Logika biznesowa
Model
View Model
View Platform-specific
PortableReferences
Databinds
DemoMVVM Light Toolkit
Problem z class libraries i przenośnością...
Portable Class Libraries
Jedno źródło Jeden projekt Jeden plik binarny Wiele platform!
Dostępne mechanizmy
Aplikacja cross-platform
Startup
Views
Windows Store App
Platform specific functionality
View Models
Models
Portable Class Library
Platform functionality abstractions
Startup
Views
Windows Phone App
Platform specific functionality
Reference Reference
DemoPortable Class Libraries i MVVM
Nieco bardziej komplikujemy...
Nawigacja IoC
Ninject Autofac
async ...
DemoNieco bardziej skomplikowany przykład...
Potrzebujemy jeszcze Android, iOS?
HTML 5 – Apache Cordova aka PhoneGap Xamarin Framework
Cross-plaformowy C# Generics, Linq, Async, ...
Bazuje na Mono Komercyjny (400 USD / platforma)
Trial w pełni sprawny (emulator) iOS (potrzebny MAC), MonoDevelop Android – także Visual Studio!
MvvmCross
Bazuje (już) na Portable Class Libraries Cross-platformowość
iOS Android Windows Phone Windows 8
Bazuje na konwencjach (podobnie jak Caliburn.micro)
Wybrane zagadnienia (luźne)
Debugowanie komponentów WinRT
Nie można debugować jednocześnie kodu JS i managed (np. komponent)
WinMD i managed code
Ildasm /project – włączenie adaptera Bez tego – widzimy jak zapisane na dysku Z parametrem project – widzimy tak jak widzi CLR
Typy WinRT
Kategoria PrzykładStandard WinRT types Windows.Foundation.Collections.PropertySet,
Windows.Networking.Sockets.DatagramSocketPrimitive types Byte, Int32, String, ObjectProjected types Windows.Foundation.Uri,
Windows.Foundation.DateTimeProjected interfaces Windows.Foundation.Collections.IVector<T>,
Windows.Foundation.IclosableTypes with .NET helpers Windows.Storage.Streams.IInputStream,
Windows.Foundation.IasyncInfo
Recommended