Cimbalino Toolkit 2.4.0

I know the blog as been quite a bit quiet for the last couple of months, but I just wanted to let you know that Cimbalino Toolkit version 2.4.0 is now available!

As I didn’t put a blog post for the previous version, here’s the complete change log for everything since 2.2.0 till the current 2.4.0:

  • Now targeting SDK 14393 (Windows 10 Anniversary edition)
  • New MasterDetailView control (UWP only)
  • New ExtendedPageBase class, IHandleNavigatingFrom, IHandleNavigatedFrom and IHandleNavigatedTo interfaces (allows handling of Page.OnNavigatingFrom(), Page.OnNavigatedFrom() and Page.OnNavigatedTo() methods from inside view models)
  • New BooleanToObjectConverter, CollectionCountToObjectConverter, ComparableToObjectConverter, EmptyCollectionToObjectConverter, and EmptyStringToObjectConverter
  • Added CancellationToken support to IMessageBoxService and ILocationService
  • HamburgerMenuButton will now allow parameter check for button highlighting
  • Improvements over the INavigationService interface and implementation
  • Other fixes and improvements

Cimbalino Toolkit 2.2.0

Update: there was a packaging error in 2.2.0 which I already fixed and so the most current version is now 2.2.1!

Cimbalino Toolkit version 2.2.0 is now available!

This new version includes improved support for Windows Phone Silverlight 8.1 (WP81) so that developers can take advantage of its specific API’s (such as the FileOpenPicker)

This brings the total number of supported platforms to 5:

  • Windows Phone Silverlight 8.0 apps (WP8)
  • Windows Phone Silverlight 8.1 apps (WP81)
  • Windows Phone 8.1 apps (WPA81)
  • Windows Store 8.1 apps (Win81)
  • Windows 10 UWP apps (UAP)

Here’s the full change log for version 2.0.0:

  • Improved compatibility with Windows Phone Silverlight 8.1 (WP81)
  • New Cimbalino.Toolkit.Controls library (includes the HamburgerFrame for Windows 10)
  • New IFilePickerService to handle the file picker (when available)
  • Improvements over the INavigationService implementation
  • Other fixes and improvements

Cimbalino Toolkit Hamburger controls for UWP

Like it or not, the so called “Hamburger” design pattern has made its way to pretty much every platform, including the Windows Universal Apps!

Most Windows 10 native apps already show this new pattern, even a classic like the Calculator app!

However, for reasons unknown, Microsoft didn’t provide any Hamburger related control on the SDK base controls… frankly, this move brings back to memory when Windows Phone 7 SDK was launched without the Panorama and Pivot controls, the foundation of the whole “Metro” design guidelines!

The only alternative I’ve found is to use the Template 10, a “set of Visual Studio project templates”!

However, I’ve found that Template 10 version for Hamburger adds a bit of too much “fat” for my own taste, hence why I’ve been working on an alternative for the past last few weeks!

Introducing the Cimbalino Toolkit Controls

Starting with version 2.2.0 (currently still in beta 1), the Cimbalino Toolkit will feature a new package called Cimbalino.Toolkit.Control, and as the name suggests, it’s a control library for app developers.

Currently, the package features 3 controls:

  • HamburgerFrame
  • HamburgerTitleBar
  • HamburgerMenuButton

HamburgerFrame

Starting from the top, the HamburgerFrame control is a full replacement for the native Frame root control used in the app.xaml.cs file.

The control provides 3 content containers represented by the Header, SubHeader, and Pane properties, and on the center, it will show the navigated content:

HamburgerFrame container thumb

Obviously, you can specify content for this containers however you would like, or just leave them blank!

The Header allows content to be presented above the Pane, so it will never be hidden by it:

HamburgerFrame container thumb

The SubHeader allows content to be presented on the right side of the Pane. This means that if the pane is in one of the “overflow” modes it will show on top of this container, hiding the content behind it:

HamburgerFrame container thumb

The control also provides background properties for all these containers (HeaderBackground, SubHeaderBackground, and PaneBackground).

To make the life easier of developers, I’ve “borrowed” the VisualStateNarrowMinWidth, VisualStateNormalMinWidth, and VisualStateWideMinWidth properties from Template 10, which allow to specify the break points where the pane state and location will readjust. If you don’t want to use these, you can always do it manually with the exposed pane related properties (IsPaneOpen, DisplayMode, OpenPaneLength, CompactPaneLength, …).

HamburgerTitleBar

The HamburgerTitleBar control provides a basic Hamburger button on the left side (can be hidden with the MenuButtonVisibility property), and a Title property.

HamburgerTitleBar

This is a quite rudimentar and easy to use control, yet developers might want to just go ahead and create their own version of this control and place it on their apps!

HamburgerMenuButton

Finally, the HamburgerMenuButton is the button you’ll be using in the pane to indicate the available menu options!

This control shows a left-side icon and an optional label (through the Icon and Content properties):

HamburgerMenuButton basic states

The regular approach here will be to just place all the HamburgerMenuButton controls inside a vertical StackPanel, but one can also stack them horizontally, and in this case, we would only show the icon and hide the label (using the provided LabelVisibility property).

