Tag: UWP

When UWP comes into play with Xamarin Forms, you’ll notice that several default control settings are often not resulting in a pleasing UI.

One that caught my eye recently was the way the height is set in a grouped lisview header.
So assume following setup, you define a listview and enable grouping. With that you would like to control what is being shown in the header, so you define your own GroupHeader Template. Inside the template, you only need a small display area, so for demo purpose we will only enable a Label control, but are setting it’s height to a fix amount of 25!
Complete XAML look like this:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<ListViewx:Name="ItemsListView"

ItemsSource="{Binding Items}"

VerticalOptions="FillAndExpand"

HasUnevenRows="true"

RefreshCommand="{Binding LoadItemsCommand}"

IsPullToRefreshEnabled="true"

IsRefreshing="{Binding IsBusy, Mode=OneWay}"

IsGroupingEnabled="True"

CachingStrategy="RecycleElement"

ItemSelected="OnItemSelected">

<ListView.GroupHeaderTemplate>

<DataTemplate>

<ViewCell Height="25">

<StackLayout HeightRequest="25"BackgroundColor="Lime">

<Label Text="HEADER"Margin="5,0,0,0"/>

</StackLayout>

</ViewCell>

</DataTemplate>

</ListView.GroupHeaderTemplate>

<ListView.ItemTemplate>

<DataTemplate>

<ViewCell>

<StackLayout Padding="5"BackgroundColor="Yellow">

<Label Text="{Binding Text}"

LineBreakMode="NoWrap"

Style="{DynamicResource ListItemTextStyle}"

FontSize="16"/>

<Label Text="{Binding Description}"

LineBreakMode="NoWrap"

Style="{DynamicResource ListItemDetailTextStyle}"

FontSize="13"/>

</StackLayout>

</ViewCell>

</DataTemplate>

</ListView.ItemTemplate>

</ListView>

When this is done you’ll get the following layout on iOS ( I added background colours to show off the different templates and their heights ).

So everything is looking ok in reference to what we defined in XAML, but now let’s look at UWP…

Well this is odd! Somehow the height of our headers is larger than what we defined… looks like UWP has some default rendering that overrides what we have set.
So after some digging through the source code of Xamarin forms, I’ve not found any special setting that could trigger this. In other words it’s not something Xamarin does to the UWP rendering of the listview.
This meant I needed to go look at the default template settings of the UWP control itself. What I found was that the listview control has a special header template style defined that uses a specific value for the minimum height for the ListViewHeaderItemMinHeight!
It’s set to 44… this explains our weird look and feel on UWP.

With this in mind it’s actually very easy to fix this in our app. All we need to do is provide a better minimum height value for the given style key.
When using UWP in Xamarin forms, you do this sort of overrides inside your App.xaml file by defining a theme resource dictionary and adding the same key like so:

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<Application

x:Class="App1.UWP.App"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="using:App1.UWP"

RequestedTheme="Light">

<Application.Resources>

<ResourceDictionary>

<ResourceDictionary.ThemeDictionaries>

<ResourceDictionaryx:Key="Default">

<x:Doublex:Key="ListViewHeaderItemMinHeight">1</x:Double>

</ResourceDictionary>

</ResourceDictionary.ThemeDictionaries>

</ResourceDictionary>

</Application.Resources>

</Application>

With this in place our UI will finally look like the same as the iOS counterpart.

When developing cross platform apps with Xamarin forms, you’ll notice that your apps will look and feel right at home on each OS. This because the nice people of Xamarin render each Xamarin forms control as a native control with the needed control properties all filled in.
You can still tweak some of these properties when they are leveraged through the Xamarin forms control abstraction or use custom renderers and effects to get down to the native control layer.

Most of the time this is all working great, but when you try to take UWP into account, you’ll notice not everything works straight out of the box.
Hence this blog post, showing you how you can hack the current TabbedPage implementation of Xamarin forms for UWP to enable pivot headers with images!

If you’ll use following XAML in Xamarin forms, you’ll get a nice Pivot control in UWP

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"

xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

xmlns:local="clr-namespace:TabbedPage"

x:Class="TabbedPage.MainPage">

<NavigationPage Title="Schedule 1"Icon="first.png">

<x:Arguments>

<local:SchedulePage/>

</x:Arguments>

</NavigationPage>

<NavigationPage Title="Schedule 2"Icon="second.png">

<x:Arguments>

<local:SchedulePage/>

</x:Arguments>

</NavigationPage>

</TabbedPage>

But when you run the app, you’ll notice that on UWP nothing is happening with the Icon property of the NavigationPage

While on iOS you’ll get something like this

