0 Comments

imageIn this tutorial we will create an UWP Dashboard app. The dashboard will contain widgets where each widget is a self contained part, providing functionality to the app. We will be using Caliburn.Micro to build the app.

Background

We all have used widget based dashboard apps. VSTS’ project front page is just one example (you can see red arrows pointing to individual widgets):

image

Azure Portal is another good example:

image

Common for widget based dashboards is that each widget is a self contained part: It can work alone or with 1000 other widgets without interfering with the other widgets. Another common feature for widget based apps is the shell: Shell contains the common application UI (like the toolbar) and hosts the widgets.

Building widget based dashboard using UWP

We’re going to use couple libraries to build the dashboard: Caliburn.Micro is used to bring down the amount of code and Telerik’s UI for UWP is used for some pretty widgets. The Telerik’s UI components are great but in this case they are completely optional: You can create your widgets and the shell using any controls you want. But I would recommend using Caliburn.Micro as it allows to keep our code base simple and clean.

Caliburn.Micro

Caliburn.Micro is a MVVM framework. It is a convention based framework and after you learn the conventions, it is powerful and simple to use. The reason we’re using Caliburn.Micro in this app is its built-in view locator. The view locator is the component which allows you to easily build UWP dashboard apps and which allows us to do that with minimum amount of code.

Creating our app

We will start by creating the app and configuring Caliburn.Micro. Starting point is the “Blank App (Universal Windows)” template:

image

Target and minimum versions don’t really matter:

image

MainPage.xaml can be deleted at this point.

To hook up Caliburn.Micro, first add the Nuget package “Caliburn.Micro” (version 3.2):

image

Then open App.xaml and change it into the following format:

<cm:CaliburnApplication
x:Class="UWP_WidgetDasboard.App"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cm="using:Caliburn.Micro"
    RequestedTheme="Light">

</cm:CaliburnApplication>

All the App.xaml.cs requires few changes: It doesn’t inherit Application anymore so we can remove that and also some Caliburn.Micro specific setup is needed. Once you get this right, you can usually just copy paste the code from app to app. The full App.xaml.cs can be found from this tutorial’s GitHub repository but here’s the most interesting parts:

        protected override void Configure()
        {
            container = new WinRTContainer();
            container.RegisterWinRTServices();

            container.Singleton<ShellViewModel>();
        }

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            if (args.PreviousExecutionState == ApplicationExecutionState.Running)
                return;

            DisplayRootView<ShellView>();
        }

Configure-method will be used to initialize the widgets and the shell. OnLaunched decides page is shown at launch. As we can see the code uses ShellViewModel and ShellView so let’s create those before we can hit F5 to make sure everything works.

ShellView is just a blank page:

image

And ShellViewModel is a class which inherits Screen:

using Caliburn.Micro;

namespace UWP_WidgetDasboard
{
    public class ShellViewModel : Screen
    {
    }
}
Now if you hit F5 you should see our empty app starting without errors:

image

At this point we have a working app with a shell but without any content. The solution explorer is the following (highlighted are the files which we have changed):

image

Next up is creating the widgets.

Creating the first widget

For each widget we need two things:

  • UserControl for the UI
  • Caliburn.Micro based ViewModel (Screen or Conductor) for the logic

We also have to have a common IWidget interface, which can be empty. This is our starting point:

namespace UWP_WidgetDasboard
{
    public interface IWidget
    {
    }
}

Let’s create our first widget: Customer Info. To get some structure, we’re going to create a folder for each widget. These aren’t required but they make things easier to find. Create an empty user control (CustomerInfoView) and an empty class (CustomerInfoViewModel) into the project:

image

CustomerInfoViewModel is the place where widget’s logic will be: It can contact the database/web api to fetch data or access some resource packaged with the app. The CustomerInfoViewModel should be a “Caliburn.Micro ViewModel”, meaning it needs to inherits from a Screen or from a Conductor. Screen is your choice if you want to display information about a single object, Conductor is great if you have a list of object. For example CustomerInfoViewModel is a Screen because we just display info about a single Customer. CustomerSearchViewModel should be a Conductor as it quite likely displays a range of customers.