The NavigationSourcePageType property allow developers to specify the destination page type for navigation purposes. If the property is set, the button will automatically highlight anytime the page is the frame current navigation content.

So how can I use these in my app?

First step is to add the Cimbalino.Toolkit.Controls NuGet package to the project!

Then, create a new user control to define your menu; in it, add as many HamburgerMenuButton instances as the number of options you want to present!

Here’s how your menu might look like:

<UserControl x:Class="App1.View.HamburgerPaneControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:controls="using:Cimbalino.Toolkit.Controls"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:view="using:App1.View"
             d:DesignHeight="300"
             d:DesignWidth="400"
             mc:Ignorable="d">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <StackPanel>
            <controls:HamburgerMenuButton Content="Home" NavigationSourcePageType="view:MainPage">
                <controls:HamburgerMenuButton.Icon>
                    <FontIcon FontSize="16" Glyph="& #xE80F;" />
                </controls:HamburgerMenuButton.Icon>
            </controls:HamburgerMenuButton>

            <controls:HamburgerMenuButton Content="Details" NavigationSourcePageType="view:DetailsPage">
                <controls:HamburgerMenuButton.Icon>
                    <FontIcon FontSize="16" Glyph="& #xE8BC;" />
                </controls:HamburgerMenuButton.Icon>
            </controls:HamburgerMenuButton>
        </StackPanel>

        <controls:HamburgerMenuButton Grid.Row="1"
                                  Content="Settings"
                                  NavigationSourcePageType="view:SettingsPage">
            <controls:HamburgerMenuButton.Icon>
                <FontIcon FontSize="16" Glyph="& #xE713;" />
            </controls:HamburgerMenuButton.Icon>
        </controls:HamburgerMenuButton>
    </Grid>
</UserControl>

Next, open the app.xaml.cs file and replace this line:

rootFrame = new Frame();

with this:

rootFrame = new Cimbalino.Toolkit.Controls.HamburgerFrame()
{
    Header = new Cimbalino.Toolkit.Controls.HamburgerTitleBar()
    {
        Title = "App1"
    },
    Pane = new View.HamburgerPaneControl()
}

Congratulation: your app now has a universal Hamburger menu with a nice title bar! 🙂

App with HamburgerFrame

Next steps might be to create a separate user control to hold the HamburgerTitleBar, which will then allow you to bind the Title property to view model (making it easier to update on a page by page basis).

To make things easier, I’ve provided the source code for a simple app using these controls!

XAML Behaviors now open source and on UWP

In case you missed the big news, the XAML Behaviors are now open source in GitHub and available to use in UWP, both in managed and native apps, mostly due to the work of some awesome MVPs!

They were kind enough to keep me in the loop and that allowed me to prepare for the incoming changes! 😉

Cimbalino Toolkit 2.1.0

Version 2.1.0 of the Cimbalino Toolkit is a basic update of the toolkit with a few improvements and bug fixes, but takes into account the new XAML Behaviors:

  • UWP apps it now will pull the XAML Behaviors Managed NuGet package to the projects
  • non-UWP apps will still use the NuGet PowerShell scripts to add the Behaviors SDK

A few weeks ago I introduced the MonitoredInteraction class from Cimbalino Toolkit 2.0.0 to “prevent memory leaks in behaviors”, and I’m happy to say that those changes made it’s way to the XAML Behaviors code! 🙂

Do notice that while the Interaction class in the XAML Behaviors now performs the proper attach/detach pattern, the same can’t be said for the Behaviors SDK Extension for non-UWP apps, so I strongly advise you to keep using the MonitoredInteraction class for those projects!

One final note: if you actually want to use the XAML Behaviours, you will have to actually manually add the NuGet package to your project… this is due to the new Transitive Dependencies feature of NuGet 3.x, and as far as I know, there is no way of going around this extra step!

How to prevent memory leaks in Behaviors

Attached Behaviors have been around for quite a while, and though I personally always liked them, they have a fundamental flaw: they can lead to huge memory leaks!

I’ve seen quite a few fixes for them (like this one from MVP Joost Van Schaik), though none proved to be truly “universal” and final!

To demonstrate the problem, let’s take a practical example:
– create an app with two pages
– page 1 will have a button to navigate to page 2
– page 2 will have a button that when clicked, will navigate back to page 1 after a pause of 2 seconds

Here’s the view model for page 2, Page2ViewModel:

public class Page2ViewModel
{
    public event EventHandler GoBack;

    public ICommand DelayedGoBackCommand { get; private set; }

    public MainViewModel()
    {
        DelayedGoBackCommand = new CustomCommand(OnDelayedGoBackCommand);
    }

    private async void OnDelayedGoBackCommand()
    {
        await Task.Delay(2000);

        GoBack?.Invoke(this, EventArgs.Empty);
    }
}

The code is really simple: when the DelayedGoBackCommand gets invoked, we will make a 2 seconds pause, and then raise the GoBack event.

Now lets say that all view models have been registered as singletons in the App class, something like this:

