Content from Former Microsoft WPF and Silverlight Team Member

Someone pointed me in the direction of a series of great blog posts that have recently been migrated to a github repository. The posts are quite old, dating back to a period between 2005 and 2013 when Beatriz Stollnitz worked for Microsoft as part of the WPF and Silverlight teams. Here are the links to each of the posts – happy reading!

Update 11th August: I’ve forked the repository and have started to work my way through the sample code to a) update it to WPF on .NET 4.7.2 and b) provide a similar example for UWP + Uno (iOS, Android, WASM). Feel free to check it out and help out!

01-DataContext

02-EmptyBinding

03-GetListBoxItem

04-BindToComboBox

05-DisplayMemberPath

06-SelectedValue

07-ChangePanelItemsControl

08-BarGraph

09-CollectionViewSourceSample

10-MasterDetail

11-MasterDetailThreeLevels

12-DataBoundDialogBox

13-TemplatingItems

14-SortingGroups

15-GroupingTreeView

16-GroupByType

17-BoundListView

18-ThreeLevelMasterDetailADO

19-ObjectDataProviderSample

20-InsertingSeparators

21-CustomSorting

24-AsynchronousBinding

25-BindToEnum

26-DataTriggerSample

27-ConvertXaml

28-FilterSample

29-MultipleFilters

30-MultiBindingConverter

31-ChangesMultithreading

32-PolygonBinding

33-PolygonBinding2

34-PolygonBinding3

35-CommonQuestions

36-ADOIndependentView

37-PlanetsListBox

38-UpdateExplicit

39-TreeViewPerformancePart1

40-TreeViewPerformancePart2

41-TreeViewPerformancePart3

42-WPFPresenter

43-BindToXLinq

44-XLinqXMLMasterDetail

45-DebuggingDataBinding

46-DragDropListBox

47-ExpandTreeViewPart1

48-ExpandTreeViewPart2

49-ExpandTreeViewPart3

51-UIVirtualization

52-DataVirtualization

54-PieChartWithLabels

55-PieChartWithLabelsSilverlight

56-PieChartWithLabelsSilverlight

57-DataVirtualization

58-MultipleStyles

59-WPFCollectionViewSource

60-SLCollectionViewSource

61-OredevComputerWeekly

62-DataVirtualizationFiltering

64-DataVirtualizationFilteringSorting

66-SortingHierarchy

67-PieChartWithLabelsUpdates

69-BindRadioButtonsToEnumsPart1

70-BindRadioButtonsToEnumsPart2

71-BindRadioButtonsToEnumsPart3

72-BindRadioButtonsToEnumsPart4

73-BindRadioButtonsToEnumsPart5

74-PositioningDataBoundItems

75-SimultaneousEnableDisable

76-FocusWatcher

77-CaptureWatcher

78-BetterBindableBase

79-BooleanConverters

Using the UWP SplitView on iOS, Android and WebAssembly with Uno

In this post we’re going to cover one of the basics of app navigation which is the use of the UWP SplitView. If you’re coming from iOS and Android development you might be thinking “huh, I don’t even know what that is.” Well the good news is that it’s actually something you’re already familiar with. Whether you’re used to an app that has a master-details layout, or one that uses a burger menu to display a flyout menu, these can both be implemented using the UWP SplitView.

One thing to be aware of is that the UWP SplitView is one of the basic controls that was added early in the UWP lifecycle. Since then there have been other controls added, such as the NavigationView and the MasterDetailsView (Windows Community Toolkit) that provide extended functionality and are worth exploring depending on the requirements of your project.

New Project – Cross-Platform App (Uno Platform)

Let’s get into it – we’re going to start with creating a new project based on the latest Uno Visual Studio Extension (updated at end of July – if you’re using an older version I would recommend updating). I’m also working with the Visual Studio 2019 (16.3 preview 1.0) as this provides the best support for working with WebAssembly.

Cross-Platform App using the Uno Solution Template

Once you’ve created your solution, I would highly recommend that you a) update NuGet references and b) go through each platform and make sure you can build and run the application. However, as at the time of writing do NOT update the Microsoft.Extensions.Logging.* packages – there’s a note in the csproj files that states “Note that for WebAssembly version 1.1.1 of the console logger required.” My recommendation is to leave these packages at v1.1.1 across all projects. For the Uno libraries I pick the latest prerelease versions but be warned that this occasionally backfires as you may get an unstable version – this is why it’s important to run each platform before proceeding!!

Note: One issue I’m currently seeing in the Uno template is that it generates assets (i.e. images) with names that include the scale factor eg scale-200. This is fine for UWP but fails to build for Android. I’ve gone through and just removed the scale factor from the filenames. You’ll need to rebuild your UWP project to make sure it picks up the filename changes correctly.

Note 2: When running the WebAssembly (aka WASM) project, make sure you select “Start without Debugging” in Visual Studio.

Note 3: When running the iOS build you may need to set the Deployment Target in the Info.plist. If you’re using the latest preview of Visual Studio it will pick up iOS 12.4 on the build agent which will cause you app to fail to deploy if you haven’t set the Deployment Target.

Adding the UWP SplitView

Now that we have our new application up and running, it’s time to add the SplitView control.

Design in Blend

For this we’re going to switch over to Blend – yeh, the product still exists and you’ll see in a minute why we’re going to be using it. To make the switch, right-click on the MainPage.xaml in the shared project and select Design in Blend.

Switching to Design in Blend

Switching to Blend will take a few seconds, particularly if this is the first time you’ve ever opened Blend. You’ll also see errors as the iOS and Android projects won’t open – ignore these and don’t worry about the upgrade log that will popup (these are irritating but can be safely ignored as they won’t impact your project).

Despite selecting Design in Blend from the MainPage.xaml, once in Blend, you’ll actually need to use the Solution Explorer window to open MainPage.xaml in the designer. Once you’ve opened MainPage.xaml, Blend should feel fairly familiar, even if this is the first time you’ve used it. This is because a lot of the windows are shared with Visual Studio – the separation between the products is a mix of legacy (don’t want to disrupt the tiny percentage of developers who still use it) and the optimising that design tasks will be done using Blend.

Blend Designer

Adding the SplitView

There are a number of ways to add the SplitView control into the MainPage. If you’re familiar with writing XAML it’s probably just easiest to add the SplitView element. However, to build familiarity with Blend, let’s add the SplitView using the designer. In the Assets window, enter “splitview” to locate the SplitView control. Use the mouse to drag the SplitView down to the Objects and Timeline window at the position in the hierarchy where you want it to appear. In this case we’re going to drop it inside the existing Grid – I typically have a Grid as the root of most pages to allow setting of background and other properties using a application-wide style, independently of what content is nested within the Grid.

Adding the UWP SplitView

Adding the SplitView this way will add it as the second child of the Grid, immediately following the existing TextBlock. As we want the SplitView to take up the entire space of the page, we’re going to move the TextBlock in the main content area by dragging the TextBlock into the Grid that is nested within the SplitView. The XAML of the page should now look like the following:

<Page
    x:Class="UwpSplitViewSample.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:local="using:UwpSplitViewSample"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <SplitView>
            <SplitView.Pane>
                <Grid />
            </SplitView.Pane>
            <Grid>
                <TextBlock
                    Margin="20,20,20,20"
                    FontSize="30"
                    Text="Hello, world !" />
            </Grid>
        </SplitView>
    </Grid>
</Page>

The SplitView is made up of two distinct areas: the main content area and the pane that can be shown/hidden (i.e. the flyout). From this code we can see that the SplitView as two nested XAML elements which align to the SplitView areas. The first is the SplitView.Pane which defines the layout of the content that will appear within the pane/flyout of the SplitView. The second defines the layout of content to appear within the main content area of the SplitView, in this case a Grid with a TextBlock contained within it.

Adjusting Layout with Blend

I’ll repeat this: For those of us familiar with writing XAML, you’ll find that manually crafting XAML is by far the quickest way to add and edit elements. However, Blend provides a number of shortcuts for positioning elements that can come in handy. Some of which we’ll cover here.

Designing the SplitView Pane

For the purpose of this post, all we’re going to do is to add a StackPanel with a TextBlock and Button as children to both the SplitView.Pane and the SplitView. The TextBlock will be used to indicate what part of the SplitView it is (Pane or Content) and the Button will be used to Show and Hide the pane of the SplitView.

Let’s start with the SplitView.Pane which already has a Grid element. In the Objects and Timeline window, right-click on the Grid and select Change Layout Type, followed by StackPanel.

Change Layout Type to StackPanel

You should see the Grid change to StackPanel and remains selected in the Objects and Timeline window. Next, with the StackPanel still in focus, use the Assets window to locate the TextBlock and double-click on TextBlock to add a TextBlock as a child to the StackPanel. Repeat, this time for a Button.

We’re going to position the StackPanel in the centre of the SplitView pane. To do this, again keep the StackPanel selected in the Objects and Timeline window, we’re going to go to the Properties window and scroll down to the Layout section at set the HorizontalAlignment and VerticalAlignment properties to Center.

Centering the StackPanel

Whilst we’re using the Properties window, select the TextBlock and change the Text property to “Pane”, and then select the Button and change the Content property to “Hide Pane” (Note that unlike Xamarin.Forms that has a Text property, to set the text on a Button in UWP XAML you need to set the Content property).

The last thing we’re going to do with the XAML for the SplitView.Pane is to add an event handler to the Click event of the Button. With the Button selected in the Objects and Timeline window, go to the Properties window, and click on the lightning bold icon to switch from properties to events view. Locate the Click event and type the name of the event handler you want to create, in this case PaneButtonClick. When you press Enter the PaneButtonClick method will be created in the MainPage.xaml.cs code behind file and the XAML will be updated with the Click property.

Adding an Event Handler for the Click Event

For the moment, that’s where we’ll leave the XAML for the SplitView.Pane and we’ll implement the logic for the Click event handler shortly.

Designing the SplitView Content

The layout of the SplitView content is going to be very similar to that of the pane: A StackPanel with nested TextBlock and Button. However, we’re going to go about it slightly differently, considering the fact that we already have a TextBlock nested in a Grid in the content area. We’re going to start by wrapping the TextBlock in a StackPanel. To do this, right-click somewhere in the TextBlock on the designer and select Group Into, followed by StackPanel (this also works if you right-click on the TextBlock in the Objects and Timeline window).

After doing this the hierarchy of elements in the SplitView content will be Grid, StackPanel, TextBlock. However, if you look at the XAML you’ll notice that Blend has added some additional attributes, setting the Margin on the StackPanel and the Height and Width on the TextBlock. To remove these, we can just right-click the StackPanel and select Layout, followed by Reset All. Repeat this on the TextBlock.

From here we can repeat the remaining steps that we did for the SplitView pane:

  • Add a Button to the StackPanel
  • Set HorizontalAlignment and VerticalAlignment on the StackPanel to Center
  • Set Text on the TextBlock to “Content Area”
  • Set Content on the Button to “Show Pane”
  • Add an event handler called ShowPaneButtonClick to the Button Click event

The final XAML in MainPage.xaml should look similar to:

<Page x:Class="UwpSplitViewSample.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:local="using:UwpSplitViewSample"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <SplitView>
      <SplitView.Pane>
        <StackPanel HorizontalAlignment="Center"
                    VerticalAlignment="Center">
          <TextBlock Text="Pane"
                     TextWrapping="Wrap" />
          <Button Click="PaneButtonClick"
                  Content="Hide Pane" />
        </StackPanel>
      </SplitView.Pane>
      <Grid>
        <StackPanel HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Orientation="Vertical">
          <TextBlock Text="Content Area" />
          <Button Click="ShowPaneButtonClick"
                  Content="Show Pane" />
        </StackPanel>
      </Grid>
    </SplitView>
  </Grid>
</Page>

DisplayMode Property on the UWP SplitView

The UWP SplitView has two properties that are worth exploring in a bit of detail and we’ll use these to control the behaviour, or should I say the layout, of the SplitView based on screen width. Let’s start with the easy one, which is the IsPaneOpen property. As you can imagine from the name, this property indicates whether the pane of the SplitView is currently open (i.e. displayed in full, rather than hidden or in compact mode), or not.

The second property worth looking at is the DisplayMode of the SplitView, and has the following four possible values:

  • Overlay – When the pane is visible it appears as an overlay across the content area. It doesn’t affect the size of the content area when it is shown/hidden.
  • Inline – When the pane is displayed it reduces the size of the content area by the width of the pane. As the pane is shown/hidden the width of the content area shrinks and grows accordingly.
  • CompactOverlay – Same as Overlay, except when the pane isn’t open, it still takes up space on the page equal to the CompactPaneLength property. Typically the compact view would show a list of icon buttons as a summary of the options available in the pane when it’s open.
  • CompactInline – Same as Inline, except when the pane isn’t open it still takes up space on the page equal to the CompactPaneLength property.

We’ll leave the use of the CompactOverlay and CompactInline options for the moment and focus on the other two options. The Overlay option is great for when the size of the application is narrow, for example on a mobile phone. The Inline option is better suited for when the application has sufficient width to allow the pane to be shown and there still to remain sufficient content area to be useful.

Using VisualState to Set DisplayMode

With this in mind, we’re going to use visual states to set the DisplayMode property based on the width of the application. For the purpose of this post we’re going to use a split point of 900, meaning that if the width of the application is greater than 900 the DisplayMode will be set to Inline. If it’s below 900 it’ll be set to Overlay.

To begin with, we’re going to set the default value of the DisplayMode to Compact by adding DisplayMode=”Compact” to the SplitView element. Next in Blend we’re going to add two visual states via the States window. In the States window, click the Add state group button and give the state group a name, SizeStateGroup.

Adding a Visual State Group

Next, click the Add state button twice to add two visual states and name them NarrowState and WideState. The actual names of the visual state group and the states are only for your benefit at this point, so you can name them according to what makes sense for you.

Adding a Visual State

Click on the WideState and you should see a red dot appear along side the state name. This indicates that Blend is in visual state editing mode. You should also see a red border appear around the main design area. Note that when you’re in visual state editing mode in Blend, any change you make via the tool windows (eg changing a property) will be tracked against the selected visual state.

Visual State Editing Mode

In visual state editing mode for the WideState, use the Properties window to change the DisplayMode to Inline. Next click the lightning icon button, Edit Adaptive Triggers, alongside the WideState visual state.

Adding an AdaptiveTrigger