To make things work, the widget’s view model should also implement our IWidget interface. When using Caliburn.Micro, the widget’s initialization logic can be placed inside the OnActivate-method. Let’s insert some logic:

    public class CustomerInfoViewModel : Screen, IWidget
    {
        private Customer _customer;

        public Customer Customer
        {
            get { return _customer; }
            set
            {
                _customer = value;
                NotifyOfPropertyChange(() => Customer);
            }
        }

        protected override void OnActivate()
        {
            this.Customer = new Customer("Mikael", "Koskinen");
        }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public Customer(string firstName, string lastName)
        {
            FirstName = firstName;
            LastName = lastName;
        }
    }

Now we just implement the UI for our widget to display customer information:

    <Grid>
    
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock Style="{StaticResource TitleTextBlockStyle}" Grid.ColumnSpan="2" Text="Customer Information:"/>
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Grid.Column="0" Grid.Row="1">First name:</TextBlock>
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Grid.Column="0" Grid.Row="2">Last name:</TextBlock>

        <TextBlock Style="{StaticResource BodyTextBlockStyle}" Grid.Column="1" Grid.Row="1" Text="{Binding Customer.FirstName}"/>
        <TextBlock Style="{StaticResource BodyTextBlockStyle}" Grid.Column="1" Grid.Row="2" Text="{Binding Customer.LastName}"/>

    </Grid>

Next up is making the shell work.

Creating the shell

The shell hosts the widgets and the common UI functions. We’re going the skip the common UI functions and just include a container which contains all the widgets.

The shell is where you decide how you want to represent the widgets: You can use similar square box containers as VSTS’ or you can host each widget in a tab control or hub or carousel or anything you like. We’re going to use the square box containers.

All the widgets are “injected” into the ShellViewModel using dependency injection. This way shell doesn’t need to know which widgets it is currently hosting.

To get the dependency injection working, we need to add all the classes implementing IWidget into the Caliburn.Micro’s DI container. This is done in App.xaml.cs:

        protected override void Configure()
        {
            container = new WinRTContainer();
            container.RegisterWinRTServices();

            container.Singleton<ShellViewModel>();
            AddWidgets();
        }

        private void AddWidgets()
        {
            var types = typeof(ShellViewModel).GetTypeInfo().Assembly.GetTypes().ToList();
            var widgets = types.Where(type => type.GetTypeInfo().IsClass && System.Reflection.TypeExtensions.IsAssignableFrom(typeof(IWidget), type)).ToList();

            foreach (var widget in widgets)
            {
                container.RegisterPerRequest(typeof(IWidget), null, widget);
            }
        }

Now when we run the app, all the widgets implementing IWidget are automatically added inside the DI container. We can use this in our ShellViewModel. At this point we should also change ShellViewModel to inherit Conductor<IWidget>. This provides us Items-property, which we can use to add the widgets:

    public class ShellViewModel : Conductor<IWidget>.Collection.AllActive
    {
        public ShellViewModel(IEnumerable<IWidget> widgets)
        {
            this.Items.AddRange(widgets);
        }
    }

Now we have the basic logic implemented and we just need to display the widgets inside the ShellView. For this you can use any container. We’re going to use ItemsControl with ItemsWrapGrid:

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ItemsControl x:Name="Items">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderThickness="2" BorderBrush="LightBlue" Margin="12" Width="400" Height="400">
                        <Grid>
                            <Border Background="LightBlue" Opacity="0.1"/>
                            <ContentControl Margin="12" micro:View.Model="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
                        </Grid>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>

Now when you run the application, you should see our single widget hosted inside the shell:

image

We can make sure everything works correctly by adding couple more widgets:

image

image

Conclusion and further work:

This tutorial shows what it takes to create UWP dashboard widget app. It doesn’t take much: Only few lines of code is required to for the shell and IWidget, after which all the coding takes place inside the widgets. As each widget can be as complicated or as simple as they need, bulk of your code will be place into the individual widgets.

To make this full blown solution, the widget system needs some more functionality:

  • Instead of always having all the widgets, user should be able to add and remove widgets.
  • Common widget elements, like title and action buttons.
  • Different sized widgets instead of a single fixed size.
  • Ability to send notifications from a widget to a widget using Event aggregator.
  • Ability to send notifications from a widget to the shell using Event aggregator.

The full source code can be found from the GitHub: https://github.com/mikoskinen/blog/tree/master/UWP-WidgetDasboard

