Category: .Net

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 🙂

** Update : there is now also a new property ClearText that will show what you entered if needed

Most apps will have some kind of login feature, passing in credentials. Often this will be done with an Entry control set IsPassword to true.

But for a project we are working on, we needed a pin code entry… In other words, let the user see how many digits he has to enter and only allow numeric values.

So something like this:

To accomplish this, we created our own control. It’s a grid that will draw columns for the amount you’ve assigned to the PinLength property and it will add small dots and big dots. The big dots will become visible when the user enters digits.
Some other nice properties, you are able to hook up a Command that will be fired when the user has entered all required digits, this can be used to verify the pin.
The value of the pin is available in through the Input property.
There is also a Reset method to clear the input and redraw all small dots.

Example XAML usage:

C#

1

2

3

4

<controls:PinEntryx:Name="Pin"

PinLength="6"

Input="{Binding PinEntry, Mode=TwoWay}}"

Command="{Binding ValidatePinCommand}"/>

For now I’ve only added the iOS implementation, this because there is currently no easy way to auto show the keyboard on Android. But a work around is to draw your own keyboard on screen and hook up the Input property of the Pin control.

On a project I’m working on, we needed a label that would show an ellipsis at the end. ( the 3 … indicating there is more text but not enough space on the screen to fit it all )

Having this on a label control in Xamarin forms is easy, you just add the property

C#

1

<Label LineBreakMode="TailTruncation"/>

this will force the ellipsis to appear if needed.

But on a specific page we wanted to show more text to the end user and even than add an ellipsis if needed. So in other words we would love to be able to tell the label control how many lines it should at least try to display.
To get this working in Xamarin forms you’ll need to add a custom renderer. Because the Xamarin forms label control doesn’t have any property available for us to manipulate to accomplish this.

This is not difficult at all to do, but there is a small gotcha with Android when you want to pull this off!

But let’s start with what you need to do to get this working.
In the Xamarin forms PCL ( so the general one, not the iOS or Android project ), we first add a class called MultiLineLabel.cs – this will be our own custom control.
It inherits from Label and we only need to add 1 dependency property called Lines, defined as an int. It looks like this:

After defining this custom control, we can use it on our XAML page, like so:

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

<StackLayout>

<Label Text="NORMAL"FontSize="12"FontAttributes="Bold"/>

<Label Text="Welcome to Xamarin Forms! Let us try to create a label with text that is too long to fit on 1 line so it should wrap and implement an ellipsis if it's more than 2 lines in total"

VerticalOptions="Center"HorizontalOptions="Center"

LineBreakMode="TailTruncation"

Margin="20,0,20,0"/>

<Label Text="MULTILINE"FontSize="12"FontAttributes="Bold"/>

<controls:MultiLineLabel Text="Welcome to Xamarin Forms! Let us try to create a label with text that is too long to fit on 1 line so it should wrap and implement an ellipsis if it's more than 2 lines in total"

VerticalOptions="Center"HorizontalOptions="Center"

LineBreakMode="TailTruncation"

Margin="20,0,20,0"/>

<Label Text="MULTILINE - 2 lines"FontSize="12"FontAttributes="Bold"/>

<controls:MultiLineLabel Text="Welcome to Xamarin Forms! Let us try to create a label with text that is too long to fit on 1 line so it should wrap and implement an ellipsis if it's more than 2 lines in total"

VerticalOptions="Center"HorizontalOptions="Center"

LineBreakMode="TailTruncation"

Lines="2"

Margin="20,0,20,0"/>

<Label Text="MULTILINE - 3 lines"FontSize="12"FontAttributes="Bold"/>

<controls:MultiLineLabel Text="Welcome to Xamarin Forms! Let us try to create a label with text that is too long to fit on 1 line so it should wrap and implement an ellipsis if it's more than 2 lines in total"

VerticalOptions="Center"HorizontalOptions="Center"

LineBreakMode="TailTruncation"

Lines="3"

Margin="20,0,20,0"/>

</StackLayout>

We will be using this Lines property in our custom renderers.
First up the iOS custom renderer for our MultiLineLabel. Create a class in the Xamarin forms iOS project called CustomMultiLineLabelRenderer.cs with following code:

You’ll notice that we are checking if the user specified a value for the Lines dependency property and if this is true, we pass this to the actual iOS UIKit.UILabel control by setting it’s Lines property. With this in place we get following result.