In the Collection Editor: StateTriggers, set the MinWindowHeight to 0 and the MinWindowWidth to 900. This is adding a trigger which will return true when the width of the application exceeds 900. At this point the VisualStateManager will automatically switch to the WideState, without you having to explicitly run any code. Repeat the process of setting an adaptive trigger but this time for the NarrowState and set both MinWindowHeight and MinWindowWidth to 0.

The final XAML:

<Page x:Class="UwpSplitViewSample.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:local="using:UwpSplitViewSample"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <SplitView x:Name="splitView"
               DisplayMode="Overlay">
      <SplitView.Pane>
        <StackPanel HorizontalAlignment="Center"
                    VerticalAlignment="Center">
          <TextBlock Text="Pane"
                     TextWrapping="Wrap" />
          <Button Click="PaneButtonClick"
                  Content="Hide Pane" />
        </StackPanel>
      </SplitView.Pane>
      <Grid>
        <StackPanel HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Orientation="Vertical">
          <TextBlock Text="Content Area" />
          <Button Click="ShowPaneButtonClick"
                  Content="Show Pane" />
        </StackPanel>
      </Grid>
    </SplitView>
    <VisualStateManager.VisualStateGroups>
      <VisualStateGroup x:Name="SizeStateGroup">
       
        <VisualState x:Name="WideState">
          <VisualState.StateTriggers>
            <AdaptiveTrigger MinWindowHeight="0"
                             MinWindowWidth="900" />
          </VisualState.StateTriggers>
          <VisualState.Setters>
            <Setter Target="splitView.(SplitView.DisplayMode)" Value="Inline" />
          </VisualState.Setters>
        </VisualState>
        <VisualState x:Name="NarrowState">
          <VisualState.StateTriggers>
            <AdaptiveTrigger MinWindowHeight="0"
                             MinWindowWidth="0" />
          </VisualState.StateTriggers>
        </VisualState>
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
  </Grid>
</Page>

Note: In UWP the order of the VisualState elements doesn’t matter as all the AdaptiveTriggers are evaluated and the best match is determined. For example if the application width is 1000, the conditions for the triggers for both NarrowState and WideState are met. However, the WideState is a better match since the width is > 900. For Uno (i.e. iOS, Android and WebAssembly), the order matters – the first trigger to match, wins. In the above XAML you’ll see the WideState before the NarrowState to make sure that if the application width is > 900, the WideState visual state is active.

Opening and Closing the UWP SplitView Pane

If you run the application at this point and adjust the width of the application the DisplayMode property will switch between Inline and Overlay. However, you won’t notice any change because we currently don’t have a way to open the pane. To do this we’ll add some code to the Click event handlers we created earlier, as follows:

private void PaneButtonClick(object sender, RoutedEventArgs e)
{
    splitView.IsPaneOpen = false;
}
private void ShowPaneButtonClick(object sender, RoutedEventArgs e)
{
    splitView.IsPaneOpen = true;
}

UWP SplitView In Action

With all the XAML and code in place, let’s see it in action on all various platforms.

UWP with Resizing Application
Opening the Pane on WASM
Auto-dismiss Flyout on Android

In this post we’ve covered off how easily you can build a responsive interface using Blend and the UWP SplitView. The fact that it then just works on iOS, Android and WebAssembly is a big bonus thanks to the Uno platform.

ListView and GridView Templates for Windows (UWP)

In my previous post I discussed Control Template in Windows development (UWP and Platform.Uno). I feel the topic of templates warrants at least one follow up post. So, in this post I’m going to walk through ListView Templates and GridView Templates. As both ListView and GridView inherit from ListViewBase, I’m actually going to focus my attention on the ListView. However, the GridView shares the same templates, just with a default horizontal layout.

You might be thinking that surely the ListView only has 1, maybe 2, templates. In this post you’ll see that there are all sorts of templates, that allow you to tailor the ListView. The flexibility offered by the XAML framework, whether you code in XAML or in C#, is truly amazing, as you’ll come to see.

Populating a ListView with Data

Let’s jump in and build out a basic page with some data. For the purpose of this post I’m going to define a static array of data that we’ll be working. I’ve exposed a property, Presenters, that lists a selection of presenters for the upcoming Xamarin Developer Summit. Each presenter has a Name, Title, Company and AvatarUrl.

public sealed partial class MainPage 
{
    public MainPage()
    {
        this.InitializeComponent();
    }
 
    public Presenter[] Presenters { get; } = 
        new Presenter[]
    {
        ("Dan Siegel", "Microsoft MVP & Owner","AvantiPoint", 
        "https://xamarindevelopersummit.com/wp-content/uploads/2019/04/[email protected]" ),
        ("David Ortinau", "Senior Program Manager","Microsoft", 
        "https://xamarindevelopersummit.com/wp-content/uploads/2019/04/david_spk.png" ),
        ("James Montemagno", "Principal Program Manager","Microsoft", 
        "https://xamarindevelopersummit.com/wp-content/uploads/2019/04/james_spk.png" ),
        ("Donovan Brown", "Principal DevOps Manager","Microsoft", 
        "https://xamarindevelopersummit.com/wp-content/uploads/2019/04/donovan_spk.png" ),
        ("Jonathan Peppers", "Senior Software Engineer","Microsoft", 
        "https://xamarindevelopersummit.com/wp-content/uploads/2019/05/[email protected]" ),
        ("Martijn van Dijk", "Microsoft and Xamarin MVP","Baseflow", 
        "https://xamarindevelopersummit.com/wp-content/uploads/2019/04/[email protected]" )
    };
}

public class Presenter
{
    public string AvatarUrl { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
    public string Company { get; set; }

    public static implicit operator Presenter((string Name, string Title, string Company, string AvatarUrl) info)
    {
        return new Presenter { Name = info.Name, Title=info.Title, Company = info.Company, AvatarUrl = info.AvatarUrl };
    }
}

In the XAML for the MainPage I’m going to add a ListView and set the ItemsSource property to the Presenters property. I’m using the x:Bind syntax to eliminate the need for reflection and improve performance of the app. However, if your data isn’t available when the page loads, you should consider setting the Mode to OneWay if using the x:Bind syntax.

<Grid>
    <ListView ItemsSource="{x:Bind Presenters}" />
</Grid>

At this point if I run the app, what I see is a blank window. However, on closer inspection you can see that there are indeed multiple rows. As the mouse moves over a row it gets a grey background. When I click on a row, that row gets a black border around it, to indicate it’s the selected row.

Clearly we need to adjust the layout of the ListView so that we can see information about the presenters.

Default Layout using ToString

We’ll start with the simplest way to get information to display in the ListView, which is to override the ToString method. Here I’m returning a string made up of the Name, Title and Company of the presenter.

public override string ToString()
{
    return $"{Name} - {Title} - {Company}";
}

Running the app again, without modifying the XAML, I can see that each row corresponds to a presenter in the Presenters array.

Display Single Property using DisplayMemberPath

The DisplayMemberPath property on the ListView can be used to specify a property on the data bound item. In this case we’re setting the path to be the Name property.

<ListView DisplayMemberPath="Name"
        ItemsSource="{x:Bind Presenters}" />

Whilst the DisplayMemberPath might be useful for simple data sets, it does rely on reflection. The string literal set as the DisplayMemberPath needs to be converted into a get operation on the corresponding property.

Item Layout using ItemTemplate and ItemTemplateSelector

What do you do if you want to specify a more complex layout for the items in the array. One of the most common templates to be specified on a ListView is the ItemTemplate. By defining a DataTemplate that can be used by the ListView, you can control exactly how each item in the ListView is presented.

Using a DataTemplate for an ItemTemplate

If you haven’t worked with ListView templates before, it’s worth opening your solution in Visual Studio Blend. In the Objects and Timeline window, right-click on the ListView and select Edit Additional Templates, Edit Generated Items (ItemTemplate) and Create Empty.

Give the new template a name, PresenterItemTemplate, and add it as a resource on the page.

The XAML only contains the ItemTemplate and ItemsSource properties. The DisplayMemberPath shown earlier is no longer required

<ListView ItemTemplate="{StaticResource PresenterItemTemplate}"
            ItemsSource="{x:Bind Presenters}" />

Each presenter is displayed using two columns that you can see defined in the following XAML. In the first column is an Image using the AvatarUrl property. The second column has a StackPanel, allowing the Name and Company to be stacked.

<DataTemplate x:Key="PresenterItemTemplate"
                x:DataType="local:Presenter">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Image Margin="8"
                Source="{x:Bind AvatarUrl}" />
        <StackPanel Grid.Column="1"
                    VerticalAlignment="Center">
            <TextBlock Margin="0,0,0,4"
                        Text="{x:Bind Name}"
                        Style="{StaticResource TitleTextBlockStyle}" />
            <TextBlock Text="{x:Bind Company}"
                        Style="{StaticResource SubtitleTextBlockStyle}" />
        </StackPanel>
    </Grid>
</DataTemplate>

Our items are already looking much better. Note that the hexagonal frame around the presenter’s avatar is part of the image, not the ItemTemplate.

Multiple Templates using a DataTemplateSelector as the ItemTemplateSelector

In some cases it may be necessary that you need to modify the ItemTemplate based on some attribute of the data. By setting the ItemTemplateSelector property on the ListView, you can dynamically switch the ItemTemplate that’s used.

For this example we’re going to use whether the presenter works for Microsoft or not, based on their Company property. I’ve created a derived class, PresenterTemplateSelector, off of the DataTemplateSelector base class. In the SelectTemplateCore method I’m inspecting the Company property and returning one of two DataTemplate based on whether its equal to “Microsoft”.

public class PresenterTemplateSelector:DataTemplateSelector
{
    public DataTemplate RegularPresenter { get; set; }
    public DataTemplate MicrosoftPresenter { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        if(item is Presenter presenter)
        {
            return presenter.Company == "Microsoft" ? MicrosoftPresenter : RegularPresenter;
        }

        return base.SelectTemplateCore(item);
    }
}

In the following XAML I’ve defined two DataTemplates. The difference is that the MicrosoftPresenterItemTemplate uses a Microsoft Logo in place of the presenter’s avatar image.

<Page.Resources>
    <DataTemplate x:Key="PresenterItemTemplate"
                    x:DataType="local:Presenter">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Image Margin="8"
                    Source="{x:Bind AvatarUrl}" />
            <StackPanel Grid.Column="1"
                        VerticalAlignment="Center">
                <TextBlock Margin="0,0,0,4"
                            Text="{x:Bind Name}"
                            Style="{StaticResource TitleTextBlockStyle}" />
                <TextBlock Text="{x:Bind Company}"
                            Style="{StaticResource SubtitleTextBlockStyle}" />
            </StackPanel>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="MicrosoftPresenterItemTemplate"
                    x:DataType="local:Presenter">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Image Margin="8,32"
                    Source="http://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE2qVsJ?ver=3f74" />
            <StackPanel Grid.Column="1"
                        VerticalAlignment="Center">
                <TextBlock Margin="0,0,0,4"
                            Text="{x:Bind Name}"
                            Style="{StaticResource TitleTextBlockStyle}" />
                <TextBlock Text="{x:Bind Company}"
                            Style="{StaticResource SubtitleTextBlockStyle}" />
            </StackPanel>
        </Grid>
    </DataTemplate>
    <local:PresenterTemplateSelector x:Key="PresenterTemplateSelector"
                                        RegularPresenter="{StaticResource PresenterItemTemplate}"
                                        MicrosoftPresenter="{StaticResource MicrosoftPresenterItemTemplate}" />
</Page.Resources>


<Grid>
    <ListView ItemTemplateSelector="{StaticResource PresenterTemplateSelector}"
                ItemsSource="{x:Bind Presenters}" />
</Grid>

The two DataTemplates are specified as the RegularPresenter and MicrosoftPresenter properties on the PresenterTemplateSelector instance. Subsequently the PresenterTemplateSelector is set as the ItemTemplateSelector on the ListView. Running the application replaces the presenter’s avatar with a Microsoft logo for when the presenter has Microsoft as their Company.

Modifying Selection, Focus and PointerOver (Hover) Style using an ItemContainerStyle

We’ve seen a number of ways to adjust the layout for each element in the ListView. However, despite the variations in layout, when you move the mouse over an item, or click on an item to select it, the change in appearance is always the same. This is because the border that you see when an item is selected, or the gray background when you move the mouse over an item, are controlled by the ItemContainerStyle for the ListView.

You can think of the ItemContainerStyle as being a wrapper around each element in the ListView. It can be used to add borders, background or margin to every item in the ListView. The ItemContainerStyle also has a number of visual states which can be used to adjust the appearance of the item based on how the user is interacting with it.

Default Styles in Generic.xaml

The ItemContainerStyle is moderately complex, so unless you’ve spent a bit of time working with the ListView, I would recommend using one of the defaults as a starting point. The defaults are all listed in the generic.xaml file which can be located at C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.18362.0\Generic (or similar) folder on your computer.

As its name suggests, the ItemContainerStyle is indeed a Style. It is used to style each ListViewItem that is displayed within a ListView. In order to find the default ItemContainerStyle we need to look through the generic.xaml for a Style that has a TargetType of ListViewItem but has no Key set (hence making it the implicit style for all ListViewItme). In the following XAML, taken from generic.xaml, we can see that the Style is based on another explicit Style, ListViewItemRevealStyle.

<Style TargetType="ListViewItem" BasedOn="{StaticResource ListViewItemRevealStyle}" />

In Blend we can use the Apply Resource option to explicitly set the ItemContainerStyle to be the ListViewItemRevealStyle.

Custom ItemContainerStyle

Once we’ve set the ItemContainerStyle of our ListView to be the ListViewItemRevealStyle we can then use the Edit a Copy option to take a copy of the ListViewItemRevealStyle that we can make changes to.

The new Style needs a name and can be added to the current page.

Once the new Style has been added to the page, it immediately gets focus in the Objects and Timeline view. With the ItemContainerStyle in focus, you can then make changes in the Properties window. Any changes will be created as a Setter on the Style.

The following XAML is the copy of the ListViewItemRevealStyle that was copied in. There are three main parts to this Style:

  • Setters – for default values to be applied to the ListViewItem. Since each ListViewItem is generated on demand by the ListView, this is actually your opportunity to set properties directly on the ListViewItem.
  • ListViewItemPresenter – this element makes up the entire ControlTemplate for the ListViewItem. It encapsulates all the styling that you see by default around the ListViewItem and includes a large number of properties that can be adjusted to control the appearance of the ListViewItem. A lot of these properties are already set to a theme resource, making them easy to customise.
  • VisualStateGroups – these are visual states that define changes or transitions for the ListViewItem in different states. This Style only defines the CommonStates and EnabledStates VisualStateGroups as these include common states such as Selected and Pressed states which are the most likely states you’ll want to customise. If you do modify the Selected state, you’ll probably want to customise PointerOverSelected and PressedSelected for a consistent appearance when the user is interacting with the selected item.
<Style x:Key="CustomContainerStyle" TargetType="ListViewItem">
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
    <Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
    <Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
    <Setter Property="TabNavigation" Value="Local" />
    <Setter Property="IsHoldingEnabled" Value="True" />
    <Setter Property="Padding" Value="12,0,12,0" />
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
    <Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
    <Setter Property="AllowDrop" Value="False" />
    <Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
    <Setter Property="FocusVisualMargin" Value="0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
                <ListViewItemPresenter
                x:Name="Root"
                HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
                CheckBrush="{ThemeResource ListViewItemCheckBrush}"
                CheckMode="{ThemeResource ListViewItemCheckMode}"
                ContentMargin="{TemplateBinding Padding}"
                ContentTransitions="{TemplateBinding ContentTransitions}"
                Control.IsTemplateFocusTarget="True"
                DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
                DragBackground="{ThemeResource ListViewItemDragBackground}"
                DragForeground="{ThemeResource ListViewItemDragForeground}"
                DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
                FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
                FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
                FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
                PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
                PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
                PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
                PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
                ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
                RevealBackground="{ThemeResource ListViewItemRevealBackground}"
                RevealBorderBrush="{ThemeResource ListViewItemRevealBorderBrush}"
                RevealBorderThickness="{ThemeResource ListViewItemRevealBorderThemeThickness}"
                SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
                SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
                SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
                SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
                SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="Selected" />
                            <VisualState x:Name="PointerOver">
                                <VisualState.Setters>
                                    <Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
                                    <Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="PointerOverSelected">
                                <VisualState.Setters>
                                    <Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
                                    <Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="PointerOverPressed">
                                <VisualState.Setters>
                                    <Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
                                    <Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <VisualState.Setters>
                                    <Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
                                    <Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="PressedSelected">
                                <VisualState.Setters>
                                    <Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
                                    <Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="DisabledStates">
                            <VisualState x:Name="Enabled" />
                            <VisualState x:Name="Disabled">
                                <VisualState.Setters>
                                    <Setter Target="Root.RevealBorderThickness" Value="0" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </ListViewItemPresenter>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The ListViewItemPresenter is the single element that makes up the ControlTemplate. It is responsible for hosting the ItemTemplate and does infact inherit from ContentPresenter. However, unlike the ContentPresenter which is a basic content host, the ListViewItemPresenter implements standard ListView behaviour such as selection borders and changing the background when you hover over the item etc.

Overriding a ThemeResource to Customise the ListViewItemPresenter

A lot of the behaviour of the ListViewItemPresenter is configurable on the ListViewItemPresenterOr by simply adjusting its properties in the ControlTemplate. Furthermore, a good percentage of these properties are already specified in the ControlTemplate using either a ThemeResource or via a TemplateBinding.

For example take the PointerOverBackground property, which determines the background colour of the ListViewItem when the mouse hovers over it. By default the PointerOverBackground property uses the ListViewItemBackgroundPointerOver theme resource.

<ListViewItemPresenter
    x:Name="Root" ...
    PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}" />

One way to change the PointerOverBackground property is to set it directly on the ListViewItemPresenter.

<ListViewItemPresenter
    x:Name="Root" ...
    PointerOverBackground="Red" />

Alternatively, I can leave the PointerOverBackground set to the ListViewItemBackgroundPointerOver theme resource. I can then override the default value of the ListViewItemBackgroundPointerOver resource. If adjusting properties on the ListViewItemPresenter is the only reason to override the default Style, you can do this by simply defining the matching static resource.

<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver">Red</SolidColorBrush>

ListViewItemPresenter Properties that have a TemplateBinding

There’s a bit of inconsistency with how the properties on the ListViewItemPresenter are specified. As we’ve seen with the PointerOverBackground property, some properties are set using a theme resource. However, there are other properties that are set using a template binding. For example, the HorizontalContentAlignment property is set using a TemplateBinding.

<ListViewItemPresenter
    x:Name="Root" ...
    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />

This means that instead of overriding a theme resource, instead we have to look above the ContentTemplate to the Setters defined in the Style for the ListViewItem. In this case the HorizontalContentAlignment property is set to Left.

<Style x:Key="CustomContainerStyle" TargetType="ListViewItem">
    ...
    <Setter Property="HorizontalContentAlignment" Value="Left" />

If you’re not familiar with the HorizontalContentAlignment property it’s used to define how the contents of a ContentPresenter is aligned and sized. With the default value of Left, the content of the ListViewItem will be positioned adjacent to the left edge. Even if you specify the HorizontalAlignment to be Center or Stretch on the first element of the ItemTemplate, the contents will still be aligned to the left. This is a common issue that developers run into when using the ListView and is easily fixed by setting the HorizontalContentAlignment to Stretch.

Visual States on the ListViewItemPresenter

The ListViewItemPresenter encapsulates a lot of behaviour associated with how the ListViewItem is styled. However, in the ControlTemplate for the ListViewItem you can see that there are some visual states defined within the ListViewItemPresenter. These visual states can be used to further customise the appearance of the ListViewItem based on the state of the item in the list.

In the default Style for the ListViewItem, which we copied into our project earlier, there are two VisualStateGroups defined: CommonStates and DisabledStates. From an initial inspection this would appear to cover most states that you can imagine a ListViewItem would be in, such as Normal, Pressed, PointerOver, Enabled etc. However, there is a set of visual states that haven’t been defined here which is common to a lot of XAML element. The FocusStates group is typically made up of Focused and Unfocused states. As you can imagine, these define the changes to the appearance when an element gets or loses focus.

I’m going to adjust the ListViewItemPresenter to shrink the ListViewItem when it gets focus. I’ll do this by applying a render transform to reduce the ScaleX and ScaleY properties to 0.8. Before I can add the visual states, I first need to make sure that there is a render transform object that I can manipulate. In this case I’m going to use a CompositeTransform as this gives me the most flexibility to apply any render transform, not just a scale transform.

<ListViewItemPresenter
    x:Name="Root" ...
    RenderTransformOrigin="0.5,0.5">
        <ListViewItemPresenter.RenderTransform>
            <CompositeTransform x:Name="CustomTransform"/>
        </ListViewItemPresenter.RenderTransform>

Next I’m going to add a new VisualStateGroup to the ListViewItemPresenter. In this group I’ve defined two visual states. The Unfocused state doesn’t have any properties set, whereas the Focused state sets the ScaleX and ScaleY properties.

<ListViewItemPresenter
    x:Name="Root" ... >
        <VisualStateManager.VisualStateGroups>
            ...
            <VisualStateGroup x:Name="FocusStates">
                <VisualState x:Name="Focused">
                    <VisualState.Setters>
                        <Setter Target="CustomTransform.ScaleX" Value="0.8" />
                        <Setter Target="CustomTransform.ScaleY" Value="0.8" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Unfocused" />
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </ListViewItemPresenter>

In order to see the impact of this I’ve set the SelectionMode on the ListView to Extended. This defines how many items can be selected, and how the ListView allows items to be selected. The Extended value means that on Windows you can hold down the Ctrl key whilst using the up and down arrow keys to move the focus between items without selecting them.

The changes we’ve applied to the ListViewItemPresenter (that you can see in the following image) are:

  • We’ve overridden the default value of the ListViewItemBackgroundPointerOver to set it to Red
  • We’ve applied a scale transform when an item is in the Focused state.

In the following image you can see three complete items that are in different states:

  • Selected – the first item in the list has been selected, which is highlighted by the green background
  • PointerOver – when the screenshot was taken the mouse pointer was hovering over the second item, hence the Red background thanks to the ListViewItemBackgroundPointerOver resource.
  • Focused – the keyboard has been used to move focus to the third item by holding the Ctrl key and using the arrow keys. The Focused visual state causes the item to be scaled down to 80%.

Expanded Style for ListViewItem

In the previous sections we’ve been working with a copy of the default Style for the ListViewItem. However, if you take a look in the generic.xaml file, you’ll see that there is another Style for the ListViewItem called ListViewItemExpanded. When building for Windows 8/8.1 this expanded Style used to be the default, before the introduction of the ListViewItemPresenter. The ListViewItemExpanded Style goes on for almost 500 lines in order to explicitly define similar behaviour to the ListViewItemPresenter. Unless you really can’t get the ListViewItemPresenter to do what you need, I would avoid attempting to extend the ListViewItemExpanded Style.

So now that I’ve warned you about the complexity of the ListViewItemExpanded Style, it does bode the question as to why I mentioned it. For a couple of reasons: Firstly, it’s important to know that this Style exists and where to find it, in case you really want to dig in and customise the ListViewItem. The second reason is so that I can point out that in place of the ListViewItemPresenter, the ListViewItemExpanded Style uses a vanilla ContentPresenter to host each item in the ListView.

Minimal Style for ListViewItem

Occasionally you may want to do away with all the visual enhancements that you get out of the box with the ListView. This may be to squeeze that last little bit of performance out of the ListView (often required on Xbox where memory management is abysmal), or it may be that you don’t want all the hover effects, or the animations when items are selected or add/removed from the ListView. As mentioned in the previous section where we discussed the ListViewItemExpanded Style, the key to hosting items in the ListView is the ContentPresenter. Thus, it’s easy for us to create a bare minimum Style that doesn’t do anything other than host the items in the ListView.

<Style x:Key="MinimalContainerStyle" TargetType="ListViewItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
                <ContentPresenter x:Name="ContentPresenter"
                    Grid.Column="1"
                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                    ContentTemplate="{TemplateBinding ContentTemplate}"
                    Content="{TemplateBinding Content}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

As you can see from the following image there’s no additional padding or margin, and there’s no selection, focus or mouse over states.

Note: If you get to the point where you strip out all the layout, animation and other behaviour from the ListViewItem (such as in the MinimalContainerSylte above), you should consider using an ItemsControl instead of the ListView. You can think of the ItemsControl as a raw repeater that allows you to data bind a collection of elements in order to have them presented in a list on the screen. However, it doesn’t support selection and other interactivity features that the ListView has.

ItemsPanel

So far we’ve looked at templates that govern how each item in the ListView appear. The ItemsPanel property on the ListView accepts an ItemsPanelTemplat which defines how items are placed relative to each other. For example the default ItemsPanelTemplate that is specified on the ListView template uses an ItemsStackPanel to efficiently layout items in a vertical stack

<ItemsPanelTemplate>
    <ItemsStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>

What’s interesting is that you can easily switch between laying items out in a vertical list, to having them presented horizontally, by changing the Orientation to Horizontal on the ItemsStackPanel. You will also have to adjust the default Setters on the ListView template to enable horizontal scrolling and disable vertical scrolling.

Most XAML developers will be familiar with a regular StackPanel that’s used to present items in either a vertical or horizontal list. The ItemsStackPanel is similar in that it presents items by stacking them. However, it has been specifically designed for use with a ListView, GridView or even an ItemsControl. It is capable of virtualising the items in the ListView making it particularly efficient for large lists.

It is worth pointing out that virtualisation isn’t always a good thing. If you have a small number of items in the list, you may get a better experience by disabling virtualisation. Using a regular StackPanel instead of an ItemsStackPanel will prevent any virtualisation meaning that scrolling won’t have any ghost cells (cells where the contents haven’t completely rendered). However, be aware that as the number of items increases, so will both the load time and the memory usage.

GridView v ListView

Whilst on the topic of the ItemsPanel property, it’s worth looking at the default value for the GridView. Instead of using an ItemsStackPanel, the GridView uses an ItemsWrapGrid, allowing items to wrap in either a horizontal or vertical direction.

Both the GridView and ListView inherit from the ListViewBase class. If you inspect the default Style for both GridView and ListView you’ll see that the main variations are in the direction of scrolling and the ItemsPanel. As an experiment to see how well you understand the various templates, try converting a GridView into a ListView and vice versa – you can do this just by adjusting the attributes of the various templates.

Header and Footer Templates

We’re getting towards the end of the templates for the ListView but I’d be remiss if I didn’t point out the Header and Footer templates. One basic usage for these is to add space to the beginning or the end of the list of items. However, if you just want to do this, you may want to consider just adding a margin to the ItemsStackPanel in the ItemsPanel.

The header and footers of a ListView are pairs of properties. There are a Header and HeaderTemplate properties, and there are Footer and FooterTemplate properties. These work very similar to Content and ContentTemplate properties on a ContentControl. The Header and Footer represent the data that you want to display. Then of course the HeaderTemplate and FooterTemplate define the template for that data.

<ListView ...
    Header="This is the header">
    <ListView.HeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" Style="{StaticResource TitleTextBlockStyle}"/>
        </DataTemplate>
    </ListView.HeaderTemplate>
</ListView>

The following image illustrates the Header being applied via the HeaderTemplate as the beginning of the ListView. In this case I’ve added a Margin of 50 to the top of the ItemsStackPanel, which as you can see appears after the Header but before the list of items.

ListView Template

So the last template I’m going to cover in this post is of course the template for the ListView itself. If you look in the generic.xaml file you’ll find implicit styles for both the ListView and the GridView. The default styles define things like the transitions to be applied to items (i.e. the ItemContainerTransitions), the ItemsPanel (i.e. ItemsStackPanel for ListView, ItemsWrapGrid for GridView) and of course the ControlTemplate for the ListView and GridView themselves.

The ControlTemplate for both ListView and GridView are relatively simple and are made up of a Border, a nested ScrollViewer and a nested ItemsPresenter.

Scroll Events

A scenario that comes up from time to time is that you want to trigger some behaviour based upon the ListView being scrolled. This might be the first time its scrolled, or perhaps it’s when the scrolling gets to a certain point. Either way, you can easily attach an event to the ScrollViewer that’s part of the ControlTemplate for the ListView.

Templates for ListView and GridView

In this post we’ve walked through a variety of different ways you can customise the appearance of the ListView and GridView controls. There are templates for controlling how items appear and their behaviour, and there are templates for styling the ListView and GridView themselves.

One set of templates we didn’t touch on in this post are those that are used when grouping data. Whilst grouped data typically uses the ItemTemplate to render each item in the list, there are separate templates for the group header and footers. We’ll leave the topic of working with grouped data for another post.

XAML Control Templates for Windows (UWP) and Platform.Uno