So what gives? Well, the current Xamarin forms tabbed page implementation will not take into account this Icon property and ignore it during rendering.
Reading the guidelines from Microsoft, it’s recommended to actually do use icons for pivot headers if possible, read on it here https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tabs-pivot.
The result should be something like this

Now let me show you a hack / workaround to get the same result on UWP. I stress hack, because of the current TabbedPage implementation in Xamarin forms there is no direct way to handle this.

To create a working solution, we need to change the HeaderTemplate that is specified inside that TabbedPageStyle. Normally we would just drop in a new Style with the same name inside our UWP App.Xaml file to override the one from Xamarin forms. But due to how Xamarin forms is initialised during startup this won’t work. So a small interception has to be made to get this going.

Add a new Styles.Xaml file in your UWP project and add following Style element to it

This will enable the use of the Icon property that we have set in our Xamarin forms xaml for each tab of the tabbedPage. Only thing left is swapping out the current HeaderTemplate and using ours.
So be sure to tell UWP we have this Style in our ResourceDictionary by adding it in the App.Xaml

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<Application

x:Class="TabbedPage.UWP.App"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="using:TabbedPage.UWP"

RequestedTheme="Light">

<Application.Resources>

<ResourceDictionary>

<ResourceDictionary.MergedDictionaries>

<ResourceDictionary Source="Styles.xaml"/>

</ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

</Application.Resources>

</Application>

After that, open up the App.Xaml.cs file and look for the Xamarin.Forms.Forms.Init(e); line.
Below it add an extra line of code to do the actual Template swapping

Like I said this is a hack… but it works perfectly 🙂 instead of using the default Xamarin forms TabbedPageStyle inside the Pivot header template we’ll now be using our own TabbedPageStyle2.
Only one small detail remains, you’ll notice I added a converter inside the Style. This was needed because the Icon property on the NavigationPage of Xamarin forms maps to a FileImageSource but that is not processable straight away as a source value for the Image control inside UWP.

The converter will get the File property of the FileImageSource and return that as a valid source. With this in place you’ll get the correct image shown!

So, been seeing a lot of SVG support being introduced into UWP to get vector images. I love this evolution, but somehow I still love how fonts work and mostly I still go that route if I need some icon representation inside an UWP app.
Fonts also easily scale, by setting the font size, what often results in better outlining with text being set on the same size! Adding color is also no problem and depending on what library you are using there is often also a full filled version as an outlined version available for a given icon.

So let me show you this alternative way on how you can use a great open source icon library to good use inside your UWP apps, through their available font.

First up go to this great icon library called Material Design Icons, here select the Download button and in the popup window select the Download the webfont button. This will contain the materialdesignicons-webfont.ttf that we will use in our UWP app.
To use it in your app, place the TTF inside your Assets folder.

Now that you have the font as an asset, you’ll still need to enable its usage in xaml. To do this, we’ll first add a reference to the font in a ResourceDictionary.
Add following entry in your resource dictionary :

Now that the style is available for any TextBlock you want to use, we can add those in our UI.
For example if you want to add an expand symbol to an image to indicate the user can enlarge it, we just select a good icon from the font and place a TextBlock inside a button on the image.
Now the most difficult part is actually getting hold of the actual text representing a given icon.
To get this, you’ll need to install the TTF in windows ( right click on the font and select install ) and use the Windows Character Map tool to copy the value.

Select a given icon and press copy to get hold of the actual value

Only thing left to do is define an button and add a TextBlock to it with the font value.
Note : in the code preview below this will not be shown because the font value can not be rendered. But inside visual studio you will see a ? representation.

So by now most people will know that I’m ‘still’ busy creating a Strava app for UWP called Kliva ( yes it is Open Source here… ).
Now the main purpose for using UWP was the fact that we could create 1 app that can be used on desktop/tablet pc’s and mobile phones!
Thanks to the new way of using Visual States in XAML we can tweak our design like we want depending on the size of the screen real estate.

All fine and dandy, but depending on the form factor it could also be that we need to navigate in a different way, Microsoft illustrated this by defining a Stacked Pattern and a Side-by-side pattern.Read up on all the details here…

Now how can we as devs handle this difference in navigation? Well let me show you how we handled it in Kliva.

You’ll notice we do 2 things here, enable a Loading mode if needed and when a page is Navigated we trigger some code in a ViewModel.
Let’s deconstuct this later, I’ll first show you the actual frame setup…

So our frame will always consist of a SplitView control and the actual pages of our app will be rendered inside the SplitView.Content part!
We are using the SplitView control for the Side-by-side pattern reason, we will however need to adjust this in mobile mode, again more on this later 🙂 ( yep going to be a long post )

