Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Getting Started with Xamarin.Forms and Platform Specific Resources using OnPlatform

Previous posts in this sequence on Getting Started with Xamarin.Forms:
Multi-Targeting in Visual Studio, SDK Versions, MvvmCross, Authenticating with ADAL
Refactoring MvvmCross and Services, Effects, Navigation with MvvmCross
Presentation Attributes in MvvmCross, Resources and Styles, Resource Dictionaries

In previous posts we’ve looked at using resources and then styles and resource dictionaries in order to manage the style of elements throughout our application. Whilst Xamarin.Forms provides an out-of-the-box cross platform experience, the reality is that if you don’t tweak the layout a bit for each platform, your application is going to look very generic, and not in a good way. In this post we’ll look at some of the different ways that you can adjust layout based on which target platform the application is running on.

The starting point is to look at an individual element, such as a Label, and how an individual property can be adjusted for different platforms using an OnPlatform element.

<Label Text="Hello World!">
     <Label.FontAttributes>
         <OnPlatform x:TypeArguments="FontAttributes">
             <On Platform="Android" Value="Italics"/>
             <On Platform="iOS" Value="None"/>
             <On Platform="UWP" Value="Bold"/>
         </OnPlatform>

     </Label.FontAttributes>
</Label>

In this example instead of supplying a value for the FontAttributes attribute we’ve expanded into long form using a Label.FontAttributes element. Nested within this element we create an OnPlatform element, supplying the TypeArguments attribute to indicate what Type of value the OnPlatform is going to produce. Within the OnPlatform element we then have an On element for each platform we want to specify a value for.

Since we’re not a big fan of having literals specified for an individual element, and even more so when doing per-platform styling, we can also define resources using the OnPlatform syntax:

<OnPlatform x:Key ="FeatureColor" x:TypeArguments="Color">
     <On Platform="Android" Value="Red"/>
     <On Platform="iOS" Value="Green"/>
     <On Platform="UWP"  Value="Blue"/>
</OnPlatform>

This defines a resource, FeatureColor, within a ResourceDictionary, with different colors defined for each of the three platforms.

As you can see, defining values for each platform can start to add a lot of bloat to your XAML. A work around for this is to use a similar technique that we’ve discussed previously where we include files on a per platform basis. For resources this requires a bit of fiddling, so there are a few steps involved. We need to start with the csproj for the UI project and adjust the first ItemsGroup to remove all XAML files that are within the Platforms folder. Next we need to selectively add back the XAML files based on what the target platform is. The bold lines in the following XAML from the csproj file indicate these changes.

<ItemGroup>
   <Compile Remove="Platforms\**\*.cs" />
   <None Include="Platforms\**\*.cs" />
   <EmbeddedResource Remove="Platforms\**\*.xaml" />
   <None Include="Platforms\**\*.xaml" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
   <Compile Include="Platforms\Netstandard\**\*.cs" />
   <EmbeddedResource Include="Platforms\Netstandard\**\*.xaml" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('uap')) ">
   <Compile Include="Platforms\Uap\**\*.cs" />
   <EmbeddedResource Include="Platforms\Uap\**\*.xaml" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
   <Compile Include="Platforms\Ios\**\*.cs" />
   <EmbeddedResource Include="Platforms\Ios\**\*.xaml" />
</ItemGroup>

<ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
   <Compile Include="Platforms\Android\**\*.cs" />
   <EmbeddedResource Include="Platforms\Android\**\*.xaml" />
</ItemGroup>

Next we need to create platform specific XAML files. I simply copied the LiteralResources.xaml and LiteralResources.xaml.cs into each of the Platform folders and renamed both the files and the class name to PlatformLiteralResources. In my case the project structure looks like the following:

image

You’ll notice that the PlatformLiteralResources.xaml is only showing under the Netstandard – this appears to be a bit of a bug in Visual Studio as the file exists and should appear in the project structure for all the platforms. The only thing left to do is define some platform resources and to link the PlatformLiteralResources class into the resource dictionary hierarchy:

PlatformLiteralResources

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="
http://xamarin.com/schemas/2014/forms"
                     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                     xmlns:res="clr-namespace:StrataPark.UI.Resources"
                      x:Class="StrataPark.UI.Resources.PlatformLiteralResources">
     <ResourceDictionary.MergedDictionaries>
         <res:LiteralResources />
     </ResourceDictionary.MergedDictionaries>
    <x:Double x:Key="DefaultLabelFontSize">24</x:Double>