0 Comments
  •   Posted in: 
  • UWP

imageUWP apps support multiple views/windows. Compared to Windows Forms and WPF apps there’s one big difference in UWP: All application views use different threads. This makes it harder to build applications where different views communicate with each other.

In this post we explore couple different ways of multi-window communication.

Creating a new View (Window) in UWP

To create a new view in UWP app one can use CoreApplication.CreateNewView. Here’s the basic code for opening an another view:

            CoreApplicationView newView = CoreApplication.CreateNewView();
            int newViewId = 0;
            await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                Frame frame = new Frame();
                frame.Navigate(typeof(Secondary), null);
                Window.Current.Content = frame;
                // You have to activate the window in order to show it later.
                Window.Current.Activate();

                newViewId = ApplicationView.GetForCurrentView().Id;
            });

            bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);

Here’s an example output:

image

There’s a good tutorial about multi view app development at Dev Center: Show multiple views for an app.

Next, let’s look how we can make the views to communicate with each other.

Example app

In our example app we have two views: The main one and a secondary. Secondary view contains a button and when clicked, we want to update the main view.

Main view has method which updates the TextBlock:

 

        public void UpdateMessage(string newMessage)
        {
            this.Message.Text = newMessage;
        }

The problem

As mentioned, all the views have different threads in UWP. As with Windows Forms and WPF, there’s only one thread which can access UI controls. Trying to access them from other threads will cause exceptions.

The first approach to multi view communication in UWP is the direct one: We pass the main view to secondary view and try to update the main view’s TextBox directly using MainPage.UpdateMessage:

Main view is passed to Secondary View:

                frame.Navigate(typeof(Secondary), this);

Secondary view receives the Main view:

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            this.MainPage = (MainPage) e.Parameter;
        }
 

Main view’s UpdateMessage is called directly:

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            this.MainPage.UpdateMessage("Hello from second view");
        }

Here we hit the problem: This throws an exception:

image

First solution to this problem is using CoreDispatcher directly.

First option: Directly using CoreDispatcher

We can use Main View’s CoreDispatcher to get around this problem. The change is done on the UpdateMessage-method:

        public void UpdateMessage(string newMessage)
        {
            this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.Message.Text = newMessage);
        }

With this, we get the desired result:

image

Second option: EventAggregator

The first option works but if there is much communication between the views, it can be tedious to manually call CoreDispatcher at every point. Another option is to change the pattern:

Insted of views communicating directly with each other, you add a middle man which handles the communication between views. EventAggregator is a familiar pattern and it fits into this problem nicely: You raise messages from your views and if some other view is interested, it acts on that message.

I’ve posted a gist which contains a source code of a multi-view UWP EventAggregator. You can examine it to get the idea but in production use it’s good to use something like WeakReferences so that EventAggregator knows when to let go of views.

The idea in this pattern is that you create one EventAggregator for each of your views but the EventAggregator contains a static (shared) list of subscribers which are common to all the views. Here’s what we change in our example app:

Main view:

        
    public sealed partial class MainPage : Page, MainPage.ISubscriber
    {
        public MainPage()
        {
            this.InitializeComponent();
            var eventAggregator = new MyEventAggregator();
            eventAggregator.Subscribe(this);
        }

Note that MainPage now implements ISubscriber.

Secondary view:

        
        public Secondary()
        {
            this.InitializeComponent();
            this.EventAggregator = new MyEventAggregator();
        }

Note that there’s no need to pass Main view to Secondary view: Secondary view doesn’t have to know that Main view exists.

Secondary view raises a message:

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            this.EventAggregator.Publish(new Message("hello from second view"));
        }

Main view handles the message:

        public void Handle(Message message)
        {
            this.Message.Text = message.Text;
        }

image

Conclusion

Different view threads in UWP apps can bite you. You can get around the problem using CoreDispatcher. If there’s much communication happening between the views, it can be better to use a middle man (mediator) to handle the cross thread communication. EventAggregator is one example of this kind of a pattern.

0 Comments
  •   Posted in: 
  • UWP

image There’s some cases where SemanticZoom in an UWP app provides a nice way of quickly navigating your app’s content. On the other hand SemanticZoom is something which can be hard for your app’s users to find so one should use it sparingly.

