WPF – Bring the Loaded Event to MVVM

In the spirit of bringing the “Closing” event to your view model, I also decided that I wanted an easy way to bring the “Loaded” event to my view model. This one I don’t like as much as many frameworks have some kind of navigation that can take care of this for you. But if you have a simple app and want to initialize your view model when your window is loaded, you might find this helpful.

Just like in the previous article, you could wire into the “Loaded” event on each window and then delegate to the view model. This does work, but does tend to repeat the same code over and over again. Instead of this I went in and did a solution that is similar to the “Closing” event.

First up is create an interface that defines an Action that will be called when the window is loaded.

public interface ILoadedAction
{
    void WindowLoaded();
}

And a delegate based implementation of the ILoadedAction interface. I like this because it probably takes care of 99% of my cases.

public class DelegateLoadedAction : ILoadedAction
{
    public Action LoadedActionDelegate { get; set; }

    public DelegateLoadedAction()
    {
    }

    public DelegateLoadedAction(Action action)
    {
        LoadedActionDelegate = action;
    }

    public void WindowLoaded()
    {
        LoadedActionDelegate?.Invoke();
    }
}

And finally, some attached properties for our Window.

public class LoadedBindings
{
    public static readonly DependencyProperty LoadedEnabledProperty =
        DependencyProperty.RegisterAttached(
            "LoadedEnabled",
            typeof(bool),
            typeof(LoadedBindings),
            new PropertyMetadata(false, new PropertyChangedCallback(OnLoadedEnabledPropertyChanged)));

    public static bool GetLoadedEnabled(DependencyObject sender) => (bool) sender.GetValue(LoadedEnabledProperty);
    public static void SetLoadedEnabled(DependencyObject sender, bool value) => sender.SetValue(LoadedEnabledProperty, value);

    private static void OnLoadedEnabledPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (sender is Window w)
        {
            bool newEnabled = (bool) e.NewValue;
            bool oldEnabled = (bool) e.OldValue;

            if (oldEnabled && !newEnabled)
                w.Loaded -= MyWindowLoaded;
            else if (!oldEnabled && newEnabled)
                w.Loaded += MyWindowLoaded;
        }
    }

    private static void MyWindowLoaded(object sender, RoutedEventArgs e)
    {
        ILoadedAction loadedAction = GetLoadedAction((Window) sender);
        loadedAction?.WindowLoaded();
    }


    public static readonly DependencyProperty LoadedActionProperty =
        DependencyProperty.RegisterAttached(
            "LoadedAction",
            typeof(ILoadedAction),
            typeof(LoadedBindings),
            new PropertyMetadata(null));

    public static ILoadedAction GetLoadedAction(DependencyObject sender) => (ILoadedAction) sender.GetValue(LoadedActionProperty);
    public static void SetLoadedAction(DependencyObject sender, ILoadedAction value) => sender.SetValue(LoadedActionProperty, value);
}

I created two attached properties, one to enable or disable this feature and one to bind to the interface that contains the action to execute when the window is loaded. You could make this even simpler by removing the enabled/disabled property, but I like the flexibility of being able to turn it on and off. If you did want to do that, you would have to define a DependencyPropertyChangedEvent for the LoadedActionProperty and subscribe and unsubscribe to the Loaded event there.

To use these properties, open up your window XAML file, add in the namespace declaration and define your properties.

<Window x:Class="SampleApp.MainWindow"
    xmlns:local="clr-namespace:SampleApp"

    local:LoadedBindings.LoadedEnabled="True"
    local:LoadedBindings.LoadedAction="{Binding LoadAction}">
</Window>

In the sample above I removed some of the other declarations and assumed that our attached properties were in the same namespace as our MainWindow class.

Next, in the view model class, we simply do this:

public class MainWindowViewModel : BaseViewModel
{
    /// constructor, properties etc ...
    /// ...