</ResourceDictionary>

StyleAndTemplateResources

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="
http://xamarin.com/schemas/2014/forms"
                     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                     xmlns:res="clr-namespace:StrataPark.UI.Resources"
                     x:Class="StrataPark.UI.Resources.StyleAndTemplateResources">
     <ResourceDictionary.MergedDictionaries>
         <res:PlatformLiteralResources />
     </ResourceDictionary.MergedDictionaries>

    <!-- Other resources -->
</ResourceDictionary>

Note that the hierarchy is now App.xaml >> StylesAndTemplateResources >> PlatformLiteralResources >> LiteralResources.

And there you have it, you can now define platform specific literals in the PlatformLiteralResources xaml file without worrying about using the OnPlatform element.

Getting Started with Xamarin.Forms and Effects

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross
Getting Started with Xamarin.Forms and Authenticating with ADAL
Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

At some point in building a cross platform application using Xamarin.Forms you’ll need to build out some platform specific features. There are a couple of ways to do this, depending on what you want to achieve. One of those ways is to use an Effect. In this example we’re going to create an Effect that can be used to add a tooltip to any element. For the purposes of this exercise we’re going to assume that this only makes sense to add on UWP where the application can be used on a desktop where the user has a mouse and keyboard attached.

An Effect has two parts:

- A platform agnostic class which will contain any properties that the Effect needs to expose in XAML. This is the name of the element that will appear in XAML. In this case the class will be called TooltipEffect and inherits from RoutingEffect

- A platform specific class which provides the platform specific implementation. In this case this class will be called TooltipPlatformEffect and inherits from PlatformEffect. Note that as this is platform specific, it needs to reside in the platform specific folder

As an Effect is a UI component, it should be added to the UI project, which should now look something like:

image

A couple of things to note here:

- There are folders for Converters, Effects and Renderers – I’ve added these as they are common elements that you’ll be adding to your UI project

- I’ve moved MainPage into a folder called Pages

- In a lot of cases I’ll have another folder called Controls, which will contain any custom or user controls I build.

- The TooltipEffect class sits in the Effects folder (platform agnostic)

- The TooltipEffect.Platform file, which contains the TooltipPlatformEffect class, sits in the Uap platform specific folder

Now, let’s look at the implementation of the effect. First, we’ll start with the TooltipEffect:

public class TooltipEffect : RoutingEffect
{
     public TooltipEffect() : base("StrataPark.TooltipEffect")
     {
     }

    public string Tooltip { get; set; }
}

This class exposes a Tooltip string property which will be used to specify the tooltip text in XAML. In the call to the base constructor it passes in a unique identifier for the Effect. This is important to note because it needs to align with the identifier used by the platform specific implementation. Speaking of which, here’s the TooltipPlatformEffect:

[assembly: ResolutionGroupName("StrataPark")]
[assembly: ExportEffect(typeof(TooltipPlatformEffect), nameof(TooltipEffect))]

namespace StrataPark.UI.Effects
{
     [Preserve]
     public class TooltipPlatformEffect : PlatformEffect
     {
         protected override void OnAttached()
         {
             var view = Control ?? Container;

            var effect = Element.Effects.OfType<TooltipEffect>().FirstOrDefault();
             if (!string.IsNullOrWhiteSpace(effect?.Tooltip) && view != null)
             {
                 var toolTip = new ToolTip
                 {
                     Content = effect?.Tooltip
                 };
                 ToolTipService.SetToolTip(view, toolTip);
             }
         }

        protected override void OnDetached()
         {
         }
     }
}

The most important part of this code are the assembly level attributes that register both the namespace (i.e. the StrataPark prefix) and the element identifier (nameof(TooltipEffect) gives the second part of the identifier, “ToolTipEffect”). If the combination of these attributes don’t yield the same identifier set in the platform agnostic Effect, the platform specific implementation won’t be loaded at runtime.

You can now use this Effect in XAML as follows

<Button Text="Authenticate" Command="{Binding AuthenticateCommand}">
     <Button.Effects>
         <effects:TooltipEffect Tooltip="Welcome tooltip"/>
    </Button.Effects>
</Button>

One last note – when adding folders to your project, you should keep an eye on the changes that take place in your csproj. When you add/remove files and folders, occasionally Visual Studio will add unnecessary items to the csproj. Remember that by default files and folders will be include in the new csproj format. So for example, the following xml is not required, and should be removed, prior to checking your code in:

<ItemGroup>
   <Folder Include="Converters\" />
   <Folder Include="Renderers\" />
</ItemGroup>

As you’ve seen, Effects are one way to add platform specific UI logic to your application. An alternative, is to use Renderers but that’s a topic for another post.

Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio

I’ve walked through this a couple of times in the past (last year and in the Mvx+1 series I started) but I wanted to do an updated post to firstly point out that the getting started process in Visual Studio has stabilized quite a lot and the process of getting a new Xamarin.Forms project up and running is quite smooth. The second thing I wanted to add is how, and why, you can setup your .NET Standard libraries to be multi-targeted – this also has come a long way.

Note: I’m running Visual Studio 15.8 preview 5, so your experience may vary a little if you’re running a different version of Visual Studio. Before I get started I try to make sure all my components are up to date, including my MacMini which is what I use for building/debugging iOS applications.

Let’s get started by creating a new solution within Visual Studio, using the Mobile App (Xamarin.Forms) project template

image

This will prompt you to select what template to use, in this case we’re going to create a project based on a Blank template. In actual fact this template isn’t blank; it has 1 page which is required in order for the application to build and run. Also, make sure you select the .NET Standard Code Sharing Strategy. DO NOT select Shard Project – this options in my opinion should now be deprecated as multi-targeting is a much better option for achieving this same outcome.

image

After clicking OK to create the project, you’ll want to make sure you can successfully build all projects.

Next open the NuGet package manager for the solution and update all packages to the latest stable. In my case I just had to update Microsoft.NETCore.UniversalWindowsPlatform and Xamarin.Forms.

Now, make sure that each platform (i.e. iOS, Android and UWP) compiles and runs. Technically you don’t need to do this but if you run into difficulty later, at least doing a run check here gives you a “last known good” state to revert to. On that note, after checking that each platform runs, I would be making the initial commit to source control for your solution.

Next we’re going to add a new project based on the Class Library (.NET Standard) project template. This will be our Core project that will contain all our view models, services and business logic for the application.

image

The new project will come with Class1. Rename both the file and class name to MainViewModel.

Next we’re going to do a bit of a tidy up. By default the project that contains the XAML for the application (i.e. App.xaml) and for the main page of the application (MainPage.xaml) was given the same name as the solution itself. I’m not a big fan of that so I rename this to have the UI suffix. To do this you need to remove the existing project, rename the folder and project name, and add the existing project back into the solution. Don’t forget that you’ll need to update the namespace for both App and MainPage classes (in both XAML and code behind files) to include UI (e.g. the full type name of the MainPage class should be StrataPark.UI.MainPage)

After renaming the UI project, we need to double check that all the projects have the correct references. The only project reference the UI project should have is to the Core project

image

All three of the head projects (i.e. for iOS, Android and UWP) should reference both the Core and UI projects

image

Now’s another time to check that everything builds and runs (all three platforms) and then commit your changes!

Both the Core and UI projects are currently just .NET Standard 2.0 projects. This means that all code is the same for all platforms. By making these projects multi-targeted, we can enable platform specific code to be included where necessary. This is similar to the way shared libraries used to work. However, the difference is that the code stays in a separate assembly, away from the head projects.

To make use of multi-targeting, first create a file called global.json in solution folder, with the following contents:

{
     "msbuild-sdks": {
         "MSBuild.Sdk.Extras": "1.6.47"
     }
}

The MSBuild.Sdk.Extras package extends the raw multi-targeting support provided by Visual Studio/MSBuild. For both Core and UI projects, edit the csproj and replace the default TargetFramework element at the beginning of the file with the following (make sure you include the Project element as this sets the Sdk to use)

<Project Sdk="MSBuild.Sdk.Extras">
   <PropertyGroup>
     <TargetFrameworks>netstandard2.0;Xamarin.iOS10;MonoAndroid81;uap10.0.16299</TargetFrameworks>
   </PropertyGroup>

  <ItemGroup>
     <Compile Remove="Platforms\**\*.cs" />
     <None Include="Platforms\**\*.cs" />
   </ItemGroup>
  
   <ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
     <Compile Include="Platforms\Netstandard\**\*.cs" />
   </ItemGroup>
  
   <ItemGroup Condition=" $(TargetFramework.StartsWith('uap')) ">
     <Compile Include="Platforms\Uap\**\*.cs" />
   </ItemGroup>

  <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
     <Compile Include="Platforms\Ios\**\*.cs" />
   </ItemGroup>

  <ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
     <Compile Include="Platforms\Android\**\*.cs" />
   </ItemGroup>