I’ve posted one sample app about SemanticZoom to GitHub. It’s a C# / MVVM app which shows how to combine GridView with SemanticZoom. To get the zoomed out view, you can use CTRL+Mousewheel:

image

Get the code from here:

https://github.com/mikoskinen/UWP-SemanticZoom-GridView

To learn more about SemanticZoom, you can visit Microsoft’s documentation.

0 Comments
  •   Posted in: 
  • UWP

imageThe first part of our Aurelia & UWP tutorial showed us how to get started. As mentioned in the end of that post, it was easy to get started but when you start using the Aurelia app using desktop, you’ll notice that you can’t navigate backwards.

This second part of our tutorial will show you how to add back button into your app.

The back button in UWP apps

If you’ve built UWP apps using C# & XAML, you’ve quite likely encountered SystemNavigationManager. Through it, you can add the standard backward navigation button into your app:

image

More about this from the MSDN: Navigation history and backwards navigation for UWP apps

The back button in Aurelia UWP app

So if we can use SystemNavigationManager in C#, what can we do in our Aurelia app? We can use the same SystemNavigationManager!

var systemNavigationManager = Windows.UI.Core.SystemNavigationManager.getForCurrentView();

That’s one big nice thing in UWP: You can access the same WinRT classes and methods from Javascript in addition to C# and C++.

To add the back button, add backbutton.js into your app with the following content:

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
(function () {
var systemNavigationManager = Windows.UI.Core.SystemNavigationManager.getForCurrentView();
systemNavigationManager.addEventListener("backrequested", handleSystemNavigationEvent.bind(this));
window.onpopstate =function () {
var systemNavigation = Windows.UI.Core.SystemNavigationManager.getForCurrentView();
if (endsWith(window.location.href,"index.html")) {
systemNavigation.appViewBackButtonVisibility = Windows.UI.Core.AppViewBackButtonVisibility.collapsed;
}else {
systemNavigation.appViewBackButtonVisibility = Windows.UI.Core.AppViewBackButtonVisibility.visible;
}
};
})();
function handleSystemNavigationEvent(args) {
args.handled =true;
window.history.back();
}
function endsWith(str, suffix) {
return str.slice(-suffix.length) === suffix;
}

Then reference backbutton.js in index.html:

image

That’s it. You should now see the back button in your app’s title bar when you navigate away from the home page.

image

You can find the full example from GitHub: https://github.com/mikoskinen/aurelia-uwp/

In part three of Aurelia and UWP tutorial we look how to integrate more UWP app features inside your Aurelia app: The goal is to integrate the Aurelia app with Windows 10 and to make it behave like a standard C#/XAML based UWP app.

0 Comments
  •   Posted in: 
  • UWP

imageLately we’ve been writing some apps using Aurelia. Aurelia isn’t the only Javascript framework out there but it’s easily the most productive we have encountered. For someone who has been writing XAML/C# apps for the last seven years or so, Aurelia is the first platform which gives us the same kind of a feeling of productivity as the XAML/C#.

Some of the apps we’ve been building have been such that it would be great if we could release them to the Windows Store. Here’s a step-by-step tutorial on how to package the Aurelia app as an UWP app.

Requirements

Before starting, make sure that you have aurelia-cli up and running. For sample app we can use Aurelia’s “official” todo example app. You can get it from GitHub.

1. Create new UWP app

First, let’s create a new UWP app using the “Blank App (Universal Windows)” template:

image

2. Copy the Aurelia app inside the UWP app’s folder

Now get your Aurelia app or the todo-example app and copy its source code inside the UWP app’s root folder. This should override the default index.html and your folder should now look like the following:

image

3. Build Aurelia app

Next step is to build the Aurelia app. If you’ve just copied the example app from GitHub, you must first install its dependencies:

npm install

When you have the dependencies installed, build the app using aurelia-cli:

au build

image

4. Include required files in Visual Studio

Last step is to include the required files using Visual Studio. Select “scripts” folder and “Include in project”:

image

And you’re all set! Just use F5 to run the app:

image

Conclusion

This tutorial showed you how to “port” Aurelia app to an UWP app.

The source code is available from GitHub.

When you start using the app, you’ll quite likely notice a big problem quickly: There’s no back-button. The part 2 of this series shows how you can add the standard back-button, allowing desktop users to navigate back in your Aurelia app.