    private DelegateLoadedAction _loadAction = null;
    public DelegateLoadedAction LoadAction
    {
        get
        {
            return _loadAction ??
                (_loadAction = new DelegateLoadedAction(
                    () =>
                    {
                        /// do your window initialization here
                    }));
        }
    }
}

And that is about it. Now you don’t have to subscribe the Loaded event explicitly any longer and you can consolidate your code into the view model. You can also move any of those longer running operations that were in the constructor of the view model out.

Perhaps the next step will be to turn this and the Closing event code from the previous post into a nuget package that can be just installed into a project.

WPF – Bring Closing Event to MVVM

The Issue

I’m jumping around a bit, but I don’t get to work on a single project at a time, so I am going to switch gears to talk about some WPF work that I put together. In this project, I want to make sure that I can control when the user closes the window, regardless of whether they click on the “X” in the top-right or if they click the “Exit” button in the UI.

The problem that we have is that the logic that controls whether the user can close the window or not is in the view model. The exit button is controlled by the view model. But the “X” in the top-left corner can only be controlled by the Closing event in the code behind. You can use the event parameters to cancel the close. How can we leverage the logic in the view model to determine if the Window can close or not?

Hack Method

One thing we can do, is inside of the Closing event, we could query the view model to see if it is ok to exit or not. It’s not the greatest, it will be writing a lot of custom code in every window code behind.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Closing += MainWindow_Closing;
    }

    private void MainWindowClosing(object sender, CancelEventArgs a)
    {
        // make sure we have the view model class
        if (DataContext is MainWindowViewModel vm)
        {
            // check with the view model if should be canceled
            e.Cancel = vm.ShouldCancel();
        }
    }
}

Not pretty but it works.

Using Attached Properties

The way I chose to do it is to use DependencyProperty’s that participate in the XAML binding system and can attach to the view model directly and not have to wire up each and every window explicitly. To do this, we need to setup a few new properties. One for enabling or disabling this functionality; a second for a parameter to send back and forth from the view model; and finally, a third that will hold an object that contains an action that gets called when the window is attempted to be closed.

Let’s get started with the two dependency properties that are used for holding the can close implementation and the can close parameter that is passed back and forth. These properties have the following shapes.

public interface ICanCloseResult
{
    bool Cancel { get; set; }
}

public interface ICanCloseCheck
{
    void CheckCanClose(ICanCloseResult canCloseResult);
}

And here are the properties that hold these values.

public class CanCloseBinding
{
        public static readonly DependencyProperty CanCloseCheckProperty =
            DependencyProperty.RegisterAttached(
                "CanCloseCheck",
                typeof(ICanCloseCheck),
                typeof(CanCloseBinding),
                new PropertyMetadata(null));

        public static ICanCloseCheck GetCanCloseCheck(DependencyObject sender) => 
            (ICanCloseCheck) sender.GetValue(CanCloseCheckProperty);
        public static void SetCanCloseCheck(DependencyObject sender, ICanCloseCheck value) => 
            sender.SetValue(CanCloseCheckProperty, value);


        public static readonly DependencyProperty CanCloseCheckParameterProperty =
            DependencyProperty.RegisterAttached(
                "CanCloseCheckParameter",
                typeof(ICanCloseResult),
                typeof(CanCloseBinding),
                new PropertyMetadata(null));

        public static ICanCloseResult GetCanCloseCheckParameter(DependencyObject sender) => 
            (ICanCloseResult) sender.GetValue(CanCloseCheckParameterProperty);
        public static void SetCanCloseCheckParameter(DependencyObject sender, ICanCloseResult value) => 
            sender.SetValue(CanCloseCheckParameterProperty, value);
}

Next we have to build up the dependency property that enables or disables the functionality. The important thing this property does is, when it is set to true, it attaches an event handler to the Closing event of the window. Then, when that event is executed, it tries to get the instances of the other two parameters and execute them. So it looks like the following.

