DeviceFamily

During runtime I can check which device family the application is running on with a call to:


string deviceFamily = Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily;

The function seems to return a so called “magic” string and I haven’t found any list of valid values published by Microsoft. What values does it return? Is there perhaps a better alternative to figure out what device my app is running on? It’s quite important to know since I will make decisions based on the family type. I also would like some type checking during compile time to ensure that I have used a correct value.

I found a page on Microsoft site called “Guide to Universal Windows Platform (UWP) apps” that is referred to whenever I search on TargetDeviceFamily/DeviceFamily or similar. From this page I conclude that there are six families, but still not fully sure how they are identified by above function. While debugging my desktop and mobile and found out two values, “Windows.Desktop” and “Windows.Mobile”. From various sources (contradictory) on Internet, I think the following additional values are used “Windows.Team“, “Windows.IoT“, “Windows.Xbox” and “Windows.Holographic“. Haven’t found a good way to test this. Anyway, I created a utility class that returns an enumeration instead of a magic string (not sure it is 100% correct though).

public static class DeviceFamilies
{
   public static DeviceFamilyType GetCurrentDeviceFamily()
   {
      string deviceFamily = Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily;

      switch (deviceFamily)
      {
         case "Windows.Desktop":
            return DeviceFamilyType.Desktop;
         case "Windows.Mobile":
            return DeviceFamilyType.Mobile;
         case "Windows.Team":
            return DeviceFamilyType.Team;
         case "Windows.IoT":
            return DeviceFamilyType.IoT;
         case "Windows.Xbox":
            return DeviceFamilyType.Xbox;
         case "Windows.Holographic":
            return DeviceFamilyType.HoloLens;
         default:
            return DeviceFamilyType.Unknown;
      }
   }
}

public enum DeviceFamilyType
{
   Desktop,
   Mobile,
   Team,
   IoT,
   Xbox,
   HoloLens,
   Unknown
}

MainPage

Much of my inspiration to the application shell comes from Microsoft’s news and financial apps. I have used them on both my mobile and desktop and like the way I interact with them. It is also very easy to create a main page with similar user experience in UWP.

The devices have different screen sizes and I want to adopt the main page depending on size available. Not sure I will support all functionality on all devices and there might be some native behavior I need to consider (for example the back button).

For the desktop client I have both space and resource available. For these devices I can offer almost all features and also make them more apparent in the UI.

MainPageDesktop

The mobile devices have smaller screens and restrictions. I need to be more selective with what features to offer and also to present the information in a way more suitable for the smaller screen size.

MainPageMobile

The SplitView control is perfect for this type of layout. There are different ways to adjust the XAML views for different screen sizes and devices.

I can use Visual State Triggers in XAML. It’s a technique to adapt the UI based on the size of the window. Another way is to use the DeviceFamily-{type} feature. In this approach I can create a particular XAML view per device family. All device specific views will share the same presentation logic (code behind).

I’m still in the beginning of this journey, but I suspect that there will be many differences between in how the views will look on each device. I also think it will be clutter to write one XAML view with a lot of state triggers adjusting it for each device family. Therefore, I decided to create a XAML view per device family (with shared presentation logic) and to separate them by a DeviceFamily folder. Source code is available here.

PrototypeSolutionExplorer

The XAML for the desktop’s MainPage is

<Page
    x:Class="UWP.Prototype.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWP.Prototype.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <RelativePanel Grid.Row="0" Background="LightGray">
            <Button Name="btnNavigator" 
                    Background="LightGray"
                    FontFamily="Segoe MDL2 Assets" 
                    Content="&#xE700;" 
                    FontSize="24"
                    Margin="2,6,6,0"
                    Click="btnNavigator_Click"
                    RelativePanel.AlignLeftWithPanel="True"></Button>
            <CommandBar Name="cmdbarToolbar" RelativePanel.RightOf="btnNavigator">
                <AppBarButton Name="cmdbtnBack"  Icon="Back" Label="Back" />
                <AppBarButton Name="cmdbtnForward" Icon="Forward" Label="Forward"/>
                <AppBarSeparator Name="cmdsepNavigationCrud"></AppBarSeparator>
                <AppBarButton Name="cmdbtnRefresh" Icon="Refresh" Label="Refresh"/>
                <AppBarButton Name="cmdbtnClear" Icon="ClearSelection" Label="Clear"/>
                <AppBarButton Name="cmdbtnSave" Icon="Save"  Label="Save" />
                <AppBarButton Name="cmdbtnAdd" Icon="Add"  Label="Add" />
                <AppBarButton Name="cmdbtnEdit" Icon="Edit"  Label="Edit" />
                <AppBarButton Name="cmdbtnDelete" Icon="Delete" Label="Delete"/>
                <AppBarSeparator Name="cmdsepCrudCancel" ></AppBarSeparator>
                <AppBarButton Name="cmdbtnCancel" Icon="Cancel"  Label="Cancel"/>
            </CommandBar>
        </RelativePanel>
        <SplitView Name="spvwNavigator"
                    Grid.Row="1"  
                    DisplayMode="CompactOverlay"  
                    OpenPaneLength="200"  
                    CompactPaneLength="52"  
                    HorizontalAlignment="Left">
            <SplitView.Pane>
                <ListBox SelectionMode="Single"  
                          Name="lbNavigator">
                    <ListBoxItem Name="lbiHomePage">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontFamily="Segoe MDL2 Assets" FontSize="24" Margin="0,0,0,0" Text="&#xE10F;" />
                            <TextBlock Text="Home" FontSize="20" Margin="20,0,0,2" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem Name="lbiEventPage">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/Assets/EventIcon.png" Height="Auto" Width="24" Margin="0,0,0,0" HorizontalAlignment="Left"></Image>
                            <TextBlock Text="Event" FontSize="20" Margin="20,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem Name="lbiAboutPage">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontFamily="Segoe MDL2 Assets" FontSize="24" Margin="0,0,0,0" Text="&#xE171;" />
                            <TextBlock Text="About" FontSize="20" Margin="20,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem Name="lbiBuyPage">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontFamily="Segoe MDL2 Assets" FontSize="24" Margin="0,0,0,0" Text="&#xE719;" />
                            <TextBlock Text="Buy" FontSize="20" Margin="20,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                </ListBox>
            </SplitView.Pane>
            <SplitView.Content>
                <Frame Name="frmContent">
                </Frame>
            </SplitView.Content>
        </SplitView>
    </Grid>