Recently there has been a lot of discussion about using code to declare the user interface of an app. Such as a recent post I did following the announcement of SwiftUI by Apple. In the Xamarin.Forms world the hashtag CSharpForMarkup has become the latest distraction. CSharpForMarkup encourages developers to move away from XAML to defining their layouts using C#. Whilst I’m not against this, I do feel that we’re all discussing the wrong problem. Whether you use code or XAML to define your layouts, Xamarin.Forms suffers from being tied to the underlying platform controls. Renderers, Effects and Visual are all mechanisms to compensate for not having XAML control templates for every control (more on templates).

Enter Platform.Uno and their mission to take the XAML framework from Windows (UWP) and adapt it to other platforms. As an alternative for building apps for iOS and Android, Platform Uno was moderately interesting. With their push to support WebAssembly, Platform.Uno opens up a world of opportunities for building rich applications for the web. Their recent example of publishing the Windows calculator to the web (https://calculator.platform.uno) is just the the start for this technology.

In this post we’ll walk through how the XAML templating system works and how to go about defining a Control Template to customise the behaviour of controls.

Note: In this post I’ll be using XAML so that I can use Blend to assist with writing XAML. You can choose to use C# if you prefer defining your layouts in code. The point of this post is to highlight the templating capabilities of UWP and Platform.Uno.

Lookless or Templated Controls

One of the foundations of XAML was the notion of a templated, or lookless, control. In his post “What does it mean to be ‘lookless’?” Dave observes that a lookless control is one where the UI is declared in XAML and the behaviour or functionality of the control is defined in code. My view is that a lookless control is one where the functionality of the control isn’t tied to a specific design. By this I mean that each aspect of the control should be defined using a template, thus making it a templated control. A developer using the control should be able to adjust any of the templates without affecting the functionality of the control.

What is a Button?

Let’s look at what this means in practice by examining a Button. If I asked you what you thought a Button in UWP is, you’d probably answer by writing the following element:

<Button Content="Press Me!" />

All you’ve done is declared a Button with content that says “Press Me!” that uses the default Button styles. You haven’t actually answered the question. So let’s start with a simple definition of a button.

A Button is an element that responds to the user tapping or clicking by performing some action.

However, in the context of UWP where a Button is an actual control, this definition is a little too vague. For example, the following Border/TextBlock combination matches the definition

<Border Background="Gray" Tapped="PressMeTapped">
    <TextBlock Text="Press Me!"/>
</Border>

Tapping on the Border does invoke the PressMeTapped event handler but is that all we mean when we say a Button. I would argue that one of the significant aspects to a Button is that it gives some visual cues to the user. By this I mean that when the user hovers their mouse over a button they can the mouse pointer changes, or the Button adjusts how it looks. Similarly, when the user taps or clicks on the Button they should get some visual feedback confirming their action. This feedback is what separates a Button from just simply a tap or click event handler that can be attached to any element.

What we’ve just observed is that the Button has a number of different visual states. In the context of a UWP button these are the Normal, PointerOver and Pressed states. Using the default Button style in the Light theme, these states are shown in the following image.

States in the Control Template for the UWP Button
UWP Button States

As part of extending our definition of a Button I was careful not to define what feedback, or change to layout, should be used for each state of the Button. UWP ships with Dark and Light themes and a set of default control styles that combine to give you the states shown above. However, the important thing to remember is that the visual appearance isn’t what defines a Button. Perhaps an updated definition might be something like:

A Button is an element that responds to the user tapping or clicking by performing some action. It has Normal, PointerOver, Pressed and Disabled visual states that can provide feedback and guide the user on how to interact with the control.

Content v Text Properties

Xamarin.Forms deviates from most other XAML platforms when it comes to defining elements and attributes. For example, instead of using a StackPanel, Xamarin.Forms has a StackLayout. Not only are they named differently, they also exhibit different behaviour. Similarly, the Button control has a Text property instead of a Content property. Whilst this might seem like a decision to simplify the Button control it highlights the limitation of Xamarin.Forms due to the lack of templating.

Let’s back up for a second and take a look at the Content property. In a lot of cases you might simply set the Content attribute to a string, such as the earlier example where I set the Content to “Press Me!”. However, to override the styling of the text, or add other content to the Button, I can set the Content property explicitly.

<Button>
    <StackPanel>
        <TextBlock Style="{StaticResource HeaderTextBlockStyle}"
                   Text="Press Me!" />
        <TextBlock Style="{StaticResource BodyTextBlockStyle}"
                   Text="or.... perhaps not" />
    </StackPanel>
</Button>

Note: As the Content property on the Button is annotated with the ContentPropertyAttribute, we don’t need to wrap the StackPanel in Button.Content tags.

Even though I’ve changed the content of the Button, I haven’t in anyway changed the way the Button functions. In fact, in this case I haven’t even changed how the Button changes appearance for the different states.

Using a Content Template

Before we get into customising the different Button states I just wanted to touch on the use of content templates. In the previous example I showed how the Content of the Button could be set to any arbitrary XAML. What happens if I want to reuse the content layout but just with different text? This is where the ContentTemplate property is useful.

The ContentTemplate property expects a DataTemplate which will be used to define the layout for the Content. At runtime the DataContext of the ContentTemplate will be set to the value of the Content property. Let’s see this in practice by moving the XAML from the Content property into the ContentTemplate.

<Button>
  <Button.Content>
    <local:ButtonData Heading="Press Me!" SubText="or.... perhaps not" />
  </Button.Content>
  <Button.ContentTemplate>
    <DataTemplate>
      <StackPanel>
        <TextBlock Style="{StaticResource HeaderTextBlockStyle}"
                   Text="{Binding Heading}" />
        <TextBlock Style="{StaticResource BodyTextBlockStyle}"
                   Text="{Binding SubText}" />
      </StackPanel>
    </DataTemplate>
  </Button.ContentTemplate>
</Button>

In this code block you can see that the Content property has been set to a new instance of the ButtonData class. The two TextBlock elements are subsequently data bound to the Heading and SubText properties.

public class ButtonData
{
    public string Heading { get; set; }

    public string SubText { get; set; }
}

What this shows is that we’ve separated the data (i.e. the instance of the ButtonData class) from the presentation (i.e. the DataTemplate that is specified for the ContentTemplate property). Now if we wanted to reuse the DataTemplate across multiple elements we can extract it as a StaticResource. The following code illustrates extracting the DataTemplate to a StaticResource, as well as updating the data binding syntax. The x:Bind syntax gives us strongly typed data binding. Meaning we get intellisense and better runtime performance as there are no reflection calls. Button1 and Button2 are properties on the page that return instances of the ButtonData class.

<Page.Resources>
    <DataTemplate x:Key="MyButtonTemplate"
                  x:DataType="local:ButtonData">
        <StackPanel>
            <TextBlock Style="{StaticResource HeaderTextBlockStyle}"
                       Text="{x:Bind Heading}" />
            <TextBlock Style="{StaticResource BodyTextBlockStyle}"
                       Text="{x:Bind SubText}" />
        </StackPanel>
    </DataTemplate>
</Page.Resources>
<Button Content="{x:Bind Button1}"
        ContentTemplate="{StaticResource MyButtonTemplate}" />
<Button Content="{x:Bind Button2}"
        ContentTemplate="{StaticResource MyButtonTemplate}" />

Custom Control Templates

So far we’ve seen how the Button control supports arbitrary Content and the use of ContentTemplates to reuse layouts across multiple controls. Neither of these can be used to adjust the visual appearance of the different Button states. In this section we’re going to start by looking at what properties you can adjust to tweak the existing states. We’ll then bust out Blend and start messing with the way a Button looks. All of this will be done without changing the functionality of the Button.

ThemeResources in the Control Template

In the previous section I added some arbitrary XAML to the Content of the Button. However, when I run the application I still see the default background gray. The background of the Button control is part of the default Template for the control. We’ll delve into this in a little more detail in the next sections. For the time being we’re going to adjust the colour of the background and round the corners on the border.

Adjusting the background of the Button when it’s in the Normal state can be done two ways. You can either specify the Background on the Button element itself, or you can override the ButtonBackground resource with the colour of your choosing.

<Page.Resources>
    <Color x:Key="ButtonBackground">DarkGreen</Color>
</Page.Resources>

<Button Content="{x:Bind Button1}"
        Background="Blue"
        ContentTemplate="{StaticResource MyButtonTemplate}" />
<Button Width="200"
        Height="200"
        HorizontalAlignment="Center"
        Content="{x:Bind Button2}"
        ContentTemplate="{StaticResource MyButtonTemplate}" />

At this point if you run the application up on UWP you’ll see that the initial colours for the two Button elements are blue and dark green respectivey. However, if you move the mouse over each of them you’ll see that they switch back to a grey background. This is because we’ve only adjusted the colour used to set the initial background colour. To adjust the colour for the PointerOver and Pressed states we need to adjust the appropriate resources, which are aptly called ButtonBackgroundPressed and ButtonBackgroundPressed. A full list of the overridable colours is available in the documentation for the Button control. Alternatively you can find the entire list of built in color resources in the ThemeResources.xaml file (more information here).

Button Colors in ThemeResources.xaml

In addition to changing the background colour, we also wanted to round the corners of the border that appears around the control when the user moves the mouse in closer. This can be done by simply setting the CornerRadius property to 10 on the Button element.

When we get to talking about visual states we’ll go through how properties on the Button control are modified with each visual state.

Changing the Control Template Layout

Sometimes it’s necessary to make changes that can’t be achieved by either setting the ContentTemplate or overriding the default colour resources. For example, say you wanted to add the Built to Roam logo as a watermark behind the content of the Button. To do this we need to override the Template for the Button. For this I’m going to use Blend as it’s particularly good at edit templates.

To begin editing the control template, locate the Button in the Objects and Timelines window. Right-click on the [Button] and select Edit Template, followed by Edit a Copy.

Editing a Copy of the Default Button Template

Next, you’ll be prompted to give the new template a name and specify where you want the template to be defined. When the new template is created it will include the default Button Template, thus allowing you to customise it. In this case the WatermarkButtonTemplate will be defined in the current document, limiting its availability to just the Button elements on the page.

Naming the New Control Template

Note: In this example we’re copying the default Button template. However, what gets copied into the XAML is actually the entire default Button style. This includes all the default property setters. The value of the Template property is set to a new instance of a ControlTemplate.

I’m not going to go through the changes to the template in detail but the summary is:

  • Wrap the ContentPresenter in a Grid called ContentFrame
  • Move Background, BackgroundSizing, BorderBrush, BorderThickness and CornerRadius from the ContentPresenter to ContentFrame
  • Adjust Visual States so that they reference ContentFrame for border and background properties. Leave any references to Foreground targetting the ContentPresenter element.
  • Add an Image inside the Grid with Source set to an image added to the Assets folder.
  • Set Opacity to 20% (0.2) and Stretch to Uniform on the Image.

Before:

<ControlTemplate TargetType="Button">
    <ContentPresenter
        x:Name="ContentPresenter"
        Padding="{TemplateBinding Padding}"
        HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
        AutomationProperties.AccessibilityView="Raw"
        Background="{TemplateBinding Background}"
        BackgroundSizing="{TemplateBinding BackgroundSizing}"
        BorderBrush="{TemplateBinding BorderBrush}"
        BorderThickness="{TemplateBinding BorderThickness}"
        Content="{TemplateBinding Content}"
        ContentTemplate="{TemplateBinding ContentTemplate}"
        ContentTransitions="{TemplateBinding ContentTransitions}"
        CornerRadius="{TemplateBinding CornerRadius}">
        <VisualStateManager.VisualStateGroups>                
        ...
        </VisualStateManager.VisualStateGroups>
    </ContentPresenter>
</ControlTemplate>

After:

<ControlTemplate TargetType="Button">
    <Grid
        x:Name="ContentFrame"
        Padding="{TemplateBinding Padding}"
        Background="{TemplateBinding Background}"
        BackgroundSizing="{TemplateBinding BackgroundSizing}"
        BorderBrush="{TemplateBinding BorderBrush}"
        BorderThickness="{TemplateBinding BorderThickness}"
        CornerRadius="{TemplateBinding CornerRadius}">
        <Image
            Opacity="0.2"
            Source="Assets/BuiltToRoamLogo.png"
            Stretch="Uniform" />
        <ContentPresenter
            x:Name="ContentPresenter"
            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
            AutomationProperties.AccessibilityView="Raw"
            Content="{TemplateBinding Content}"
            ContentTemplate="{TemplateBinding ContentTemplate}"
            ContentTransitions="{TemplateBinding ContentTransitions}"
            FontFamily="Segoe UI" />
        <VisualStateManager.VisualStateGroups>
        ...
        </VisualStateManager.VisualStateGroups>
    </Grid>
</ControlTemplate>

The net result is that the image is displayed on top of the background colour (which is set on the parent Grid) but beneath the content.

The important thing about defining this ControlTemplate is that it can be reused on any Button, irrespective of the Content that is being displayed. Again, these changes have affected the design of the Button but we still haven’t modified what happens when the user interacts with the Button.

Tweaking Control Template Visual States

The last set of changes we’re going to look at is how we modify the behaviour of the Button when the user does interact with it. In this case we’re going to look at the Pressed state. We’re going to change the default behaviour to slightly enlarge the Button when it’s in the Pressed state. To do this we need to modify the Pressed VisualState that is defined inside the ControlTemplate.

Using Blend we’ll step through adjusting the Pressed Visual State to expand the Button to 150% of it’s original size (i.e. a scale of 1.5 in both X and Y directions). To get started in the Objects and Timeline window, right click the Button element and select Edit Template, then Edit Current. This is similar to what we did previously but this time we already have a ControlTemplate in the XAML for the page.

Edit an Existing Control Template

Next, from the States window, select the Pressed state. If you click where the word Pressed is written you should see both the focus border around the Pressed state and a red dot appear alongside, indicating that Blend is in recording mode. You should also see a red border appear around the main design surface. If you look at the Button on the design surface it should appear like it’s been Pressed to illustrate what the Pressed state looks like.

Switching to the Pressed state

In the Properties window, locate the Transform section. Select the third icon in, which is for adjusting the Scale of the element. Set both X and Y values to 1.5. You should see a white square alongside each of the values indicating that you’ve explicitly set the value.

Adjusting the Scale Transform for X and Y

If you go back to the Objects and Timeline window you should see that under the ContentFrame there are entries for RenderTransform/ScaleX and RenderTransform/ScaleY to indicate that these properties have been modified for the currently selected visual state.

Visual State Properties

If you run the application now and click on the Button you should see that whilst the mouse button is depressed the Button moves to the Pressed state which shows the Button enlarged.

Enlarged Pressed State for Button

If you examine the change to the XAML, what you’ll see is that two Setters were added to the Pressed Visual State.

<VisualState x:Name="Pressed">
    <VisualState.Setters>
        <Setter Target="ContentFrame.(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Value="1.5" />
        <Setter Target="ContentFrame.(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Value="1.5" />
    </VisualState.Setters>
    <Storyboard>
        ... other existing animations ...
    </Storyboard>
</VisualState>

Animating Content Template State Transitions

The change we just made to the Control Template was to change the Scale X and Scale Y properties for the Pressed state. However, this is rather a jarring experience as there’s no transition or animation defined. The final step in this process is to add a transition both too and from the Pressed state.

In the States window, click the arrow with a plus sign and select the first item (i.e. *=>Pressed) to add a transition that will be invoked whenever the Button goes to the Pressed state, regardless of the initial state.

Adding Transition into Pressed State

If you look in the Objects and Timeline window you can now see a timeline that will define what animations are run during the transition.

Start of the Transition Timeline

Over in the Properties window, locate the Transform section and click on the empty square alongside the X property. Select Convert to Local Value, which will set the value to 1. The square will now appear as a sold white square. Repeat for Scale Y

Setting the Start of the Transition

Back in the Objects and Timeline window you should now see a keyframe marker appear at time 0. Drag the vertical orange line to 0.5 seconds.

End of Transition in Timeline

Now in the Properties window set the Scale X and Scale Y to 1.5, which is the end values for the transition. Thisshould match the values previously set for the Pressed state.

End Transition Values

Repeat this process for a transition for leaving the Pressed state. The transition should be the reverse with the Scale X and Y starting at 1.5 and ending at 1.

Transitions In and Out of Pressed State

And there you have it, an animated Pressed state.

Animated Pressed State in Control Template

The final XAML for the Transitions includes two Storyboards that defines the transition to and from the Pressed state.

<VisualStateGroup.Transitions>
    <VisualTransition GeneratedDuration="00:00:00"
                      To="Pressed">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentFrame"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
                <EasingDoubleKeyFrame KeyTime="00:00:00"
                                      Value="1" />
                <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
                                      Value="1.5" />
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentFrame"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)">
                <EasingDoubleKeyFrame KeyTime="00:00:00"
                                      Value="1" />
                <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
                                      Value="1.5" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </VisualTransition>
    <VisualTransition GeneratedDuration="00:00:00"
                      From="Pressed">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentFrame"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)">
                <EasingDoubleKeyFrame KeyTime="00:00:00"
                                      Value="1.5" />
                <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
                                      Value="1" />
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ContentFrame"
                                           Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)">
                <EasingDoubleKeyFrame KeyTime="00:00:00"
                                      Value="1.5" />
                <EasingDoubleKeyFrame KeyTime="00:00:00.5000000"
                                      Value="1" />
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </VisualTransition>
</VisualStateGroup.Transitions>