namespace CanClose.Views
{
public class CanCloseBinding
{
    // ... other properties here

    public static readonly DependencyProperty CheckCanCloseEnabledProperty =
        DependencyProperty.RegisterAttached(
            "CheckCanCloseEnabled",
            typeof(bool),
            typeof(CanCloseBinding),
            new PropertyMetadata(false, new PropertyChangedCallback(OnCheckCanClosePropertyChanged)));

    private static void OnCheckCanClosePropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (sender is Window w)
        {
            bool newEnabled = (bool) e.NewValue;
            bool oldEnabled = (bool) e.OldValue;

            if (oldEnabled && !newEnabled)
                w.Closing -= MyOwnWindowClosing; // remove the event handler for Closing from the Window
            else if (!oldEnabled && newEnabled)
                w.Closing += MyOwnWindowClosing; // add the event handler for Closing to the window
        }
    }

    public static bool GetCheckCanCloseEnabled(DependencyObject sender) => 
        (bool) sender.GetValue(CheckCanCloseEnabledProperty);
    public static void SetCheckCanCloseEnabled(DependencyObject sender, bool value) => 
        sender.SetValue(CheckCanCloseEnabledProperty, value);

    public static void MyOwnWindowClosing(object sender, CancelEventArgs e)
    {
        /// get the values from the dependency properties
        ICanCloseCheck q = GetCanCloseCheck((Window) sender);
        ICanCloseResult p = GetCanCloseCheckParameter((Window) sender);
        if (q == null || p == null)
            return;

        /// execute and save the value back to the CancelEventArgs object
        q.CheckCanClose(p);
        e.Cancel = p.Cancel;
    }
}
}

Finally, all we need to do is attach these properties to the window that we want to control from our view model. And that is done like this:

<Window x:Class="CanClose.Views.MainWindow"
    xmlns:local="clr-namespace:CanClose.Views"
    local:CanCloseBinding.CheckCanCloseEnabled="True"
    local:CanCloseBinding.CanCloseCheck="{Binding CCQuery}"
    local:CanCloseBinding.CanCloseCheckParameter="{Binding CCResult}"
    >
    <!-- stuff here -->
</Window>

And that is about it. If you want to see a sample, you can find it here.

XF vs PWA: Setting Up the API

Setting Up the API

In this post, I thought we would go over the API: the API will be able to be shared between both the Xamarin Forms app and the PWA. To get access to the API, you have to apply to the Translink Authority and get an API key. Of course, you shouldn’t share that API key with anyone, and that can be pretty difficult to achieve when you have a mobile app that must send it to the provider.

One way you can do it is to hide the key in your app somehow or encrypt it. But if you encrypt it, you are going to have to unencrypt it as well and that means hiding a different key. For this app, I am just going to proxy the provider API with my own API and that way, I won’t have to store the Translink Authority API in my local app. If this was a serious app, I would consider using my own keys and/or looking at user info in my app to guard against mis use. It is much easier to revoke my own keys than it is to have to go back to the Translink Authority for a new key in the event of misuse.

Storing the Key

I am just going to store the key in my appsettings.json file for simplicity. Your appsettings.json is stored in the root of the web api project. It looks like the following:

{
"Logging": {
"includeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
},
"mySecrets": {
"translinkKey": "xxxxxxxxxxxxxxxxxx"
}
}

To get access to the settings, we have to do some work in the Startup class. I changed the Configuration property to be an instance of IConfigurationRoot interface. To create that, I changed the constructor object to create it.

public class Startup
{
    public IConfigurationRoot Configuration { get; }
    private IHostingEnvironment _hostingEnvironment = null;

    public Startup(IHostingEnvironment env)
    {
        _hostingEnvironment = env;
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();

        Configuration = builder.Build();
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IConfigurationRoot>(Configuration);

        // rest of code
    }
}

To access the settings in your controller class, you need to have the IConfigurationRoot object injected into your controller through the constructor.