More importantly, we are now able to sneak in a full app wide loading overlay control. In other words, each time when needed, we will present an overlay with a progress ring, to indicate the app is still processing. By putting it here, inside the boilerplate code of the ApplicationFrame, it is available for all pages in the app!
Remember the code in the KlivaApplicationFrame? There is a method called ShowLoading(bool isLoading), this will put the Loading Grid in the correct VisualState ensuring it is visible or not and will also trigger the progress ring ( inside the LoadingControl ) to start.
The loading control itself is a user control that is nothing more than some text and a progress ring as show below…

We added the IsLoading property, so we can access it in our XAML – like we do in the VisualStates of the KlivaApplicationFrame.
But we also added a static method SetLoading(bool isLoading), we need this so that we can trigger the whole process of actually showing the control to the user!
In Kliva we let all our ViewModels inherit from a BaseViewModel and inside this one, we will call upon this static SetLoading method each time we think our app will need some time processing web requests.

So from a developer standpoint, each time you manipulate the IsBusy propety on the base viewmodel, our Loading Control will be shown to the user.
If you don’t like the ‘link’ between the ViewModel and the actual control, you could also work with MVVM messaging instead. No need for a static method that way, but hey we can’t always be 100% MVVM, right? 😉

Back to solving the mobile view, because you’ll remember that our original setup uses a SplitView and on mobile we want to shift this to actually using a BottomAppBar. To achieve this we need 2 things, hide the SplitView.Pane and showing the BottomAppBar.
Showing the bottom app bar is not that hard! We just check for the correct view size in our VisualStates and if needed toggle it’s visibility property depending on how large the screen actually is. From 320 to 720 we show it, everything above 720, we hide it.

Hiding the SplitView.Pane will need some coding… First part of this was already shown in our KlivaApplicationFrame, there when we navigate to a page we call upon the ShowHide method of the SidePaneViewModel.
This ViewModel is linked to the SidePane Control that is used inside the SplitView.Pane. We use several properties of this viewmodel on our SplitView properties, like the DisplayMode and IsPaneOpen ( cfr XAML code of our KlivaApplicationFrame ).
When we don’t need the SidePane of our SplitView, we set the DisplayMode to Inline and IsPaneOpen to false, if we do need the SidePane, we put the DisplayMode into CompactOverlay. That way, if on mobile, we can hide it and on desktop show it again.
We also extended the method a bit, so that we can hide the side pane on a given type of page, if needed ( currently not used )

Last but not least, we still need to find a way to adjust for page navigation or not. In our case, our main page will show a list of activities and when selecting one, present the details of that activity.
In a side-by-side pattern the details of the activity is on the right side of the list, in a stack pattern we need to navigate to the details page.

The side-by-side way is very easy, we put 2 controls in our main page, the first one contains the lists, the second one the detail info. Each of these controls are bound to the same ViewModel. So when an user selects an item from the list we will fill in the SelectedItem property on our ViewModel and our detail control will automatically show this.
But for the stacked pattern we add a bit of extra code, first again thanks to use of the VisualStates we will hide the detail control and secondly in our SelectedItem invocation we will try to start a page navigation if we are on mobile.
Not rocket science, just a little tweaking 🙂

So imaging you have this great looking layout in your UWP app, all set up with the new guidelines.
Meaning a side bar for navigation and a master detail section, that will dynamically change when you don’t have enough space to fit and master and detail.

We are talking about this layout:

But of course like in most other apps, you want to enable some filtering on the content. That way the user can find the items that are more important to him… So for UWP there is a wonderful control that has all the needed qualities for such a feature; the MenuFlyout !
Now if you add this control, as is, it will only render itself in a certain width and height depending on the content that it contains. Meaning that most of the time, it will look tiny and out of place with the rest of the visual elements.
Here is a Phone screenshot example : notice how the flyout hovers above the side pane and it’s width is only calculated to it’s content

What we would love to have, is a Flyout that takes up the full width size of the parent control it’s contained in… in other words in our example, have an equal width to the column that hosts the item list.
Let me show you how you can accomplish this.

First up, create this nice triple design, by using the new SplitView control, this will give you the side pane. Of course you’ll still need to add 2 columns to host the list and the detail content.
We’ll use the new Visual State Manager settings style to change the layout if we use the app on smaller screens!
Do note we are using a button with an empty button style to render the text for filter selection and a FlyoutMenu is attatched to that button. They are contained in the MasterColumn

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

<SplitView.Content>

<UserControl>

<Gridx:Name="LayoutRoot"