As you can see from this walkthrough, the XAML templating system is relatively sophisticated. It allows for multiple levels of configuration or tweaking in order to get it looking just right.

In coming posts I’ll be talking more about what differentiates XAML and why it’s still being used across Windows, Xamarin.Forms and of course Platform Uno. If you’re looking for cross platform solutions, please don’t hesitate to contact me or anyone on the team at Built to Roam.

Decompilers for .NET and Windows (UWP) Apps

I think I’ve been living under a rock as I’ve only just come across dnSpy, a decompiler for .net!

I’ve been building apps and services with .NET for a long time, so a Twitter thread talking about decompilers amused me. David Kean’s comment pretty accurately reflects my sentiment regarding Reflector.

Reflector was such a simple tool and it just worked. That was until Red Gate took over and I can’t even remember what happened to it. Does it still exist?

The thread started with Jared commenting that developers should be using ilSpy instead of hacking with ildasm. I’ve rocked ilSpy in my toolkit for a while now and it’s always served me well. In fact I go so far as to set it as the default file handler for .dll files. After all, what other program are you going to want to launch when you double-click on a .dll file.

dnSpy: A Decompiler for .NET

What really knocked my socks off was that someone mentioned dnSpy which I’d never heard of. Thinking it was something similar to ilspy I didn’t think much of it but figured I would download it and take a look.

Next thing I knew it was like I had opened an entire development environment. The layout was familiar, all the way down to the Debug menu that allows me to attach to process.