If you take a look at the code that was added to the csproj, you can see that there are some conditional inclusions based on the target platform. We’ll make use of this to return a platform specific welcome text for our application.

Add a Platforms folder to the Core project

Add Netstandard, Ios, Android and Uap sub-folders to the Platforms folder

Add a file called MainViewModel.Platform.cs to each sub-folder of the Platforms folder with the following text. Replace Netstandard with the name of the platform (i.e. the sub-folder name)

public partial class MainViewModel
{
     private string PlatformWelcomeText => "Welcome from Netstandard";
}

Next, we’ll modify the MainViewModel.cs file. Note how the WelcomeText property returns the platform specific text

public partial class MainViewModel
{
    public string WelcomeText => PlatformWelcomeText;
}

In the MainPage.xaml, add a new Label element that is bound to the WelcomeText property

<Label Text="{Binding WelcomeText}" />

In the codebehind for the MainPage.xaml, add the following code to the end of the MainPage constructor

BindingContext = new MainViewModel();

Now when we build and run the application on each platform, we’ll see a platform specific welcome.

image

This technique can be used to include all sorts of platform specific code within your application, making it easier to deal with the Mvvm abstraction when you need to tie into platform specific APIs. In the past you’d have typically had to create a service in the head project, or some other clumsy workaround.

Redux and the State of My XAML Application (part 3)

This is the final part in this series looking at using Redux in a XAML application. Previous parts:

- Part 1 - https://nicksnettravels.builttoroam.com/post/2018/05/15/Redux-and-the-State-of-My-XAML-Application-(part-1).aspx

- Part 2 - https://nicksnettravels.builttoroam.com/post/2018/05/16/Redux-and-the-State-of-My-XAML-Application-(part-2).aspx

At the end of Part 2 I left you wondering what magic I’m using to prevent the entire list being refreshed as items were being added/removed from the Family. In this post we’ll look at what’s going on behind the scenes.

Let’s start with the bolded text from the XAML in Part 2 – I’ve included it here so you don’t need to go back and look.

<Page.Resources>
   <converters:ImmutableDataConverter x:Key="ImmutableDataConverter"/>
</Page.Resources>
<Grid DataContext="{Binding Converter={StaticResource ImmutableDataConverter}}">

So the secret ingredient is the ImmutableDataConverter which takes the current DataContext (which will be an instance of the MainViewModel) and returns an object that will become the DataContext for the rest of the page. The question is, what is this object and what does it do?

If you recall the issue we saw when we didn’t use the ImmutableDataConverter is that when the Data property on the MainViewModel changes (ie raised the PropertyChanged event) every data bound element on the page is refreshed. What we want is that only the elements on the page where data has changed should be updated. To do this, we need to step through the Data object and only raise PropertyChanged for the parts that have actually changed. Based on this description, the ImmutableDataConverter has to have the smarts to a) prevent PropertyChanged causing the entire UI to refresh and b) be able to iterate over every object in the Data object graph and where appropriate raise the PropertyChanged event.

Behind the scenes the ImmutableDataConverter is super simple – all it does is create an instance of the ImmutableDataWrapper<T> class. It uses a small piece of reflection to determine what the generic parameter should be based on the implementation of the IHasImmutableData interface on the MainViewModel.

The ImmutableDataWrapper<T> exposes a single property Data, of type T (and it’s no coincidence that this is the same as the IHasImmutableData<T> interface which also exposes a property Data, of type T – thereby making it simple to add the ImmutableDataConverter without changing any other lines of XAML). It also listens to the PropertyChanged event on the source entity, which in this case is the MainViewModel. Now instead of the PropertyChanged event on the MainViewModel being picked up by the MainPage, it is instead picked up by the ImmutableDataWrapper and used to invoke the ChangeData method where all the work happens.

The ChangeData method is used to compare the old Data object with the new Data object (ie the value that is set on the MainViewModel when the PropertyChanged event is triggered). It does this by using reflection to step through each property on the Data object:

- Properties that are of value type, or string, are updated on the old Data object if the value on the new Data object is different – the PropertyChanged event is raised for just that property.

- For properties that return a non-value type (or string) reflection is used to interrogate the nested entity and work out which properties need to be updated.