So iOS is done and looking great. Now add the Android renderer. Create a CustomMultiLineLabelRenderer.cs class in the Xamarin forms Android project with following code:

This doesn’t look all that different from the iOS counterpart… instead of setting a property we now use a method SetLines on the Android.Widget.TextView indicating how many lines we want it to display.
But wait, if we try this and look at the result, we’ll notice that it doesn’t work!!

Yeah success!
To start I’ve done a pull request on Xamarin forms to counter this SingleLine forcing, but not sure this will be added though… https://github.com/xamarin/Xamarin.Forms/pull/234
So better be safe and add the extra line in your own custom renderer for now.

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 :

On a current Xamarin forms project I’m working on, there came the question if it would be possible to show 2 lines in the title bar of our app instead of 1.
Normally this is not something you would do, seeing the default behaviour on iOS and Android, an app would only display 1 line and cut if off by adding ‘…’.

But in our case we are showing detail information on a conversation and it would help the user if we could show some more context.

The goal would be like this:

To achieve this result, you’ll need to implement a custom renderer on each platform. Both on iOS and Android of the type PageRenderer.

First iOS.
In your Xamarin Forms solution, underneath the iOS project add a folder called CustomRenderers and add a class called CustomContentPageRenderer.cs.
Here we will implement a PageRenderer with following code

//Be sure to set the Frame to 'something' other than the default 0,0,0,0 otherwise you won't see anything!

titleLabel.Frame=newCoreGraphics.CGRect(0,0,1,1);

titleLabel.SizeToFit();

parent.NavigationItem.TitleView=titleLabel;

}

}

}

Inside the WillMoveToParentViewController method we will grab the current page and see if it does contain an actual Title ( not each page needs one ).
If so, we’ll new up an UILabel because with this iOS control we can set how many lines need to be used ( if needed ) : titleLabel.Lines = 2.
We must ofcourse not forget to pass the current page title to it and only thing left afterwards is placing this UILabel in the TitleView of the current navigation page : parent.NavigationItem.TitleView = titleLabel.

By doing this we will override the normal Xamarin Forms rendering of the title in a navigation page and allowing use of 2 lines in it!

Secondly Android.
Same setup as in iOS, so a CustomRenderers folder with a CustomContentPageRenderer class file. But there is a bit more code needed for this to work now…

You’ll see now that we are using the OnElementChanged method to do almost the same as in iOS. So again check if the actual page does have a title or not and when it does, create a new TextView element.
On this Android control we can also indicate that we want to use 2 lines is needed : title.SetMaxLines(2).
And also here we need to pass in the actual page title and adjust the default Xamarin forms rendering view : actionBar.SetCustomView (title, new ActionBar.LayoutParams (LayoutParams.MatchParent, LayoutParams.MatchParent)).

What is different on Android, is that the ActionBar ( where the title is shown ) is shared across all pages. Thus once you’ve manipulated it, it will be fixed for all.
Meaning that when you have navigation and go back in the navigation stack, you’ll see that the set title will no longer change!
To counter this, we’ll need to hook into another event to keep track of this back stack navigation and if needed reapply the title.
This is done by monitoring the Element.Appearing event and when we enter this, reset the page title : ((TextView)actionBar.CustomView).Text = page.Title.

Hope this makes some sense and can help those out there that do need this feature 🙂

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.

Sometimes you like to present a list of items to the user. But the requirements for that list are so, that it must remain compact, wrap at the screen edge and editable in that sense that you can remove items quickly.
This kind of list is often represented by tags, so how do you do this in an universal app, let me show you how!

First thing that is very important to note, is the fact that we will be using a RichTextBlock with an InlineUIContainer. We do this, because the RichTextBlock handles the screen wrapping/overflow! That will enable us to add tags and each time a new one is added to the list, the RichtTextBlock will validate if it will still fit the current line, if not it will add a new line and wrap.

And to be honest that’s it! Only thing left to do is add the real tags, that are actual Buttons inside the InlineUIContainer. In the current demo application I’m doing this in the code behind of the MainPage file, there is a method called SetTags.

Again a bit the same concept as the removal. For each tag not yet in the current tag list, we create a new button with a specific style and add a click handler that will enable the removal. Once that button is created we add it to the RichTextBlock InlineUIContainer so it will show up on screen.

When the user presses the tag, the click event will fire an the selected tag will be removed from the list.