[Route("api/bus")]
public class BusController : Controller
{
    private IConfigurationRoot _configuration = null;
    private string _apiKey = null;

    public BusController(IConfigurationRoot configuration)
    {
        _configuration = configuration;

        var section = configuration.GetSection("secrets");
        _apiKey = setion.GetValue<string>("translinkKey");
    }

    // controller actions go here
}

Now with the API key the web app can make calls to the Translinke API directly.

If you feel like checking out some of the code, you can find it here.

XF vs PWA: Exploring PWA Service Workers

PWA Getting Started

I am not finished with my work on the Xamarin Forms portion of the series yet, but I had to start some PWA work in the middle, and I thought it would be good to write about my first lessons in PWA land.

Service Workers

I think the biggest lesson I have learned so far as that the service worker is the most important component of a PWA, or the piece that separates a PWA from a regular responsive web app.
One of the really interesting things about a service worker is that it runs in the background of the browser itself and can run even if your app isn’t currently loaded. How cool is that? I am looking forward to trying that one out.

The service worker has a number of capabilities.
Cache Content: It can cache your content, giving you the ability to have an app presence even when you are offline.
Push Notifications: It can subscribe to a push service and receive messages. The service worker can take these messages and update the state of the app or display a notification of some kind.
Notifications: It can send notifications to the user using the host operating system notification mechanism.
Channel Messaging: It can communicate with other service workers and the host application.

The first thing I am going to do is make sure that my app shows up even if it is offline. Even if your app needs to be online to do anything useful, it is still a nicer experience for the user if your app loads and presents an explanation of what is happening.

Setting Things Up

First we will make a simple web page. There won’t be much of anything going on. We will just pull in some bootstrap resources from their CDN and add in some of our own styles and javascript.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <title>service workers</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
    <link rel="stylesheet" href="my.css" >
</head>
<body>
    <h1>hello from pwa land</h1>

    <a href="https://code.jquery.com/jquery-3.3.1.slim.min.js">https://code.jquery.com/jquery-3.3.1.slim.min.js</a>
    <a href="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js">https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js</a>
    <a href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js">https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js</a>
    <a href="http://my.js">http://my.js</a>
</body>
</html>

and some custom css

body {
    margin: 20px;
}

javascript

console.log('loaded');

For serving up your content, I am using a simple http web server called ‘http-server’. You do require node which you can download from here.

You can install the http-server using the following command:
npm install http-server -g
The -g installs it so that it installed globally and you can use it anywhere.

At the command line, change to your content directory and execute the following command:
http-server -p 8080 -a localhost -c 0
This starts up an http server servicing the content in the current direcctory from http://localhost:8080.
You should be able to open your web browser and go the above address to http://localhost:8080/index.html and serve up the page from above.

Create our Service Worker file

It’s important that we create this file at the root of our web app. Service workers have scope where they apply to the current folder and below. They can’t travel up. I should also note that service workers only work over https connections, localhost being the only exception to that. If you need an ssl certificate, letsencrypt.org is a place where you can get free SSL certificates for your site.

// service worker file

Our file will be empty, but that’s ok, we just need to have a file to handle the registration.

Register our Service Worker

The last thing we do in our index.html file is perform the registration of our service worker. In a script tag just before the closing body tag, add the following code.

    <!-- our code from above -->



        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('service-worker.js')
            .then(function(registration) {
                console.log('Service worker registration successful with scope: ', registration.scope);
            })
            .catch(function(error) {
                console.log('Service worker registration failed: ', error);
            });
        }


</body>

This is important. We need to check if our browser supports service workers and that is checked from the navigator object in javascript. If it is, we can do the actual registration. If it isn’t, we just ignore it and keep our app as is. That is a key point to PWA’s: start at the basic functionality and then add on the capabilities as the host browser supports them.

Filling out the Service Worker