sealed partial class App : Application
{
    public static Page2ViewModel Page2ViewModel { get; } = new Page2ViewModel();

    // remaining code
}

This is the code behind for page 2, where we will set the page view model:

public class Page2
{
    public Page2()
    {
        InitializeComponent();

        DataContext = App.Page2ViewModel;
    }
}

And this is the view we will be using for page 2:

<Page x:Class="MyApp.Page2"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:core="using:Microsoft.Xaml.Interactions.Core"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:i="using:Microsoft.Xaml.Interactivity"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      x:Name="PageRoot"
      mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <i:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="GoBack"
                                       SourceObject="{Binding}">
                <core:CallMethodAction MethodName="GoBack"
                                       TargetObject="{Binding Frame,
                                                              ElementName=PageRoot}" />
            </core:EventTriggerBehavior>
        </i:Interaction.Behaviors>

        <Button Command="{Binding DelayedGoBackCommand,
                                  Mode=OneTime}"
                Content="Go Back" />
    </StackPanel>
</Page>

As you can see above, the button is binded to the Page2ViewModel.DelayedGoBackCommand. Also, we will be using an EventTriggerBehavior to monitor the Page2ViewModel.GoBack event, and when it gets raised, we will use the CallMethodAction to invoke the Page2.Frame.GoBack method.

Now here’s the catch: while behaviors have a way of being notified when they are to be detached, that never happens!! Not when you leave the page, not when the page gets unloaded, and not even when garbage collection runs.

As such, when we navigate back from page 2, Page2ViewModel.GoBack event will still hold a reference to the EventTriggerBehavior, leading to a memory leak!

But things get even worse in this example: everytime we navigate to page 2, we will subscribe over and over again the GoBack event, so multiple invocations will eventually occur – definitely not what we wanted!

Introducing the MonitoredInteraction class

The Cimbalino Toolkit now has the MonitoredInteraction class to solve this issue!

The MonitoredInteraction was built as a direct replacement of the Microsoft.Xaml.Interactivity.Interaction, and will monitor the attached object Loaded and Unloaded events and call for the attachment and detachment of all behaviors it contains!

Here’s how page 2 view would look if put it to use:

<Page x:Class="MyApp.Page2"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:core="using:Microsoft.Xaml.Interactions.Core"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:behaviors="using:Cimbalino.Toolkit.Behaviors"
      x:Name="PageRoot"
      mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <behaviors:MonitoredInteraction.Behaviors>
            <core:EventTriggerBehavior EventName="GoBack"
                                       SourceObject="{Binding}">
                <core:CallMethodAction MethodName="GoBack"
                                       TargetObject="{Binding Frame,
                                                              ElementName=PageRoot}" />
            </core:EventTriggerBehavior>
        </behaviors:MonitoredInteraction.Behaviors>

        <Button Command="{Binding DelayedGoBackCommand,
                                  Mode=OneTime}"
                Content="Go Back" />
    </StackPanel>
</Page>

Really, really simple, yet it will finally ensure that behaviors do get detached when one navigates away of a page, and re-attached when navigating in!

Hopefully someone from the Behaviors SDK team will read this, and take some of the suggestions here to fix this well known issue that’s been around for quite a while! 😉

Cimbalino Toolkit 2.0.0 (final)

Bring out the champagne, because Cimbalino Toolkit version 2.0.0 has gone “gold” and is now production ready! 🙂

As previously stated, the focus for this new version was to add support for UWP (Universal Windows Platform), thus making the toolkit support a total of 4 platforms:

  • Windows Phone Silverlight 8.0 and 8.1 apps (WP8)
  • Windows Phone 8.1 apps (WPA81)
  • Windows Store 8.1 apps (Win81)
  • Windows 10 UWP apps (Universal Windows Platform)

Please remember to manually add the Behaviors SDK to your UWP apps if you use Cimbalino! The other platforms will have it added automatically, but due to changes in the way NuGet works this is not possible for UWP.

Cimbalino Toolkit 2.0.0-beta1

Assuming you don’t live in a planet where you don’t get internet (and I know that’s not the case as you’re reading this!), by now you know that Windows 10 has officially launched!

So did Visual Studio 2015 and NuGet 3.x, so pretty much everything you need to develop new Windows 10 universal apps, right? Not quite! 😉

Presenting the new and improved version 2.0.0-beta1 of the Cimbalino Toolkit, and as you already suspect, it is fully compatible with UWP (Universal Windows Platform)!

Proper kudos is owed to MVP Scott Lovegrove as he has done pretty good job for the last couple of weeks to get the toolkit up and running in Windows 10! 🙂

There is a breaking change on using the toolkit from previous versions: NuGet has removed the functionality of running Powershell scripts when you install a package, and Cimbalino Toolkit required that to add the Behaviors SDK to your projects… that said, please make sure that you manually add the Behaviors SDK to any project using the Cimbalino.Toolkit NuGet package!

On a final now, remember that this new version is still a beta as the code and documentation will be reviewed and tested during the next weeks, so do expect to find some issues and bugs! If you find any, please do report them directly on GitHub!