Loaded="OnLayoutRootLoaded">

<VisualStateManager.VisualStateGroups>

<VisualStateGroupx:Name="AdaptiveStates"

CurrentStateChanged="OnAdaptiveStatesCurrentStateChanged">

<VisualStatex:Name="Mobile">

<VisualState.StateTriggers>

<AdaptiveTrigger MinWindowWidth="0"/>

</VisualState.StateTriggers>

<VisualState.Setters>

<Setter Target="MasterColumn.Width"Value="*"/>

<Setter Target="DetailColumn.Width"Value="0"/>

<Setter Target="MasterListView.SelectionMode"Value="None"/>

</VisualState.Setters>

</VisualState>

<VisualStatex:Name="Desktop">

<VisualState.StateTriggers>

<AdaptiveTrigger MinWindowWidth="720"/>

</VisualState.StateTriggers>

<VisualState.Setters>

<Setter Target="MasterColumn.Width"Value="*"/>

<Setter Target="DetailColumn.Width"Value="1.8*"/>

</VisualState.Setters>

</VisualState>

</VisualStateGroup>

</VisualStateManager.VisualStateGroups>

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinitionx:Name="MasterColumn"/>

<ColumnDefinitionx:Name="DetailColumn"/>

</Grid.ColumnDefinitions>

<Buttonx:Name="FilterButton"

Style="{StaticResource EmptyButtonStyle}"

Content="Showing all items"

Margin="10,5,0,10"

Grid.Row="0"

Grid.Column="0"FontWeight="Bold">

<Button.Flyout>

<MenuFlyoutx:Name="FilterFlyout"Opened="OnFilterFlyoutOpened">

<MenuFlyoutItem Text="all items"/>

<MenuFlyoutItem Text="my items"/>

<MenuFlyoutItem Text="friends' items"/>

</MenuFlyout>

</Button.Flyout>

</Button>

<ListViewx:Name="MasterListView"

Grid.Row="1"Grid.Column="0"

ItemContainerTransitions="{x:Null}"

ItemTemplate="{StaticResource MasterListViewItemTemplate}"

IsItemClickEnabled="True"

ItemClick="OnMasterListViewItemClick">

<ListView.ItemContainerStyle>

<Style TargetType="ListViewItem">

<Setter Property="HorizontalContentAlignment"Value="Stretch"/>

</Style>

</ListView.ItemContainerStyle>

</ListView>

<ContentPresenterx:Name="DetailContentPresenter"

Grid.Column="1"

Grid.RowSpan="2"

BorderThickness="1,0,0,0"

Padding="24,0"

BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"

Content="{x:Bind MasterListView.SelectedItem, Mode=OneWay}"

ContentTemplate="{StaticResource DetailContentTemplate}">

<ContentPresenter.ContentTransitions>

<!--Empty by default.See MasterListView_ItemClick-->

<TransitionCollection/>

</ContentPresenter.ContentTransitions>

</ContentPresenter>

</Grid>

</UserControl>

</SplitView.Content>

</SplitView>

Now that we have this all setup up, only thing left to do is calculate the actual width of the MasterColumn and use that to change the size of the flyout. But also take into account the side pane width to shit the flyout in place.
We will recalculate each time the flyout opens, because the app could be resized by the user before the flyout is actually opened.
So you’ll see a handler hooked up called for the Opened event called OnFilterFlyoutOpened with following code

The trick here is to change the MenuFlyoutPresenterStyle, with that style we can apply a minimum width to the actual flyout. That width should be equal to the width of the Master column…
We also apply some margin to compensate for the side pane.
By doing all this we now get following nice result :

Using a Flyout control in an UWP app is super handy to show contextual actions, but somehow they aren’t very MVVM friendly.
It was easier during windows 8.1 days, but with UWP it’s a hassle.

I’ve seen many solutions on how to tackle this problem, but let you give me mine just to show some other angles.
I’m trying to use the new UWP XamlBehaviors that went Open Source a while back, for all the info take a look here https://github.com/Microsoft/XamlBehaviors.

So the setup, we have a page that has a button – that button will open a flyout. On this flyout we have another button that will trigger some long running process in MVVM ( it’s not in this demo 😛 ).
What we want to do is dismiss the flyout from our MVVM if the process is done.

Some things to note… We are using a MVVM command through binding for the button that is shown on the flyout.
The other thing, is the DataTriggerBehavior! It’s one of the behavior types that is available through the XamlBehaviors and what it allows us to do is perform some action when some data element changes to a certain value.
Here we are monitoring the IsFlyoutClosed boolean of our MVVM ViewModel to see when it’s being set to True. If this happens, we’ll perform an action called CloseFlyoutAction.
This action is a custom one and it’s purpose is to close the current given Flyout, as shown in the code below.