What? come again? Attach to Process? Yes, that’s right you can attach to a running process, set breakpoints and intercept exceptions (and I’m sure a whole bunch more things. Ironically whilst I was attempting to modify an image of dnspy running, Paint.NET crashed on me. Whilst Paint.NET was hung, I was able to attach to the process using dnspy and see that it was stuck waiting for a print dialog to return.

dnSpy: a Decompiler for .NET

If you’re using ilspy, you should check out dnspy

For anyone still using ildasm, you should check out ilspy and dnspy

Developers not using a decompiler, what have you been doing? Get yourself a decompiler for .NET, and use either ilspy or dnspy.


Nick Randolph @thenickrandolph
If you need help debugging your application, contact Built to Roam


Fiddler Debugging Http/Https Traffic for Xamarin iOS, Android and Windows (UWP) Applications

Debugging Http/Https Traffic using Fiddler for Xamarin iOS, Android and Windows (UWP) Applications

One of the most frustrating things as a frontend developer is when you are receiving incorrect data. You don’t know whether the problem lies with your application, or the backend services. The easiest way to validate this is to pretend to be a hacker. You can stage a man-in-the-middle attack on your own application. Debugging using tools like Fiddler or Charles can be used to inspect the traffic from your application. Unfortunately, the same effort that goes into protecting apps from such attacks, also means that it is harder for developers to setup Fiddler debugging.

In this post I’ll walk through setting up Fiddler debugging for a Xamarin.Forms application. The same basic approach will work for a native or Xamarin iOS/Android application as well. For this post I’ve created an application using the Blank Xamarin.Forms template that comes with Visual Studio 2019. I’ve selected to target all three platforms.

In the OnAppearing method in the MainPage of the Xamarin.Forms application, I’ve added some basic code to retrieve a string for a Https endpoint. We’ll use a Https endpoint on the assumption that if we can intercept Https then we can also intercept Http traffic.

protected override async void OnAppearing()
{
     base.OnAppearing();
     var client = new HttpClient();
     var users = await client.GetStringAsync("https://reqres.in/api/users?page=0");
     Debug.WriteLine(users);
}

Setting Up Fiddler Debugging

Before we get started with the individual platforms, it’s worth checking your configuration for Fiddler:

  • You need to make sure you have setup Https traffic decryption. I’m not going to repeat the documentation, so check out how to Configure Fiddler to Decrypt HTTPS Traffic.
  • You’ll also need to setup Fiddler debugging for remote traffic. This can be done by opening the Options window. Under the Connections tab, make sure the “Allow remote computers to connect” checkbox is checked. If you’re running Skype, or some other communication tools, it may have jumped onto the default port configured in Fiddler. In this case you can adjust the “Fiddler listens on port”.
Fiddler Debugging Options Window
Enabling remote connection in Fiddler

Windows (UWP)

I’ll start with Windows, because it’s relatively straight forward to get setup. With Fiddler running, you can run the UWP project from within Visual Studio and Fiddler debugging will work. Fiddler will capture the Https traffic without any further configuration or setup.

Fiddler Debugging
Capturing network traffic in Fiddler

In some cases, you need to make sure your application is added to the exemption list, so that traffic can be routed to the local machine. For more information see the blog post Revisiting Fiddler and Win8+ Immersive applications. To check this, click the WinConfig button in the top left corner of the Fiddler interface.

WinConfig
Click WinConfig to adjust the exemption list for Windows 10 apps

Locate your application and confirm that there is a check in the box next to your application. If it’s not checked, check the box, and then click Save Changes

Exemption Utility
Locate your UWP application and check the box to add your application to exemption list

One other issue I’ve seen but can’t reproduce reliably, is that sometimes when you run your application from Visual Studio it unchecks the box in the WinConfig in Fiddler. If for some reason you no longer see traffic in Fiddler for your application, go back and double check the exemption list in Fiddler.

Diagnosing Issues with Fiddler on Windows

When configuring Https traffic decryption, you’ll be prompted to install and trust the Fiddler root certificate. If you don’t accept all the prompts, Fiddler debugging for Windows applications will not work. Windows traffic debugging works without any further configuration because the Fiddler root certificate is trusted on the machine running Fiddler.

If you’re attempting to run the Windows application on a different machine than the one running Fiddler, you’ll need to install and trust the Fiddler root certificate. This is in addition to setting the remote machine as a proxy, which is a topic for another post. Navigate to http://[ipaddress]:[port] where [ipaddress] is the ip address of the machine running Fiddler and the [port] is the port number that Fiddler is listening on. Do NOT use https as this site is http only. You should see a screen similar to the following image – if you don’t, make sure you check that Fiddler is running!!

Fiddler Debugging Echo Service
Click on the FiddlerRoot certificate to install the root certificate

Click on the FiddlerRoot Certificate and install as a Trusted Certificate Authority on the Local Machine. This should allow your Windows application to trust Fiddler.

iOS Fiddler Debugging

Next up is iOS and in this case we’re going to use the iOS simulator. The same process should work with any iOS device that’s on the same local network as the machine running Fiddler. There are two steps to setup iOS for traffic debugging:

  1. Trust the Fiddler root certificate, and
  2. Set the http proxy to use the machine running Fiddler.

To setup the simulator, first launch the iOS application from Visual Studio. If you’re on Windows, this will launch the remote viewer for the simulator. Once the simulator is running, stop debugging and we’ll setup the simulator for traffic debugging.

Trusting the Fiddler Certificate

Navigate to http:[ipaddress]:[port] (eg http://192.168.1.109:8888) to load the Fiddler echo page. Then click on the Fiddler Certificate link. Follow the prompts to download and install the certificate.

Fiddler Echo Service iPhone Download Certificate iPhone Download Profile iPhone

In addition to downloading the certificate you also need to install it. Go to Settings / General / Profile and click through on the FiddlerRoot profile in order to Install it.

image image image image image image image

The Fiddler root certificate needs to be trusted as a root certificate. Go to Settings / About / Certificate Trust Settings and toggle the switch next to the FiddlerRoot certificate. Fiddler generates a certificate for each site you go to that is derived from the root certificate, so the root certificate needs to be installed as a trusted certificate.

image image image image

The only difference between a real iOS device and the simulator is that on a real iOS device you can set a network proxy. There are online tutorials, such as this one, for instructions on setting a proxy. Unfortunately, setting up a proxy this isn’t configurable on the simulator. If you want to use a proxy in the simulator, you can set the proxy on the mac running the simulator but this would affect all traffic on the mac. Alternatively, when running on the simulator, we can adjust the HttpClient to use a WebProxy using the following code:

var handler = new HttpClientHandler();
handler.Proxy = new WebProxy("192.168.1.109", 8888);
var client = new HttpClient(handler);

Running the iOS application should show network traffic in Fiddler debugging window. You should still see the returned data printed out in the Output window (ie from the Debug.WriteLine statement).

Android Fiddler Debugging

For Android I’m going to use the Android Simulator. Real devices should behave similarly, assuming they’re connected to the same local network as the machine running Fiddler.

Unlike iOS, that will use any proxy configured for the device, for Android you need to explicitly opt in to use a proxy in your code. You’ll need to use code similar to the following on both emulator and real devices:

var handler = new HttpClientHandler();
handler.Proxy = new WebProxy("192.168.1.109", 8888);
var client = new HttpClient(handler);

What’s a little scary about this code is that it “just works”. You might be thinking that this is a good thing. However, it does raise the question of how much of the system security model does the Microsoft built HttpClientHandler respect. What I would have expected is an SSL fail exception because the Fiddler root certificate isn’t trusted by the emulator. Furthermore, the application is not configured to use any user certificates.

The other thing to point out here is that you should not be using the HttpClientHandler. I’ve discussed this in my previous post on working with the HttpClient. Let’s change our code by moving it into the OnCreate method of the Android head project. We’ll also change over to using the AndroidClientHandler.

protected override async void OnCreate(Bundle savedInstanceState)
{
     ...
     var handler = new AndroidClientHandler();
     handler.Proxy = new WebProxy("192.168.1.109", 8888);
     var client = new HttpClient(handler);
     var users = await client.GetStringAsync("https://reqres.in/api/users?page=0");
     System.Diagnostics.Debug.WriteLine(users);
}

When we run the application we see the very familiar SSL handshake exception being raised, which is what we should expect. To get things to work, we now need to install the Fiddler certificate and configure the application to use user certificates.

Install the Fiddler Root Certificate

To install the Fiddler root certificate, navigate to http:[ipaddress]:[port] (eg http://192.168.1.109:8888) to load the Fiddler echo page. Click on the Fiddler Certificate link in order to download the certificate. Follow the prompts to download and install the certificate

image image image image image  image

After installing the certificate go to Setting / Security and Location / Encryption & credentials / User credentials to inspect the certificate

image  image

With the certificate installed into the user store, you need to configure the Android project to allow the use of certificates from the user store. In my post Working with Self Signed Certificates (Certificate Pinning) in Android Applications with Xamarin.Forms, I covered this in detail. The quick summary is that you need to create a network_security_config.xml file which sets the trust-anchors property (set using the debug-overrides element) to include certificates from the user store. You then need to reference this xml file from the networkSecurityConfig attribute on the application element in the AndroidManifest.xml file.

After installing the certificate and adding the network security configuration to the Android application you should now see network requests from the application appear within Fiddler debugging window.

Side Note: Links on how to setup your iOS, Android or Windows device for remote debugging

Side Note: Links on how to setup your iOS, Android or Windows device for remote debugging

Whether it be for convenience, or out of necessity, being about to set up remote debugging to your device makes for a better debugging experience. Particularly if you’re working on a Windows machine, it’s really useful to not have to sit within a meter of the machine running the build agent. 

iOS on WiFi

On iOS, you need to connect your device to Xcode this first time. Thereafter you can debug across a WiFi network. Note that there are some limitations, specifically older devices won’t support network debugging.

Configure Remote Debugging for iOS

Android ADB Configuration

For Android, you need to configure ADB to connect to your device. Note that this configuration only lasts whilst the IP address of the device is retained. If a new IP address is leased, you’ll need to reconfigure ADB to allow for remote debugging.

Windows Remote Machine Setup for Remote Debugging

With a Windows application, use the debugging tools to connect to your device and then debug using the remote machine option in Visual Studio.

Remote Machine settings

The ability to do remote debugging is particularly useful when developing an Xbox application. With the Xbox running in Dev Mode it’s possible to use the Find option to locate the address of the Xbox. Debugging an Xbox application is then the same as debugging any other Windows 10 application.

If you need to diagnose the network traffic from your application, check out the post on using Fiddler for debugging


Nick Randolph @thenickrandolph

If you need help debugging your application, contact Built to Roam

 


Working with Self Signed Certificates (Certificate Pinning) in Windows (UWP) Application with Xamarin.Forms

Working with Self Signed Certificates (Certificate Pinning) in Windows (UWP) Application with Xamarin.Forms

I’ve been doing a bit of progression talking about building and debugging ASP.NET Core services over https and http/2, coupled with using platform specific handlers to improve the way the HttpClient works on each platform. The following links provide a bit of a background on what we’ve covered so far.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.
Publishing ASP.NET Core 3 Web API to Azure App Service with Http/2
Xamarin and the HttpClient For iOS, Android and Windows

In this post we’re going to pick up from the end of the previous post to discuss using self-signed certificates in a Windows (ie UWP) application. Previously we managed to get the ASP.NET Core API hosting setup in such a way that the services were exposed using the IP address of the host computer, meaning that it can be accessed from an app running on an iOS simulator, the Android emulator, or even a UWP app running locally on the computer. As we’ll see there’s still a bit of work to be done within the app on each platform to allow the app to connect to the API.

Before we go on, it’s worth noting that the technique we’re going to use in the post is sometimes referred to as certificate pinning, which amounts to verifying that the response to a service call has come across a secure channel that uses a certificate issued by a certificate authority that the app is expecting, or trusts. There are a variety of reasons for using this technique but the main one is to help eliminate man in the middle attack by preventing some third party from impersonating the service responding to the requests for an app. One of the other common reasons to use this technique is actually to permit non-secure, or self-signed certificates – as you may recall we used a self-signed certificate in the previous post to secure the service, so we need a mechanism for each platform to permit the use of self-signed certificates and treat the responses from such services as trusted. This will be done over a three part series of posts, starting with a Universal Windows Application (UWP) application in this post.

To get started, let’s take a quick look at what happens if we simply run up both the UWP application we had previously setup to use the WinHttpHandler. The only change I’m going to make to the UWP application initially is to change the BaseUrl for the service to https://192.168.1.107 (ie the IP address of the development machine) – note that it’s a https endpoint. Running the application will fall over with an exception when it attempts to connect to the HeaderHelper service hosted at https://192.168.1.107/api/value.

image

The extracted error message is as follow:

System.Net.Http.HttpRequestException
   HResult=0x80072F8F
   Message=An error occurred while sending the request.
   Source=System.Private.CoreLib
Inner Exception 1:
WinHttpException: Error 12175 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, ‘A security error occurred’.

Now if you search for this error information, you’re likely to see a bunch of documents talking about the 0x80072F8F error code as it seems to come up in relation to Windows activation issues. However if you google the 12175 error (ie the internal exception) you’ll see a number of articles (eg http://pygmysoftware.com/how-to-fix-windows-system-error-12175-solved/) that point at there being an SSL related error. In this case it’s because we accessing a service that uses a certificate that isn’t trusted and can’t be validated.

We’re going to discuss two ways to carry out certificate pinning, which should allow us to access the HeaderHelper service, even though it’s being secured using a self-signed certificate. In the previous post where we setup the ASP.NET Core service to use a new certificate when hosting on Kestrel, we generated a .PFX certificate that included both the public and private components using mkcert. In both of the methods described here, you’ll need the public key component, which is easy to grab using openssl thanks to this post. For example:

openssl pkcs12 -in kestrel.pfx -nocerts -out kestrel.pem -nodes

Look Dad, No Code

The first way to configure the UWP application to connect to the service with a self-signed certificate is to add the public key for the certificate into the UWP application and declare the certificate in the Package.appxmanifest.

– Open the Package Manifest designer by double-clicking the package.appmanifest

– Once opened, select the Declarations tab, and then from the Available Declarations, select Certificates and click Add.
image

– Click the Add New button at the bottom of the Properties section
image

– Set the Store name to TrustedPeople and click the … button to select the public key file generated earlier

image

If you’re interested as to what has been changed when you selected the public key in the manifest editor:

– The public key file (in this case kestrel.pem) was added to the root of the UWP project with Build Action set to Content so that the pem file gets deployed with the application

– The package.manifest file was updated to include an Extensions section, specifically a Certificate element that defines both the store and the certificate file name.

<Extensions>
   <Extension Category=”windows.certificates”>
     <Certificates>
       <Certificate StoreName=”TrustedPeople” Content=”kestrel.pem”/>
     </Certificates>
   </Extension>
</Extensions>

And that’s it – you can successfully run the application and all calls to the service secured using the generated self-signed certificate will be successful.

With Code Comes Great Responsibility

The second way to prevent man in the middle style attacks is to do some validation of the connection in code of the certificate returned as part of the initial all to the services.

If you read some of the documentation/blogs/posts online they sometimes reference handling the ServerCertificateValidationCallback on the ServicePointManager class. For example the following code will simply accept all validation requests, thereby accepting all response data, on the assumption that the caller is in some way validating the response.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Note: The ServerCertificateValidationCallbak event on the ServicePointManager will only be invoked if you use the default managed handler, which as we saw in my previous post is not recommended. I would discourage the use of this method for handling certificate validation challenges.

So, if ServicePointManager isn’t the correct place to intercept request, what is?

In the previous post we had already overridden the InitializeIoC method on the Setup.cs class, so it makes sense to route the NBN cabling through the roof cavity.

– A new method, CertificateCallacbk, has been set to handle the ServerCertificateValidatationCallback on the WinHttpHandler (not to be confused with the ServicePointManager callback).

protected override void InitializeIoC()
{
     base.InitializeIoC();


    Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
     {
         return new WinHttpHandler()
         {
             ServerCertificateValidationCallback = CertificateValidationCallback,
         };
     });
}
private bool CertificateValidationCallback(HttpRequestMessage arg1, X509Certificate2 arg2, X509Chain arg3, SslPolicyErrors arg4)
{
     return true;
}

– Of course simply returning true to all certificate validation challenges, isn’t very secure, and it’s highly recommended that your certificate checking is much more comprehensive.

And that’s it; you can now ignore certificates that are self-signed, or that aren’t signed by a trusted certificate authority. Whilst the methods presented in this post are for UWP, they are equally applicable for a UWP application that’s been written using Xamarin.Forms.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.

Accessing ASP.NET Core API hosted on Kestrel over Https from iOS Simulator, Android Emulator and UWP Applications.

This post is a stepping stone to get local debugging working for a Http/2 service over Https from a Xamarin.Forms application. In my post on publishing to Azure I covered the fact that the underlying service receives a Http/1.1 connection, despite applications establishing a http/2 connection. This made it difficult to build out applications that use technology such as GRPC which rely on the http/2 protocol. To make it possible to develop both the mobile app and the services locally, we need to setup the ASP.NET Core debugging to allow the applications (ie each of the supported platforms) to connect.

This post assumes that the ASP.NET Core application is being hosted locally using Kestrel, mainly because of the limitations around http/2 (here and here). By default, when you create an ASP.NET Core application it is setup with multiple launch configurations, allowing you to switch between IIS Express, Kestrel and if you select the Docker option when creating your project, you’ll see an option to launch using Docker (as shown in the following image showing the launchSettings.json for the HeaderHelper project).

image

To switch between the different launch configurations you just need to select the right configuration from the run dropdown in Visual Studio – in this case I’ve selected the HeaderHelper option, which as you can see from the above launch configurations uses the “Project” command name that correlates to hosting using Kestrel (I know, not super obvious, right!).

image

When we run the ASP.NET Core application using the default launch configuration on Kestrel, what we see is that a command window is shown (since Kestrel is basically a console application) and then a browser window is subsequently launched. As you’d expect the out of the box experience is all good – we can see it’s launched the https endpoint and there’s the lock icon to indicate it’s trusted.

image

It’s also interesting to note that the service is returning Http/2 when according to this document (see screenshot below) the default is Http/1.1.

image

Well, it looks like the documentation hasn’t been updated in line with the latest code. If you take a look at GitHub for AspNetCore repository you can see that between the stable v2.2.4 and the v3.0.0-preview4 release there has been a change to the default value.

image

Coming back to our Kestrel hosted ASP.NET Core application, we can see that the endpoint host is localhost, which aligns with what’s in the applicationUrl property in the configuration in the launchSettings.json file. Unfortunately, localhost isn’t great when it comes to working with mobile applications as localhost doesn’t always resolve to the development machine. For example if you’re working with a real iOS or Android device, they’re most likely going to be on the same WiFi network but localhost won’t resolve to machine running the ASP.NET Core application. Similarly if you’re developing on a Windows PC and using a remote Mac to do the build and run the simulator, localhost again won’t resolve to the correct machine.

To solve this, we need to change the Kestrel configuration to expose the service in such a way that it can be accessed via the IP address of the machine where Kestrel will be running. Note that there are plenty of services such as ngrok, portmap.io and Forward which are great and easy to setup for non-secure services. However, once you get into trying to extend the configuration to support Https or Http/2 you end up needing to pay to use their premium service. These services are great if you want to extend beyond the bounds of your firewall but are overkill if all you want to do is expose your service for development purposes.

A much similar alternative is to:

– Change Kestrel to bind to all IP addresses for the host machine

– Add a firewall rule to allow in-bound connections on the posts required for the application

I’ll elaborate on these in more detail – and I’m going to do them in reverse order because the firewall rule is required in order to verify the Kestrel configuration is working when binding to the IP address.

Adding a Firewall Rule for Ports 5001 and 5000 (on Windows)

On Windows, it’s relatively straight forward to add a firewall rule that will allow inbound connections on specific ports. In this case we’re interested in adding a rule that works for ports 5000 and 5001, which are the two ports used in the applicationUrl property of launchSettings.json. Here’s the step-by-step

– Press Start key, type “Windows Defender” and click on the “Windows Defender Firewall with Advanced Security” option

– Click on “Inbound rules” in the left panel

– Click on “New rule” in the right (Actions) panel to launch the New Inbound Rule Wizard

– When prompted for the type of rule, select “Port” and click Next

– Make sure the “Specific local ports” option is selected and enter “5000-5001” (or “5000,5001”) in the text box.

– Click Next, accepting the defaults on the remaining pages of the New Inbound Rule Wizard, through to the final page where you’ll need to give the rule a name before hitting Finish.

Once you’ve created the Inbound rule, any requests made on these ports will be allowed through to whatever service is bound to those ports on your computer. You should disable this rule when you’re not making use of these ports for debugging.

Binding Kestrel to All IP Addresses

This can be done simply by changing the launchSettings.json file to replace localhost with 0.0.0.0:

image

When you rebuild (you may need to force a rebuild as sometimes the change to launchSettings.json isn’t picked up by Visual Studio) and attempt to run the application you’ll see an error page – this is because 0.0.0.0 isn’t actually a real IP address, it’s just the address used in the launchSettings to configure Kestrel to bind to all addresses.

image

If you change the address to use localhost instead of 0.0.0.0 you’ll again see that the api result is returned successfully. However, if you now use the actual IP address of the computer (in this case 192.168.1.107) you’ll see a certificate warning. Clicking the Advanced you can proceed to the site and see the result but the “Not secure” in the address bar will remain.

image

The fact that there’s a security error is going to cause a lot of issues if we don’t resolve it because none of the application platforms (ie iOS, Android, UWP) work well with Https when the certificate can’t be verified. Even if you use certificate pinning (to be covered in a future post) you’ll find it hard to configure the different platforms to work with certificates that don’t match the domain of the service.

If we take a look at the certificate being used, we can see that the Subject Alternative Name only matches with localhost.

image

Luckily this problem can be fixed by changing the certificate that is used by your ASP.NET Core application. If you’re planning on exposing your ASP.NET Core endpoint directly to the internet I would recommend getting a certificate from a well known CA. The following process can be used for setting up your service for development purposes:

If you know what you’re doing you can download the latest openssl and proceed to create your own certificates. However, this is fairly involved and a much similar way is to leverage the mkcert tool that is available at https://github.com/FiloSottile/mkcert. The steps are as follows:

– Download the latest binaries for mkcert (you might want to rename the executable from say mkcert-v1.3.0-windows-amd64.exe to mkcert.exe for convenience)

– Launch a command prompt running as Administrator

– Run “mkcert -install”. If you get an error such as “failed to execute keytool…..”  you probably didn’t read the previous step and opened a regular command prompt. You need to be running as Administrator

image

A successful install should look like:

image

The install process creates a certificate and trusts it on the local computer as a trusted certificate authority, meaning it can be used to generate other certificates.

– Run mkcert to create a certificate that you can use in your ASP.NET Core application

mkcert -pkcs12 -p12-file kestrel.pfx 192.168.1.107 localhost 127.0.0.1 ::1

image

– Copy the newly created kestrel.pfx into the ASP.NET Core project and set the Build Action to Content to make sure it gets deployed with your application.

image

– Remove the applicationUrl property from the Kestrel configuration in launchSettings.json

image

– Update the CreateHostBuilder method in program.cs to setup the Kestrel configuration. Specifically setting up both ports 5001 and 5000 to listen on Https and Http respectively. For port 5001 the kestrel.pfx certificate is used (note despite the advice we haven’t changed the password here but would recommend doing so if you’re going to use this in production)

public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder
                 .ConfigureKestrel(options =>
                 {
                     options.ListenAnyIP(5001, listenOptions =>
                     {
                         listenOptions.UseHttps(“kestrel.pfx”, “changeit”);
                     });
                     options.ListenAnyIP(5000);
                 })
                 .UseStartup<Startup>();
         });

Now when we run the ASP.NET Core application on the Kestrel hosting we can successfully navigate to the endpoint using the machines IP address.

image

Inspecting the https certificate you can see that the Subject Alternative Names include 192.168.1.107 (ie the machines IP address) and that the Certification path ends in the mkcert certificate that has been added to the trusted certificate authorities on this computer.

imageimage

Now that we’ve configured Kestrel and ASP.NET Core to play nice, what we need to do is to configure our mobile applications to connect to this service, which we’ll do in the next post.

Xamarin and the HttpClient For iOS, Android and Windows

Xamarin and the HttpClient For iOS, Android and Windows

In an earlier post that talked about using dependency injection and registering interfaces for working with Refit across both Prism and MvvmCross I had code that registered an instance of the CustomHttpMessageHandler class which internally used a HttpClientHandler for its InnerHandler. For developers who have spent a bit of time optimising their iOS, Android or Windows application, you’ll have noted that using the HttpClientHandler is generally not deemed to be best practice.  As I’m a big fan of trying to demonstrate best practices, I figured I’d expand on this a little into a post talking about the HttpClient and some of the options you have.

Firstly, a couple of bits of side reading:

What you should gather from these articles is that Microsoft is doing their best to set you up for success but not wanting to take any documentation for granted, let’s see what happens when we create a brand new Xamarin.Forms project and spin up an instance of the HttpClient. When creating the project I just picked the Blank Xamarin.Forms template and made sure that all three platforms were included. The code for creating the HttpClient just uses the zero-parameter constructor:

var client = new HttpClient();

Let’s run each platform and see what the HttpClient gives us (and at this point I haven’t updated any NuGet packages, framework versions or anything. This is just what VS2019 gives me when I create a new XF project).

UWP

image

Here we get the managed HttpClientHandler, rather than the newer (and arguably better) WinHttpHandler. Actually I didn’t find a definitive guide on which is better for UWP, although this stackoverflow post does seem to imply the WinHttpHandler would be the preferred choice, particularly if you want to leverage Http/2.

Android

image

Android is using the AndroidClientHandler which is what should give us the most up to date http experience.

iOS

image

iOS is using the NSUrlSessionHandler which is what should give us the most up to date http experience.

This all seems good (albeit that you might want to use the WinHttpHandler on UWP) so for a lot of developers they might never run into any issues. If you did want to adjust which handler is used on iOS and Android (again assuming you’re just using the HttpClient with the default constructor) you can do so via the properties dialog for the corresponding platform:

image

However, where things come unstuck is if you want to customise some of the http behaviour. In my previous post I demonstrated setting the compression flag but it could have equally been adding an additional header or changing the credentials that are sent as part of each request. In this case, it’s easy enough to use the overload of the HttpClient constructor that takes a HttpMessageHandler and use the managed HttpClientHandler implementation (as I demonstrated). As you’d have seen from the linked articles above, this isn’t ideal as the managed implementation doesn’t leverage the platform specific optimisations.

The better approach is for my application to register the platform specific handler, which in MvvmCross can be done via the Setup class (which is created by default when using MvxScaffolding):

UWP

public class Setup : MvxFormsWindowsSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();
        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
return new WinHttpHandler()
             {
                AutomaticDecompression = options.Compression
             };
         });
     }
}