</Page>

The XAML for the mobile’s MainPage is very similar. The risk with current approach is obliviously a lot of duplicated code, and I need to write more code before I really know the best way to design the views. A view per device family or many visual state triggers….

<Page
    x:Class="UWP.Prototype.Views.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:UWP.Prototype.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.BottomAppBar>
        <CommandBar Name="cmdbarToolbar" RelativePanel.RightOf="btnNavigator">
            <AppBarButton Name="cmdbtnSave" Icon="Save"  Label="Save" />
            <AppBarButton Name="cmdbtnAdd" Icon="Add"  Label="Add" />
            <AppBarButton Name="cmdbtnEdit" Icon="Edit"  Label="Edit" />
            <AppBarButton Name="cmdbtnDelete" Icon="Delete" Label="Delete"/>
            <AppBarButton Name="cmdbtnCancel" Icon="Cancel"  Label="Cancel"/>
        </CommandBar>
    </Page.BottomAppBar>

    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <RelativePanel Grid.Row="0" Background="LightGray">
            <Button Name="btnNavigator" 
                    Background="LightGray"
                    FontFamily="Segoe MDL2 Assets" 
                    Content="&#xE700;" 
                    FontSize="24"
                    Margin="0,0,0,0"
                    Click="btnNavigator_Click"
                    RelativePanel.AlignLeftWithPanel="True"></Button>
        </RelativePanel>
        <SplitView Name="spvwNavigator"  
                    Grid.Row="1"  
                    DisplayMode="Overlay"  
                    OpenPaneLength="200"  
                    CompactPaneLength="56"  
                    HorizontalAlignment="Left">
            <SplitView.Pane>
                <ListBox SelectionMode="Single"  
                          Name="lbNavigator">
                    <ListBoxItem Name="lbiHomePage">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontFamily="Segoe MDL2 Assets" FontSize="24" Margin="0,0,0,0" Text="&#xE10F;" />
                            <TextBlock Text="Home" FontSize="20" Margin="20,0,0,2" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem Name="lbiEventPage">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/Assets/EventIcon.png" Height="Auto" Width="24" Margin="0,0,0,0" HorizontalAlignment="Left"></Image>
                            <TextBlock Text="Event" FontSize="20" Margin="20,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem Name="lbiAboutPage">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontFamily="Segoe MDL2 Assets" FontSize="24" Margin="0,0,0,0" Text="&#xE171;" />
                            <TextBlock Text="About" FontSize="20" Margin="20,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem Name="lbiBuyPage">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock FontFamily="Segoe MDL2 Assets" FontSize="24" Margin="0,0,0,0" Text="&#xE719;" />
                            <TextBlock Text="Buy" FontSize="20" Margin="20,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                </ListBox>
            </SplitView.Pane>
            <SplitView.Content>
                <Frame Name="frmContent">
                </Frame>
            </SplitView.Content>
        </SplitView>
    </Grid>
</Page>

Mobilize.NET

From the build event earlier this year I heard about a tool, Mobilize.NET, too relieve the work load to migrate an app from Silverlight to UWP. There is a good web cast from channel 9 about it at https://channel9.msdn.com/Events/Build/2016/P498. I really liked the idea even though I suspected that the tool wouldn’t be able to convert so much of my app. But just to get some help with some well-known common tasks sounded very helpful. So I installed it and gave it a try.

There were many issues reported and it would take very long time to sort things out (if even doable). As I looked through the converted code I realized that I’m just trying to port the code. My current implementation is just intended as an app for windows phone. It’s not designed as a universal app capable of running on several different devices.

I wanted to change this! Instead of just porting my “windows phone 8.1-ish” user interface to the universal windows platform. I wanted to re-design it so it becomes “universal-ish” and able to run on several different devices, primarily desktops and phones. Also, cross-platform in the long run.

Didn’t get so much help from Mobilize.NET and now my next challenge is to find a universal user interface, easy to use, implement and maintain for all different kind of devices…. Let’s see what I will end up with.