C#

1

2

3

4

5

6

7

8

9

10

publicclassCloseFlyoutAction:DependencyObject,IAction

{

publicobjectExecute(objectsender,objectparameter)

{

varflyout=sender asFlyout;

flyout?.Hide();

returnnull;

}

}

And that’s it… only thing left to do is manipulate the boolean on the ViewModel when you want to close the flyout.

All good and well, but what when we want to use this setup in our cross platform environment? In other words what do we need to do in our UWP project when we are building it using Xamarin and MvvmCross? For reference we are talking about using a PCL project ( for cross platform use ) and a UWP native project using that PCL, all wired up with MvvmCross.
The basis of this setup came from this blogpost: http://stephanvs.com/implementing-a-multi-region-presenter-for-windows-10-uwp-and-mvvmcross/

We’ll only be focussing on the UWP part, because setting up MvvmCross should be ok for people who know MvvmCross 🙂
When your project is created, we’ll set up a main page where we implement our SplitView.
I’ve added a FirstView and it inherits from MvxWindowsPage, it contains the SplitView with a Frame in the content part. Import thing to note here is that we are providing a name for the Frame, called FrameContent, this will define our MultiRegion.

C#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<SplitViewx:Name="RootSplitView"

DisplayMode="Inline"

OpenPaneLength="256"

IsTabStop="False">

<SplitView.Pane>

<StackPanel Margin="0,50,0,0">

<Button Content="Second"Command="{x:Bind Vm.SecondCommand}"/>

<Button Content="Third"Command="{x:Bind Vm.ThirdCommand}"/>

</StackPanel>

</SplitView.Pane>

<!--OnNavigatingToPage we synchronize the selected item inthe nav menu with the current page.

OnNavigatedToPage we move keyboard focus to the first item on the page after it'sloaded and update the Back button.-->

<Framex:Name="FrameContent">

<Frame.ContentTransitions>

<TransitionCollection>

<NavigationThemeTransition>

<NavigationThemeTransition.DefaultNavigationTransitionInfo>

<EntranceNavigationTransitionInfo/>

</NavigationThemeTransition.DefaultNavigationTransitionInfo>

</NavigationThemeTransition>

</TransitionCollection>

</Frame.ContentTransitions>

</Frame>

</SplitView>

Nothing fancy so far. But in the code behind of this View we need to add a property called AppFrame, because that will be used later on to enable the page loading in the defined frame. So just add the following in the code behind:

Now for the actual page loading, we will need to override the View Presenter creation of MvvmCross, this is done in the Setup.cs of the UWP project. Because instead of creating normal MvvmCross views, we need a MultiRegionView.
So add the following override in your Setup.cs file:

Last thing to do is indicate what views need to be loaded inside the frame, you do this by adding a MvvmCross attribute above your View definition. So if I want SecondView to be loaded in the region, I just add the following above the class definition of the view in code behind:

C#

1

[MvxRegion("FrameContent")]

This will tell MvvmCross to load the complete view in a Region called FrameContent and like we said earlier, this is the name of our Frame we definied in our FirstView.
Now each time when you navigate to this view by using the MvvmCross viewmodel navigation, it will be shown inside the frame of your SplitView!

Well I’m only just getting started with an UWP windows 10 project, so naturally I guessed I would hit some bumps on the road.
But the real first problem I got, was not an easy one to solve. The fix is easy, but I couldn’t wrap my head around it at first…

So hence this blogpost so maybe others could benefit from it.
Thanks to Scott Lovegrove for helping and testing this…

So what did I want to do, I wanted to change the background of the root grid of a XAML View depending on the Size of the page ( or depending on the Device Family that was viewing the page ).
First can be done with the new Adaptive triggers, second one can be done with a Custom trigger : look at Morten Nielsen his lib on Github.

But got no result, same thing with the Device Family trigger!
I then contacted Scott to see if he had an angle I didn’t try and together we tried several other Setters.
Like using other uri’s for the Value like: ms-appx:///Assets/White-Wallpaper-Windows-10-HD.jpg and other bindings for the Target like: LayoutRoot.(Grid.Background)

But all without luck, even contacted Morten to see if debugging the custom trigger would help. But nothing seemed to work out.

Until it hit me, maybe we can’t deep link Targets… so I changed the code to following

Scott has a valid point, that the inner workings of the triggers is trying to map it to the real object and that can be very different then what we put in our XAML. So some internal conversion could be missing when using triggers.