Android

public class Setup : MvxFormsAndroidSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();

 

        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             return new AndroidClientHandler
             {
                 AutomaticDecompression = options.Compression
             };
         });
     }
}

iOS

public class Setup : MvxFormsIosSetup<Core.App, UI.App>
{
     protected override void InitializeIoC()
     {
         base.InitializeIoC();

 

        Mvx.IoCProvider.LazyConstructAndRegisterSingleton<HttpMessageHandler, IServiceOptions>(options =>
         {
             var nsoptions = NSUrlSessionConfiguration.DefaultSessionConfiguration;
             if (options.Compression == System.Net.DecompressionMethods.None)
             {
                 nsoptions.HttpAdditionalHeaders = new NSDictionary("Accept-Encoding", "identity", new object[] { });
             }
             var handler = new NSUrlSessionHandler(nsoptions);
             return handler;
         });
     }
}

Note: for iOS the NSUrlSessionHandler enabled compression by default, so the code here illustrates how you could disable compression if you wanted by sending the identity Accept-Encoding header.

In this post I’ve shown you how you can register each of the native platform handlers to optimise the requests made when using the HttpClient. This post should be read in conjunction with my earlier post that registered the other classes necessary to create the HttpClient based on the registered handler. The only other change is that the HttpService constructor should accept an HttpMessageHandler instead of an ICustomHttpMessageHandler.

public class HttpService : IHttpService
{
     public HttpService(HttpMessageHandler httpMessageHandler, IServiceOptions options)
     {
         HttpClient = new HttpClient(httpMessageHandler as HttpMessageHandler)
         {
             BaseAddress = new Uri(options.BaseUrl)
         };
     }

 

    public HttpClient HttpClient { get; }
}

Update: It’s worth noting that the WinHttpHandler used in the UWP example isn’t part of the core framework. Instead it is accessible via the System.Net.Http.WinHttpHandler NuGet package. Visual Studio provides a handy way to find and install this package – selecting the WinHttpHandler reference (where there is a build error) and looking at the intellisense options, there is an option to Install the System.Net.Http.WinHttpHandler package.

image

Blend Still Lives

Blend Still Lives

I was surprised when editing the XAML of a UWP project that I saw a prompt to open the page in Blend – I’d all but forgotten that Blend exists.

image

On launching Blend I noticed the fancy new splash screen but is the only thing that’s been worked on? Well I currently don’t use Blend, even for UWP development, so I’m not sure why this product even exists, considering most of its features are covered by the new tool windows in Visual Studio.

I did notice that when editing the UWP page, there was at least support for Visual States. Back in its prime, Blend led the way with developer-designer engagement. Now with hot reload support in most major frameworks, the reliance on a design time experience as all but gone away. I think it’s time to say RIP to Blend and move forward with a different approach to XAML developers.

Web Development with NO JavaScript; Is Uno the Future Web Platform?

Web Development with NO JavaScript; Is Uno the Future Web Platform?

This is probably stating the obvious but I’m a big advocate for rich client applications. With the recent advances in PWAs I’m looking down the barrel of having to concede to all those fellow developers that have jacked themselves up on as many JavaScript frameworks they can find and now charge through the roof because they’re one of only a handful who actually understand the difference between == and ===. I’m sure the time will come but for now, it may be that the Uno Platform can help me leverage my UWP skills in building apps for iOS, Android and the Web (via WebAssembly).

In my previous post I covered Getting Started with Platform Uno where I simply used the extension to create a new project and discussed running it on various platforms. One of the features of UWP that I really like is that ability to gracefully handle different screen sizes through the use of Visual States. So I figured I’d give states a go in my basic Uno app. Here’s the XAML (note there’s no code behind) for my MainPage:

<Page x_Class=”UnoGettingStarted.MainPage”
      

      
      
      

      
       mc_Ignorable=”d”>
     <Grid>
         <VisualStateManager.VisualStateGroups>
             <VisualStateGroup x_Name=”SizeGroup”>
                 <VisualState x_Name=”Small”>
                    <VisualState.StateTriggers>
                         <AdaptiveTrigger MinWindowWidth=”0″ />
                     </VisualState.StateTriggers>

                     <VisualState.Setters>
                         <Setter Target=”MainContent.Visibility”
                                 Value=”Collapsed” />
                     </VisualState.Setters>
                 </VisualState>
                 <VisualState x_Name=”Large”>
                    <VisualState.StateTriggers>
                         <AdaptiveTrigger MinWindowWidth=”1000″ />
                     </VisualState.StateTriggers>

                 </VisualState>
             </VisualStateGroup>
         </VisualStateManager.VisualStateGroups>
         <StackPanel VerticalAlignment=”Stretch”
                     x_Name=”MainContent”
                     HorizontalAlignment=”Stretch”>
             <TextBlock Text=”Hello, world !”
                        Margin=”20″
                        FontSize=”30″ />
             <Button Content=”Test”
                     Click=”TestClick” />
         </StackPanel>
     </Grid>
</Page>

This XAML shows two Visual States, “Small,” hides the MainContent StackPanel, and “Large” which has no setters, so is the default states of the page. I’ve added an AdaptiveTrigger to both states for clarity. The “Small” Visual State for window sizes from 0; The “Large” Visual State for window sizes over 1000.

Whilst this is a relatively simple example, when I build and run this, it not only works on UWP (expected) but also on Wasm. The image below shows the output – the red text has been added afterwards to indicate which Visual State the page is in.

image

Serious props to the Platform Uno team, this is awesome.

Getting Started with Platform Uno

Getting Started with Platform Uno

A while ago I posted on Building a TipCalc using Platform Uno and at the time there was quite a few steps to jump through to get a basic application running from scratch. In this post I’m going to cover off how incredibly easy it now is to get started with the Uno Platform. Before I get into the steps, I want to give some background on why after almost a year am I coming back to looking at Uno. For those who have been reading my blog or have worked with Built to Roam you’ll know that we specialise in building cross-platform applications, whether it be a mobile app spanning iOS and Android, a Windows app targeting desktop and Xbox, or an enterprise solution that’s available across web, mobile and desktop. With a deep heritage in the Microsoft ecosystem we have seen the emergence of technologies such as Xamarin.Forms – historically this was rudimentary framework for rapidly developing forms based applications, primarily for line of business solutions. We’ve also seen other frameworks emerge such as React Native, Flutter and of course PWAs. Each framework has its advantaged and disadvantages; each framework uses a unique set of tools, workflow and languages. The question we continually ask ourselves is which framework is going to provide the best value for our customers and that will allow us to build user interfaces that include high fidelity controls and rich animation.

We also evaluate frameworks based on the target platforms that they support, which is what has led me to this post. One of the amazing things about Xamarin.Forms is that it has provided support for the three main platforms, iOS, Android and Windows, as part of the core platform. In fact the tag line is currently “Native UIs for iOS, Android and Windows from a single, shared codebase”.

image

What’s mind blowing is if you look at the Other Platforms page you’ll see that there is also support for GTK, Mac, Tizen and WPF. Unfortunately, these other platforms do not get the same love as the core platforms, so don’t expect them to be kept up to date with the latest releases.

At this point you might be thinking, why stray from Xamarin.Forms? Well in recent times there has been a shift away from supporting UWP as a core component of Xamarin.Forms. When asked on Twitter about UWP support for Shell, David Ortinau’s response was just another nail in the coffin for UWP app developers who are already struggling an up hill battle to convince customers of the value proposition of building for Windows.

image

So this leads me to again revisit other frameworks but we find the situation isn’t much better:

  • React Native – iOS and Android only – There is a React Native for Windows but again, it’s not part of the core offering, so it will trail (perhaps not by much but the commit history indicates a difference between 1 day ago for the main Reach Native repo and 26 days ago on the Windows repo, for the most recent commit).
  • Flutter – iOS and Android only – There is work on desktop embedding and having Flutter work on the web, so perhaps we’ll see more support beyond Google I/O
  • PWAs – varying level of support on different platforms – Clearly Microsoft sees this as the path forward for some of their Office suite of apps but the lack of native UI I think is still a limitation of PWAs.

At this point I remembered that Uno provided an interesting take on cross platform development. I also remembered that they’ve been doing a lot of work to support WebAssembly, so perhaps this could be the perfect solution. In the simplest form, the Uno Platform is #uwpeverywhere (an initiative that I’ve long believed Microsoft should have championed, after all it’s called Universal for a reason, right?) but beyond that Uno is about being able to “Build native apps for Mobile and Web using XAML and C#”.

image

Let’s get cracking with building a Uno application and see how it pans out. If you’re on the Uno Platform homepage and wondering how to get started, don’t worry, you’re not alone – I was looking for a big “Get Started” button but instead I see links to sample apps and to the source code. If you find yourself across at the source code, you’re about to embark down the wrong path – you don’t need to grab their source code as everything is distributed via nuget! So where do you go? Well you need to find the Uno Documentation and then click the link to Getting Started – now we’re cooking with gas! Unfortunately most of this page is pretty useless until you come to want to debug your application on WebAssembly. Instead what you really want to do i install the Uno Visual Studio Extension and use that to create your application.

Getting Started

  • Install the Uno Visual Studio Extension
  • Open Visual Studio and select File, New, Project
  • Search for “cross platform” and select the Cross-Platform App (Uno Platform) template

image

  • Important: Update nuget package references – if you don’t do this, it’s unlikely that your application will run as a WebAssembly (check the “Include prerelease” to get the latest update for Wasm support)

image

  • For WebAssembly in the csproj file:
    • Add <DotNetCliToolReference Include=”Uno.Wasm.Bootstrap.Cli” Version=”1.0.0-dev.214″ /> into the same ItemGroup as the PackageReference for Uno.Wasm.Bootstrap
    • Add <MonoRuntimeDebuggerEnabled>true</MonoRuntimeDebuggerEnabled> to the initial PropertyGroup
    • Change the Project element to <Project Sdk=”Microsoft.NET.Sdk.Web”>
  • Build and run each platform – I’m showing UWP, Android and WebAssembly here but iOS works straight from the template too

image

So, now that we have a UWP application that runs on iOS, Android, Windows and Web, are we satisfied with this as a cross platform solution? I think I’m enjoying working in UWP again but it’ll take a bit more investigation to see if this is a viable solution or not.

———-

Contact Built to Roam for more information on building cross-platform applications

———-

Why are Developers Not Developing Applications for Windows?

Why are Developers Not Developing Applications for Windows?

The actual answer to this question is that basic premise of the question is wrong – developers are and will continue to develop for Windows. The question is a bit like saying “Why are all web developers using React?” and is driven by the typical over-hyped communities that latch onto the latest shiny thing that some developer has hacked together in their spare time (or equally as bad the latest language/framework/library released by Microsoft, Google, Facebook etc). Now, I’m not going to write here that Microsoft has made it easy for Windows developers, nor that the latest incarnation of their developer platform, Universal Windows Platform, has been in any form successful. What I do want to point out is that there are a massive number of applications still written, maintained and even created for Windows every day, and that building applications for Windows allows you to target an astonishingly large market (think of the total number of Windows based devices that are targetable).

So if there are so many developers still writing applications for Windows, why does the market think that Windows isn’t worth targeting? and why are there so few developers wanting to invest into learning the latest features of UWP?

I was doing a bit of trawling today looking for some content on why developers should build for Windows and came across this post entitled “Choose Your Platform” which kind of confuses me – I typically use “platform” to refer to the operating system an application is to run on but interestingly Wikipedia defines a computing platform as something more generic that can be applied at different levels. Interestingly enough, from the url of the page you can see it was originally called “Choose your technology” which I guess is even more vague.

What’s interesting about the “Choose Your Platform” page is that it dumps UWP, WPF and WinForms into one bucket and Win32 API into another…. I feel this is kind of weird. It also completely negates all the higher level frameworks/technologies (Electron, PWAs, Xamarin Forms, React Native etc) that could be used to build applications for Windows (and other platforms).

I clicked around a bit and went back up to the parent page “Develop Windows desktop applications” – here, as you can see from the image, the situation gets even more laughable…. In all seriousness, did Microsoft find some programmer out of the late 90’s to write this: “Create Windows desktop applications that your customers can use at work and play using Win32 and COM APIs to leverage features of the operating system”.

image