- For ObservableCollections some basic list change detection is used to trigger add/remove events on the collection on the old Data object – we can probably improve the logic here to be more efficient but for the moment it does the job.

As you can imagine there’s quite a bit of reflection that has to go on each time the Data object changes. Assuming that the Data object could change quite a bit, we don’t want to be doing reflection every time, which is where the TypeHelper class comes it. The TypeHelper class has some smarts of assisting with both checking to see if an entity has change, and for updating entities. Based on the type of entity, it caches methods that are used for comparison and updating entities. You can check out the TypeHelper class if you want to see more of the details

So lastly, let’s look at the requirements for the ViewModel and your Data entity:

- ViewModel needs to implement IHasImmutableData

- Data entity (and any nested entities) needs to implement INotifyPropertyChanged but also IRaisePropertyChanged – this is required so that the ChangeData method can raise the PropertyChanged on behalf of a data entity

- Properties on the Data entity (and any nested entities) should not raise PropertyChanged – otherwise there will be multiple PropertyChanged events raised

- Any collections within the Data entity hierarchy should use ObservableCollection<T>

A couple of final pointers:

- Currently this is only available for UWP – I need to implement the appropriate converter for Xamarin.Forms (and I guess WPF if anyone cares?)

- Currently this is not thread safe – make sure you update the Data property on the ViewModel on the UI thread.

Redux and the State of My XAML Application (part 2)

In part 1 I talked a bit about the challenge that XAML based applications face when trying to use a pattern such as Redux. In this post I’m going to jump in and use Redux.NET to demonstrate the issue, and the show how we can make a small adaption to the XAML to fix this issue.

We’ll start with the basic – our application state is a Person entity, with a Name property and a Family property. The Family property is an ObservableCollection of Person:

public class Person : NotifyBase
{
     public string Name { get; set; }

    public ObservableCollection<Person> Family { get; set; } = new ObservableCollection<Person>();
}

In this case NotifyBase comes from the BuildIt.General library and implements INotifyPropertyChanged. It also implements IRaisePropertyChanged which exposes a RaisePropertyChanged method which can be called in order to raise a PropertyChanged event on the object – we’ll come to why this is important later.

Implementing the Redux pattern starts with the Store, and in this case I’m just going to expose this as a static property off the App class. In reality you���d probably register this with your IoC container and have it injected into your ViewModel but to keep things simple I’m just creating it as a static property.

sealed partial class App : Application
{
     public static IStore<Person> PersonStore { get; private set; } = new Store<Person>(reducer: PersonReducer.Execute, initialState: new Person { Name = "Fred" });

The Store of course requires a Reducer, which in this case will be the PersonReducer class

public static class PersonReducer
{
     private static Random rnd = new Random();
     public static Person Execute(Person state, IAction action)
     {
         if (action is AddAction addAction)
         {
             var newPerson = new Person { Name = addAction.NameOfNewFamilyMember };

            return new Person
             {
                 Name = state.Name,
                 Family = state.Family.DeepClone().AddItem(newPerson)
             };
         }

        if (action is RemoveAction)
         {
             var idxToRemove = rnd.Next(0, 1000) % state.Family.Count;
             return new Person
             {
                 Name = state.Name,
                 Family = state.Family.DeepClone().RemoveItemAt(idxToRemove)
             };
         }

        return state;
     }
}

As you can see from the code the PersonReducer implements two actions: AddAction and RemoveAction. We’ll create these as classes

public class AddAction : IAction
{
     public string NameOfNewFamilyMember { get; set; }
}

public class RemoveAction : IAction { }

The other thing to note about the PersonReducer is that both actions return entirely new Person entities. It also makes use of a couple of helper methods:

public static class ReduxHelpers
{

    public static ObservableCollection<T> DeepClone<T>(this ObservableCollection<T> source) where T : new()
     {
         var collection = new ObservableCollection<T>();
         var helper = TypeHelper.RetrieveHelperForType(typeof(T));
         foreach (var item in source)
         {
             var newItem = new T();
             helper.DeepUpdater(newItem, item);
             collection.Add(newItem);
         }
         return collection;
     }

    public static ObservableCollection<T> AddItem<T>(this ObservableCollection<T> source, T itemToAdd)
     {
         source.Add(itemToAdd);
         return source;
     }

