❗ There is also a version of this document with code samples in C# ❗ |
---|
By default the settings page contains a single boolean setting to track whether the app should be displayed with the Light or Dark theme.
Let's add a boolean setting to control whether errors should be automatically reported. Adding a setting requires you to:
- Update the View so it's possible to see and change the setting
- Update the ViewModel to add logic related to changing the setting.
Add the following below the StackPanel
containing the RadioButton
s in SettingsView.xaml
<CheckBox IsChecked="{x:Bind ViewModel.IsAutoErrorReportingEnabled, Mode=TwoWay}"
x:Uid="Settings_EnableAutoErrorReporting"
Margin="0,8,0,0" />
Add an entry to Strings/en-us/Resources.resw
Name: Settings_EnableAutoErrorReporting.Content
Value: Automatically report errors
When run it will now look like this:
But if you try and run it now you will get build errors as the ViewModel hasn't been updated to add the new property.
The IsLightThemeEnabled
property uses a static ThemeSelectorService
. It is not necessary to create equivalent services for every setting but is appropriate for the theme preference as this is needed when the app launches.
Because we may want to access settings in various parts of the app it's important that the same settings values are used in all locations. The simplest way to do this is to have a single instance of the SettingsViewModel
and use it for all access to settings values.
The generated code in includes a Singleton helper class to provide access to a single instance of the view model which we can use everywhere.
With this knowledge we can now add the new property for accessing our stored setting. We also need to add a new, awaitable initializer for the property too. Add the following to SettingsViewModel.vb
Imports {YourAppName}.Helpers
Imports System.Threading.Tasks
Private _isAutomaticErrorReportingEnabled As Boolean?
Public Property IsAutoErrorReportingEnabled As Boolean?
Get
Return If(_isAutomaticErrorReportingEnabled, False)
End Get
Set(ByVal value As Boolean?)
If value <> _isAutomaticErrorReportingEnabled Then
Task.Run(Async Function() Await Windows.Storage.ApplicationData.Current.LocalSettings.SaveAsync(NameOf(IsAutoErrorReportingEnabled), If(value, False)))
End If
[Set](_isAutomaticErrorReportingEnabled, value)
End Set
End Property
Private _hasInstanceBeenInitialized As Boolean = False
Public Async Function EnsureInstanceInitializedAsync() As Task
If Not _hasInstanceBeenInitialized Then
IsAutoErrorReportingEnabled = Await Windows.Storage.ApplicationData.Current.LocalSettings.ReadAsync(Of Boolean)(NameOf(IsAutoErrorReportingEnabled))
Initialize()
_hasInstanceBeenInitialized = True
End If
End Function
Then change the SwitchThemeCommand
to match this:
Public Property SwitchThemeCommand As ICommand
Get
If _switchThemeCommand Is Nothing Then
_switchThemeCommand = New RelayCommand(Of ElementTheme)(Async Sub(param)
If _hasInstanceBeenInitialized Then
Await ThemeSelectorService.SetThemeAsync(param)
End If
End Sub)
End If
Return _switchThemeCommand
End Get
End Property
We must now update our uses of the ViewModel.
In SettingsPage.xaml.vb change the property declaration from this:
Public Property ViewModel As SettingsViewModel = New SettingsViewModel()
to this:
Public Property ViewModel As SettingsViewModel = Singleton(Of SettingsViewModel).Instance
so it uses the single instance.
You may also need to add the following using statement to the top of the file.
Imports {YourAppName}.Helpers
Then change the OnNavigatedTo()
method so that instead of calling the old Initialize method, like this:
Protected Overrides Sub OnNavigatedTo(ByVal e As NavigationEventArgs)
ViewModel.Initialize()
End Sub
It now awaits the call to the new Initializer like this:
Protected Overrides Async Sub OnNavigatedTo(ByVal e As NavigationEventArgs)
Await ViewModel.EnsureInstanceInitializedAsync()
End Sub
In SettingsPage.xaml.vb change the constructor so that it handles the OnLoaded
event and add the following event handler, like this:
Public Sub SettingsPage()
InitializeComponent()
ViewModel.Initialize()
AddHandler Loaded, AddressOf SettingsPage_Loaded
End Sub
Private Async Sub SettingsPage_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
RemoveHandler Me.Loaded, AddressOf SettingsPage_Loaded
Await ViewModel.EnsureInstanceInitializedAsync()
End Sub
Everything is now complete and you can run the app and it will remember the value between invocations of the app.
If you want to access the property elsewhere in the app, ensure you have called await Singleton(Of SettingsViewModel).Instance.EnsureInstanceInitializedAsync();
. Then you can get or set the property with Singleton(Of SettingsViewModel).Instance.IsAutoErrorReportingEnabled
.
For example:
Try
...
Catch exc as Exception
Await Singleton(Of SettingsViewModel).Instance.EnsureInstanceInitializedAsync()
If Singleton(Of SettingsViewModel).Instance.IsAutoErrorReportingEnabled Then
' Send the error details to the server
End If
End Try
If you only use the value in one or two places you could call EnsureInstanceInitializedAsync()
each time before you access Singleton(Of SettingsViewModel).Instance
. But, as EnsureInstanceInitializedAsync()
only needs to be called once before it is used, if you have lots of settings or need to access them in many places you could call it once as part of the InitializeAsync()
method in ActivationService.vb.