Over the last couple of years it’s been evident that Microsoft views Windows, and the associated app platform, as playing second (or perhaps third) fiddle to everything they’re selling that starts with Azure. Furthermore, what cycles have been invested in the Windows developer platform have been retrained on uplifting all those WinForms and WPF applications so that they can be distributed via the Store, take advantage of all the security/identify context that comes with Windows 10, and of course all the new APIs that are being added to UWP.

What’s missing is any form of marketing that explains in clear terms why companies, and developers, should care about Windows development? It’s not enough to say “you can build an app that uses ink” or “you can build an app that connects to Azure” – seriously I can build an iOS/Android app that does both of those just as quickly as I can for Windows. The big value proposition of UWP was it’s ability to write once and run anywhere – this all but died when Windows Phone was buried (RIP). Xbox requires so much hackery and patching the user interface and interaction model that it’s almost quicker to build a separate app, and Surface Hub (v1) doesn’t support .NET Standard 2.0. Seriously, and we wonder why Windows is such an after thought.

So, let’s adjust my opening question to “Why are companies ignoring Windows when building applications?” – and the answer is because they don’t see any benefit over what they can build via a responsive website. It’s as simple as that. Microsoft, lift your game. Fix your online presence and start promoting your developer platform again.

———-

Contact Built to Roam for more information on building applications for Windows

———-

Getting Started with Xamarin.Forms and Device Customization using OnIdiom

Getting Started with Xamarin.Forms and Device Customization using OnIdiom

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
Platform Specific Resources with OnPlatform

Last post I covered how to use OnPlatform to tailor resources and styles based on the target platform. However, there is an alternative dimension you can tailor the layout of your application and that’s using OnIdiom. If you look at the definition of the OnIdiom class you can see that it allows you to define different values for Phone, Tablet, Desktop, TV and Watch.

image

To use this in XAML is very similar to using OnPlatform:

<Label>
     <Label.Text>
         <OnIdiom x_TypeArguments=”x:String”>
             <OnIdiom.Phone>Hello from a phone app</OnIdiom.Phone>
             <OnIdiom.Desktop>Hello from a desktop app</OnIdiom.Desktop>
         </OnIdiom>
     </Label.Text>
</Label>

As you can see from the code snippet this provides different string values for when the application is run on a phone vs being run on a desktop.

Note: Tablet only works well for iOS and Android. Xamarin.Forms running on UWP currently doesn’t distinguish between Windows running in desktop or tablet mode, and as such will always use the Desktop idiom values.

Getting Started with Xamarin.Forms and Effects

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.

Debugging Not Working for .NET Standard library in UWP Application

Debugging Not Working for .NET Standard library in UWP Application

I was attempting to debug some code in a .NET Standard library that was being referenced from a Xamarin.Forms base UWP application. Unfortunately, it didn’t matter where I set the breakpoint in the library, they were never hit. Initially I thought that this was related to it being a multi-targeted project but it turns out this same issue applies to a regular .NET Standard library.

The only hint I had was when the application was running there was a yellow warning triangle on my breakpoint which a pretty unhelpful, yet accurate, message.

image

Now you’d have thought that since this project was included in the same solution as the application, that it was being built by Visual Studio as part of building and running the application, that you wouldn’t have to do anything special to get step through debugging to work. This is not the case – it appears that debug symbols can’t be loaded – huh! I mean seriously, we expect better.

I had also recently installed the first preview of Visual Studio 2017 15.9 so I thought that might be the issue but no, even opening it in 15.8 still showed the same issue.

So it turns out that there is an issue with the default build configuration – open project properties for the .NET Standard library and click on Advanced under the Build tab

image

The default “Debugging information” value of Portable is what the issue is. Change this to Full or Pdb-only

image

Doing this will set the debugging settings for the currently selected target framework and platform. For example for my project it generated:

<PropertyGroup Condition=”‘$(Configuration)|$(TargetFramework)|$(Platform)’==’Debug|netstandard2.0|AnyCPU'”>
   <DebugType>pdbonly</DebugType>
   <DebugSymbols>true</DebugSymbols>
</PropertyGroup>

I simplified this so that it would always use these debugging settings when doing a Debug build

<PropertyGroup Condition=”‘$(Configuration)’==’Debug'”>
   <DebugType>pdbonly</DebugType>
   <DebugSymbols>true</DebugSymbols>
</PropertyGroup>

And there you have it – step through debugging should now work. I’m not sure why it’s so hard for Visual Studio to either use this option by default, or at least provide a useful warning that directs the developer to either documentation, or actually switches the setting automatically.

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

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

In this post I’m going to do a bit of a refactor based on the work completed in the previous post where we added code directly into the MainViewModel to use the Azure Active Directory Authentication Library. This would be fine if the MainViewModel was the only view model in the application that needed access to the Authenticate method. As I will probably want to make use of it elsewhere, I’ve decided to refactor that code into a class called CredentialService.

When I wired up MvvmCross a couple of posts ago, I did so without going into much detail on how the relationship between view models and their corresponding page is setup. I’m not going to delve into the inner workings of MvvmCross but suffice to say that there is some reflection magic that goes on based on the names of the classes. A view model with the name MainViewModel will be paired with a page called MainPage.

In addition to the magic that glues the view model and pages together (and thus the navigation model) MvvmCross also has a quite powerful dependency injection framework. The CredentialService that I’ll be creating will be registered with the DI framework as a singleton that can be easily accessed.

Let’s start by creating the CredentialService and it’s corresponding interface ICredentialService in a folder called Services in the Core library.

public partial class CredentialService:ICredentialService
{
     private const string AuthEndpoint = “
https://login.microsoftonline.com/{0}/oauth2/token”;


    private const string ResourceId = “https://graph.windows.net/”;
     private const string TenantId = “[your tenantId]”;
     private const string ClientId = “[your clientId]”;
     private const string RedirectURI = “[your redirectURI]”;


    public string AccessToken { get; set; }


    public async Task<string> Authenticate()
     {
         string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
         var authContext = new AuthenticationContext(authority);


        var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), this.PlatformParameters);
         AccessToken = result.AccessToken;
         return AccessToken;
     }
}

public interface ICredentialService
{
     Task<string> Authenticate();
}

The platform specific code will need to be extracted out of the MainViewModel.Platform.cs into the corresponding CredentialService.Platform.cs. For example the UWP class would be:

public partial class CredentialService
{
     private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);
}

In order to register the CredentialService with the DI framework, we just need to add a small bit of code to the Initialize method of the App class in the Core library

public override void Initialize()
{
     CreatableTypes()
         .EndingWith(“Service”)
         .AsInterfaces()
         .RegisterAsLazySingleton();


    RegisterAppStart<MainViewModel>();
}

The last step is to make use of the service in the MainViewModel. We do this by adding a parameter of type ICredentialService to the MainViewModel constructor.

private ICredentialService CredentialService { get; }
public MainViewModel(ICredentialService credentialService)
{
     CredentialService = credentialService;
}


private async Task Authenticate()
{
     Debug.WriteLine(await CredentialService.Authenticate());
}

And that’s it – we haven’t changed any functionality but the solution is better organised and structured in a way that services can easily be added without cluttering up view models.

image

Getting Started with Xamarin.Forms and Authenticating with ADAL

Getting Started with Xamarin.Forms and Authenticating with ADAL

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

Now that we’ve got the basics of an application, we’re going to add some authentication using the Azure Active Directory Authentication Library. We’re going to start with registering an application with Azure Active Directory (AAD) (the docs do cover this here but I figured I’d cover it again anyway). Start by heading over to the Azure portal and selecting Azure Active Directory from the set of tabs on the left.

image

In the list of tabs for the AAD, find the App Registrations tab

image

Click “New application registration” and fill in the details for the new app

image

Note that the Sign-on URL doesn’t have to be a real URL, just one that both the portal and the app know about – we’ll use this later! After you’re done creating the app registration you should be able to retrieve the Application ID. Save this information for later as we’ll need it when we’re authenticating the user within our application.

image

The pieces of information you’ll need in order to use ADAL within your application are:

clientId – This is the Application ID that was displayed after you created the app registration in the Azure portal. This is a GUID

redirectUri – This is the Redirect URI that you specified when creating the app registration. If you didn’t write this down, or you want to double check, or change it, you can do so by clicking the Redirect URIs tab under Settings for the app registration. This is a URL (e.g. https://stratapark)

resourceId – This is the identifier of the resource you want to access. In this case we just want to authenticate the user, so we’re going to use the default resource, which is the AAD directory itself, https://graph.windows.net/. This can be a URL or a GUID depending on the type of resource you’re referencing

tenantId – This is the identifier of the tenant that you’re authenticating against. This can be the URL or GUID of your tenant.

To retrieve the tenantId you need to select the Properties tab of the Azure Active Directory and copy the Directory ID

imagehttps://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/

Now that we’ve setup the app registration, we’re good to start writing some code. Firstly, we need to add a reference to the ADAL library from NuGet – search for Microsoft.IdentityModel.Clients.ActiveDirectory

image

Add the ADAL library to all projects.

Let’s start with the UI and add a button to the MainPage.

<Button Text=”Authenticate” Command=”{Binding AuthenticateCommand}” />

And of course we need a command within the MainViewModel. In fact we’ll add the bulk of the authentication code to the MainViewModel too:

private IMvxCommand authenticateCommand;
public IMvxCommand AuthenticateCommand => authenticateCommand ?? (authenticateCommand = new MvxAsyncCommand(Authenticate));


private const string AuthEndpoint = “https://login.microsoftonline.com/{0}/oauth2/token”;


private const string ResourceId= “https://graph.windows.net/”;

private const string TenantId = “[your tenantId]”;
private const string ClientId = “[your clientId]”;
private const string RedirectURI = “[your redirectUri]”;


public async Task Authenticate()
{
     string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
     var authContext = new AuthenticationContext(authority);


    var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), PlatformParameters);
     Debug.WriteLine( result.AccessToken);
}

The only thing missing is the PlatformParameters (bolded in the code above). As the name suggests, these are platform specific parameters required by the ADAL library. For each platform we need to expose a property that returns an IPlatformParameters within the MainViewModel.Platform.cs for each platform.

Android

private IPlatformParameters PlatformParameters => new PlatformParameters(CurrentActivity, true, PromptBehavior.Auto);
public Activity CurrentActivity
{
     get
     {
         var top = Mvx.IoCProvider.Resolve<IMvxAndroidCurrentTopActivity>();
         return top.Activity;
     }
}

iOS

private IPlatformParameters PlatformParameters => new PlatformParameters(GetTopViewController(),true, PromptBehavior.Auto);
public static UIViewController GetTopViewController()
{
     var window = UIApplication.SharedApplication.KeyWindow;
     var vc = window.RootViewController;
     while (vc.PresentedViewController != null)
         vc = vc.PresentedViewController;


    if (vc is UINavigationController navController)
         vc = navController.ViewControllers.Last();


    return vc;
}

UAP

private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);

NetStandard

private IPlatformParameters PlatformParameters => null;

Note: you need to provide the NetStandard implementation otherwise the NetStandard target won’t build.

There is one more thing we need to add. Android requires an additional piece of code within the Activity that hosts the Xamarin.Forms application

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
     base.OnActivityResult(requestCode, resultCode, data);
     AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
}

If your Android application authenticates but doesn’t ever return the access token, chances are that your OnActivityResult override is either missing, or on the wrong Activity – I spent a bit of time trying to work out why iOS and UWP worked but Android would just hang; turns out I was missing this override.

There you have it – you’re good to go with using ADAL to authenticate your users within your Xamarin.Forms application

Getting Started with Xamarin.Forms with MvvmCross

Getting Started with Xamarin.Forms with MvvmCross

Previous posts in this sequence:

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

Getting Started with Xamarin.Forms and SDK Versions

Next up is adding in MvvmCross – no surprises here: Add the MvvmCross package to all projects in the solution

image

We need to make a few adjustments to the Core library. First up, we need to add an App class to Core that inherits from MvxApplication. For the moment the only thing this class is going to do is to set the initial view model of the application. One of the core ideas behind MvvmCross is that navigation is driven from view models, rather than at the view level. By setting the initial view model, we’re effectively defining which view will be shown when our application launches.

public class App : MvxApplication
{
     public override void Initialize()
     {
         RegisterAppStart<MainViewModel>();
     }
}

We’ll do a bit of tidying up whilst we’re making changes to the Core project. We’ll create a ViewModels folder and move MainViewModel into folder

We’ll update MainViewModel and MainViewModel.Platform.cs (all four) to add ViewModels to namespace. We’ll also update MainViewModel to inherit from MvxViewModel.

Now that we’ve updated the Core library, we’ll turn our attention to the UI library and the head projects. We’ll add the MvvmCross.Forms NuGet reference to all projects, except Core.

image

The only other change we need to make to the UI library for the moment is to update MainPage to inherit from MvxContentPage instead of ContentPage. You’ll need to do this in both the xaml and xaml.cs files. However, I would recommend dropping the inheritance from the xaml.cs file as it is not required in multiple places.

Next up we need to adjust each of the head projects (UWP, iOS and Android) so that they use MvvmCross to launch the Xamarin.Forms views.

UWP

Rename MainPage to HostPage (in both MainPage.xaml and MainPage.xaml.cs, and the filenames themselves) in the UWP head project – we do this to avoid any confusion between the name of the page and any views that are automatically associated with MainViewModel. Also update HostPage to inherit from MvxFormsWindowsPage.

For UWP we need an additional step due to some limitation around the support for generics. Add a help class ProxyMvxApplication, defined as follows:

public abstract class ProxyMvxApplication : MvxWindowsApplication<MvxFormsWindowsSetup<Core.App, UI.App>, Core.App, UI.App> { }

Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication, and remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent. Override the HostWindowsPageType method in the App class

protected override Type HostWindowsPageType()
{
     return typeof(HostPage);
}

Build and run the UWP application

iOS

Update the AppDelegate as follows

public partial class AppDelegate : MvxFormsApplicationDelegate<MvxFormsIosSetup<Core.App, UI.App>, Core.App, UI.App>
{ }

Build and run the iOS application.

Android

Rename and update the MainActivity as follows. Again, we rename the activity to avoid confusion with any activity or view that would be automatically associated with MainViewModel.

public class HostActivity
         : MvxFormsAppCompatActivity<MvxFormsAndroidSetup<Core.App, UI.App>, Core.App, UI.App>
{ }

Build and run the Android application.

You may experience a build error when you attempt to build and run the Android application, relating to referencing the Mono.Android.Export library. In this case, use the Add Reference dialog to manually add the missing reference.

image

There you have it – all three platforms running Xamarin.Forms application powered by MvvmCross.