    public static ObservableCollection<T> RemoveItemAt<T>(this ObservableCollection<T> source, int index)
     {
         if (index < 0 || index >= source.Count) return source;
         source.RemoveAt(index);
         return source;
     }
}

Note: These extension methods will be added to BuildIt.General in the coming days and they rely on other types/methods (such as the TypeHelper class) that are already part of the BuildIt.General library.

With the Store and Reducer defined, we can define our MainViewModel

public class MainViewModel : NotifyBase, IHasImmutableData<Person>
{
     private Person data;
     public Person Data
     {
         get => data;
         set => SetProperty(ref data, value);
     }

    public MainViewModel()
     {
         App.PersonStore.Subscribe(newData => Data = newData);
     }
}

As this code shows, when the state in the Store changes, we’re just updating the Data property on the MainViewModel, this will in turn raise the PropertyChanged event causing the UI to be re-bound. Let’s take a look at the XAML for the MainPage.xaml:

<Page
     x:Class="reduxsample.MainPage"
     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:converters="using:BuildIt.UI.Converters"
     mc:Ignorable="d"
     Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
     <Page.Resources>
         <converters:ImmutableDataConverter x:Key="ImmutableDataConverter"/>
     </Page.Resources>

     <Grid DataContext="{Binding Converter={StaticResource ImmutableDataConverter}}">
         <Grid DataContext="{Binding Data}">
             <Grid.RowDefinitions>
                 <RowDefinition Height="Auto"/>
                 <RowDefinition />
             </Grid.RowDefinitions>
             <StackPanel Grid.Row="0">
                 <TextBlock Text="Name"/>
                 <TextBlock Text="{Binding Name}"/>
                 <TextBlock Text="Family member to add"/>
                 <TextBox x:Name="NewFamilyMemberName"/>
                 <Button Content="Add" Click="AddFamilyClick"/>
                 <Button Content="Remove" Click="RemoveFamilyClick"/>
             </StackPanel>
             <ListView Grid.Row="1" ItemsSource="{Binding Family}">
                 <ListView.ItemTemplate>
                     <DataTemplate>
                         <Border
                             BorderBrush="Azure"
                             BorderThickness="0,0,0,1">
                             <TextBlock Text="{Binding Name}"/>
                         </Border>
                     </DataTemplate>
                 </ListView.ItemTemplate>
             </ListView>
         </Grid>
     </Grid>
</Page>

This is all stock XAML with the exception of the Bold text (which we’ll come to in a minute). First, let’s add the methods for adding and removing family members

public sealed partial class MainPage : Page
{
     public MainPage()
     {
         this.InitializeComponent();

        DataContext = new MainViewModel();
     }
     private void AddFamilyClick(object sender, RoutedEventArgs e)
     {
         App.PersonStore.Dispatch(new AddAction { NameOfNewFamilyMember = NewFamilyMemberName.Text });
     }
     private void RemoveFamilyClick(object sender, RoutedEventArgs e)
     {
         App.PersonStore.Dispatch(new RemoveAction());
     }
}

Ok, now for a minute, let’s go back to the XAML and for a minute imagine that the bold text isn’t there. Now when we run the app and click the Add or Remove button, the Data property on the MainViewModel will get repopulated – the implication on the UI is that the ListView which binds to the Family property will refresh entirely. This will cause a flicker, and will drop any selected state and/or scroll position on the list – generally a really bad user experience.

With the bold text left in the XAML, when we run the app and click the Add or Remove button, only the properties that have changed are refreshed – there is no flicker on the ListView and any selection/scroll position is maintained….. so what’s going on…. can you work out why IRaisePropertyChanged is important…. more to come in my next post.

Redux and the State of My XAML Application (part 1)

Recently there has been quite a bit of noise about new tools and technologies (eg Flutter) and how they’re going to reshape how we build mobile applications. Various developers have blown a lot of smoke into the ecosystem as they’ve thrown in the towel with one technology and jumped headlong into the unknown. In this post I wanted to explore one of the key architectural differences that has developers up in arms about.

Let’s firstly step back a few, or more, years back to the dark ages of building Windows Forms (WinForms) applications where everything was done via imperative code. Visual Studio provided some basic abstraction from designer generated code v’s developer code but other than that everything was done manually. Whilst WinForms did have a form of data binding, it was so hard to get it to work well, most apps ended up resorting to writing logic to set properties on the UI elements directly.

A little further along the timeline we see the introduction of XAML (WPF, Silverlight etc) where data binding was a first class citizen. Enter the age of the MVVM pattern which was widely adopted as it offered a great separation of concerns between the view (ie the XAML) and the logic of the app. Personally I’ve never seen MVVM as much more than just the use of data binding. Recently I’ve heard of all sorts of reasons why developers thought that MVVM was being used, such as allowing the reuse of ViewModels and/or Models across different apps – I’m not sure where this concept came from but the reality is that it never happens. I think MVVM is still just about making it easier to test the logic of the application without having to spin up the UI.

Databinding works well, allowing the UI to be declaratively defined (either in XAML or code) but it doesn’t prescribe how an application should be architected behind the scenes. There are some frameworks, such as MvvmCross that help with a lot of the boilerplate logic (app start up, DI framework, navigation etc), but that’s where the guidance ends. For simple applications this isn’t an issue, and for a lot of application complexity is kept quite low, which means that keeping business logic, and state, on a page by page basis isn’t an issue. However, over time applications grow, and the complexity increases. This was identified by Facebook as the complexity of their website grew and they needed a more effective way to manage state. At this point I’m going to skip ahead to Redux (there’s more background at redux.js.org) which aims to solve the issue of state management within an application using a mono-direction flow to ensure consistency of state. I’m also not going to proclaim to be a guru on Redux, I just want to point to how it supports a new wave of React style development. The essential concept is that app state is immutable and that any changes result in a new state.

If you take a look at the way that Flutter builds their UI, the layout is made up of a sequence of widgets generated each time the build method is invoked. As the state of the application changes, a call to setState will trigger the build method to be run, yielding a completely new set of widgets that will be painted in the next pass to the screen. It’s pretty obvious that if the app state is being regenerated on each change (ie Redux pattern), this plays nicely with the setState/build flow that’s core to Flutter.

So, the question is – if we want to take advantage of Redux, do we have to abandon ship and start building Flutter apps? Well if you want to give up on all the years of experience you have, the mature ecosystem, and all the platforms that Flutter doesn’t support, sure, why not, but I do feel that in the absence of other reasons, that this is a bit like throwing the baby out with the bathwater.

To rephrase the question – in a XAML application, how do we take advantage of Redux? Well the good news is that half the work is already done – Redux.NET. However, I would caution you not to follow the rather simplistic examples given on the project website which essentially disposes of the use of data binding – if you’re going to do that, just go build your app using a different technology. Instead, we need to think a bit more about how we can marry the concept of immutable state with data binding.

The naïve approach is to expose the state of the application as a property and then every time the state changes, we update the property with the new value. For example the following ViewModel exposes a Person object which represents the current state of this simple application.

public class MainViewModel : INotifyPropertyChanged
{
     private Person data;