Alright, we have a page that is pulling in various resources, some that we own, some via external. Let’s take a look at how we can make the app function offline.
First we need to make a list of the resources that we want to cache. This is pretty simple. Obviously we want the home page, our js and css files, and our external bootstrap and jquery files.

// service-worker.js


(function () {
    'use strict';

    // our list of cache'd items. We can fill this in more later if we want.
    var filesToCache = [
        '.',
        'index.html',
        'my.css',
        'my.js',
        'https://code.jquery.com/jquery-3.3.1.slim.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js',
        'https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js'
    ];

    var staticCacheShell = 'app-shell';

})();

Next we are going to register an event handler for when the service worker is installed. The purpose of this is to setup the cache.

    // this is just below the var staticCacheShell declaration and before the closing })();

    self.addEventListener('install', function (event) {
        console.log('installing sw and caching statics');
        event.waitUntil(
            caches.open(staticCacheShell)
                .then(function (cache) {
                    console.log('adding static shel cache');
                    cache.addAll(filesToCache);
                    return;
                }).catch(function(error) {
                    console.log(error);
                })
        );
    });

What is happening above is that we are going to create the cache using our key name and then instruct the cache to add all of our pages into it. Pretty straightforward. But, how do we get pages served from the cache when we are offline? That is the next thing we are going to add to our service worker.
We add another event handler intercepting the fetch event. This sits between your app and the internet and allows you to manipulate the request. In our case, we are going to check if the request is in the cache, and if it is, return it back to your app instead of going out on to the internet. If the network request returns a page not found (404) error, we can serve up the app’s not found page (remember to add it to the list of pages). If the request is returned, we make a clone of the response and stuff it in the cache. Finally, if there is any other error, return the app’s app offline page (remember to stick that in the cache as well).

    self.addEventListener('fetch', function(event) {
        console.log('fetch event for ', event.request.url);
        event.respondWith(
            caches.match(event.request).then(function(response) {
                if (response) {
                    console.log('found ', event.request.url, ' in cache');
                    return response;
                }

                console.log('network request for ', event.request.url);
                return fetch(event.request).then(function(response) {
                    if (response.status === 404) {
                        return caches.match('page404.html');
                    }

                    return caches.open(staticCacheShell).then(function(cache) {
                        if (event.request.url.indexOf('test') < 0) {
                            cache.put(event.request.url, response.clone());
                        }

                        return response;
                    });
                });
            }).catch(function(error) {
                console.log('Error ', error);
                return caches.match('pageoffline.html');
            })
        );
    });

Now let’s run our app. I used the http-server from above and loaded the index.html in Edge. I just had my windows update and Edge was upgraded again. In there you can see that the developer tools are showing that the service worker has been registered.
pwagettingstartedservicework

Next we can look at the cache and we can see that all the pages that registered have been added to the cache.
pwagettingstartedcache

I didn’t see a way in the Edge developer tools to simulate taking the page offline, so I went over to Chrome and loaded up my page. I opened up the developer tools, went to the network tab and set the mode to be offline.

pwagettingstartedoffline
If we refresh the page from here, it will still show up, even though there is no network access for the browser. If we try to load some random page, we will get the pageoffline page.

Conclusion

So that is the quick and dirty for getting started with PWA’s, service workers and offline mode. It’s pretty cool tech and I am looking forward to exploring it some more. You can explore this code in Github.

Unable to Debug .NET Standard Project in XF UWP

Helpful Hint

Ran into a funny one today. I was trying to debug my XF project and it wasn’t loading the symbols for the .NET Standard project so it was not hitting any of my breakpoints. I am currently using Visual Studio 2017.7.1. This was happening in my UWP project.

Obviously that’s not too helpful, but luckily I found some help in the Xamarin Forms as to the setting that was causing the problem. It has to do with the type of debugging information your build outputs. All I needed to do was change it to “Pdb-Only” and we were good to go.
credit
dotnetstandarddebug