❗ There is also a version of this document with code in VB.Net ❗ |
---|
The ActivationService is in charge of handling the application's initialization and activation.
The method ActivateAsync()
it the common entry point for the application lifecycle events OnLaunched
, OnActivated
and OnBackgroundActivated
.
For more information on the application lifecycle and its events see Windows 10 universal Windows platform (UWP) app lifecycle.
The ActivationService
relies on the ActivationHandlers, that are registered in the method GetActivationHandlers()
.
Each class in the application that can handle activation derives from the abstract class ActivationHandler<T>
(T is the type of ActivationEventArguments the class can handle) and implement the method HandleInternalAsync().
The method HandleInternalAsync()
is where the actual activation takes place.
The virtual method CanHandleInternal()
checks if the incoming activation arguments are of the type the ActivationHandler can manage. It can be overwritten to establish further conditions based on the ActivationEventArguments.
We'll have look at the SchemeActivationHandler, added by the DeepLink feature, to see how activation works in detail:
protected override bool CanHandleInternal(ProtocolActivatedEventArgs args)
{
// If your app has multiple handlers of ProtocolActivationEventArgs
// use this method to determine which to use. (possibly checking args.Uri.Scheme)
return true;
}
// By default, this handler expects URIs of the format 'wtsapp:sample?paramName1=paramValue1¶mName2=paramValue2'
protected override async Task HandleInternalAsync(ProtocolActivatedEventArgs args)
{
// Create data from activation Uri in ProtocolActivatedEventArgs
var data = new SchemeActivationData(args.Uri);
if (data.IsValid)
{
NavigationService.Navigate(data.PageType, data.Parameters);
}
await Task.CompletedTask;
}
The CanHandleInternal()
method was overwritten here and it returns true by default. You can use args
to add extra validation for scenarios with multiple ProtocolActivationEventArgs
.
The HandleInternalAsync()
method gets the ActivationData
from argument's Uri and uses the PageType
and Parameters
to navigate.
The following flowchart shows the activation process that starts with one of the app lifecycle event and ends with the StartupAsync
call.
Activation starts from one of the app lifecycle events: OnLaunched
, OnActivated
or OnBackgroundActivated
. All call a common entry point for activation in ActivationService.ActivateAsync()
.
The first calls in ActivateAsync
are InitializeAsync()
and ShellCreation (in the cases where activation is interactive). If you added an Identity feature to your app, code for Identity configuration and SilentLogin will be included here too.
After this first block, HandleActivationAsync
is called (more details below).
IsInteractive
Interacting with the app window and navigating is only available when the activation arguments extend from IActivatedEventArgs
. An example for non-interactive activation is activation from a background Task.
InitializeAsync
InitializeAsync
contains services initialization for services that are going to be used as ActivationHandler
. This method is called before the window is activated. Only code that needs to be executed before app activation should be placed here, as the splash screen is shown while this code is executed.
StartupAsync
StartupAsync
contains initializations of other classes that do not need to happen before app activation and starts processes that will be run after the Window is activated.
The HandleActivation
method gets the first ActivationHandler
that can handle the arguments of the current activation. It also creates a DefaultActivationHandler
and executes it if no other ActivationHandler
is selected or the selected ActivationHandler
does not result in Navigation.
We are going to create a new ActivationHandler
to show how to extend the ActivationService
in your project. In this case, we are going to add a reader for markdown (.md) files.
The following sample code is to be added in a TS generated app using the MVVM Toolkit.
For viewing the markdown a MarkdownTextBlock
from the Windows Community Toolkit is used.
Add the following files to your project
Views/MarkdownPage.xaml
<Page
x:Class="YourAppName.Views.MarkdownPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d">
<Grid
x:Name="ContentArea">
<Grid.RowDefinitions>
<RowDefinition x:Name="TitleRow" Height="48"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock
x:Name="TitlePage"
x:Uid="Markdown_Title"
FontSize="28" FontWeight="SemiLight"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" VerticalAlignment="Center"
Margin="24,0,24,7"/>
<Grid Grid.Row="1" >
<ScrollViewer
Margin="12"
BorderBrush="{ThemeResource AppBarBorderThemeBrush}"
BorderThickness="2"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<controls:MarkdownTextBlock
x:Name="UiMarkdownText"
Padding="24,12,24,12"
Foreground="Black"
Background="White"
LinkClicked="UiMarkdownText_LinkClicked"
Text="{x:Bind ViewModel.Text, Mode=TwoWay}" />
</ScrollViewer>
</Grid>
</Grid>
</Page>
Views/MarkdownPage.xaml.cs
using System;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.Storage;
using Windows.System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using YourAppName.ViewModels;
namespace YourAppName.Views
{
public sealed partial class MarkdownPage : Page
{
public MarkdownViewModel ViewModel { get; } = new MarkdownViewModel();
public MarkdownPage()
{
InitializeComponent();
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
if (!string.IsNullOrEmpty(e.Parameter?.ToString()))
{
var text = await FileIO.ReadTextAsync(e.Parameter as StorageFile);
ViewModel.Text = text;
}
}
private async void UiMarkdownText_LinkClicked(object sender, LinkClickedEventArgs e)
{
await Launcher.LaunchUriAsync(new Uri(e.Link));
}
}
}
ViewModels/MarkdownViewModel.cs
using System;
using YourAppName.Helpers;
namespace YourAppName.ViewModels
{
public class MarkdownViewModel : ObservableObject
{
private string _text;
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value); }
}
public MarkdownViewModel()
{
}
}
}
Strings/en-us/Resources.resw
You also should add a string resource for Markdown Title.
<data name="Markdown_Title.Text" xml:space="preserve">
<value>Markdown</value>
</data>
Add a file type association declaration in the application manifest, to allow the App to be shown as a default handler for markdown files.
Handle the file activation event by implementing the override of OnFileActivated:
App.xaml.cs
protected override async void OnFileActivated(FileActivatedEventArgs args)
{
await ActivationService.ActivateAsync(args);
}
Add a FileAssociationService
to your project that handles activation from files. It derives from ApplicationHandler<T>
.
As it manages activation by FileActivatedEventArgs
the signature is:
FileAssociationService
internal class FileAssociationService : ActivationHandler<FileActivatedEventArgs>
{
}
Override HandleInternalAsync()
, to evaluate the event args, and take action:
protected override async Task HandleInternalAsync(FileActivatedEventArgs args)
{
var file = args.Files.FirstOrDefault();
NavigationService.Navigate(typeof(MarkdownPage), file);
await Task.CompletedTask;
}
Finally, we'll add our new FileAssociationService
to the ActivationHandlers
registered in the ActivationService
:
ActivationService
private IEnumerable<ActivationHandler> GetActivationHandlers()
{
// Add this new FileAssociationService
yield return Singleton<FileAssociationService>.Instance;
}