    public Person Data
     {
         get => data;
         set => SetProperty(ref data, value);
     }

This approach will work and as the Data property is updated with new Person entities, the data bound UI will update accordingly. However, if the Person object is moderately complex, with nested data bound properties, when you update the Data property there will be some nasty UI artefacts – this is because triggering PropertyChanged on the Data property will force every data binding that starts with Data to be re-evaluated. Imagine that the Person entity has a property Family, which is a list of Person entities, and that property is data bound to a ListView. If the Data property changes, the entire ListView will be repopulated, losing any selection or scroll position, not to mention other visual artefacts such as a flicker as it redraws. Clearly this isn’t what we want to happen.

This leads us to the question of how change is managed within our application. Let’s go back over our history lesson:

- With WinForms we were required to do everything. Every change within our application we needed to evaluate whether something needed to change on the UI, and then we’d explicitly set the appropriate property on the control.

- With XAML based applications we updated properties that were data bound. We still needed to work out what changed, because we didn’t want to raise the PropertyChanged event more than was absolutely necessary.

- With React style applications we no longer need to track what’s changed, we just use the latest state to build the UI.

The latter sounds great, except for the reality is that there is going to be some change tracking going on, we just don’t need to code for it. Let’s look at an example – say we have a list of items on the screen and the user has scrolled half way down the list. If the UI was to just be rebuilt, that scroll position would be lost. The same applies to text entered into a text field etc.

Perhaps what we need to do is to abstract away the need to work out what’s changed and invoke PropertyChanged only for the properties that have actually changed – if we can do that, then updating our Data property can be done as much as it needed without worrying about weird UI artefacts……

Part 2 will show an example of how changing state can be handled in a XAML application along with using Redux to keep our state immutable