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.

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.

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

XF: ListView ICommand Attached Property

Introduction

In this article we are going to look at how we can attach an ICommand object to a listview and have it execute when the user taps a listview item.

So how are we going to do this? We are going to use an attached property. The attached property is a way to move capability from the code behind to your view model where it is accessible to the business logic.

namespace XamlHelpers {
public sealed class ItemTappedCommandListView
{
    /// Define the attached property with a name and a type for the value.
    /// make sure you add in the property changed event handler so that you
    /// can react to changes to the value of the property
    public static readonly BindableProperty ItemTappedCommandProperty =
        BindableProperty.CreateAttached(
            "ItemTappedCommand",
            typeof(ICommand),
            typeof(ItemTappedCommandListView),
            default(ICommand),
            BindingMode.OneWay,
            null,
            PropertyChanged);

    /// This is the event handler that is invoked when the value of the
    /// attached property is changed. All we do is subscribe to the 
    /// ItemTapped property.
    private static void PropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is ListView listView)
        {
            listView.ItemTapped -= ListViewOnItemTapped;
            listView.ItemTapped += ListViewOnItemTapped;
        }
    }

    /// This is the event handler for when an item is tapped. We make sure
    /// that the sender is a list view, its enabled and that the list isn't in
    /// the middle of refreshing.
    /// If all that is ok, retrieve the ICommand object from the property.
    /// if there, we execute the CanExecute method, and if that is True
    /// we can execute the command.
    private static void ListViewOnItemTapped(object sender, ItemTappedEventArgs e)
    {
        if (sender is ListView list && list.IsEnabled && !list.IsRefreshing)
        {
            list.SelectedItem = null;
            var command = GetItemTappedCommand(list);
            if (command != null && command.CanExecute(e.Item))
            {
                command.Execute(e.Item);
            }
        }
    }

    public static ICommand GetItemTappedCommand(BindableObject bindableObject)
    {
        return (ICommand) bindableObject.GetValue(ItemTappedCommandProperty);
    }

    public static void SetItemTappedCommand(BindableObject bindableObject, object value)
    {
        bindableObject.SetValue(ItemTappedCommandProperty, value);
    }
}
}

Now this is how we use it in our XAML.

<ContentPage
    xmlns:u="clr-namespace:XamlHelpers;">

    <ListView ItemsSource="{Binding MenuItems}"
        u:ItemTappedCommandListView.ItemTappedCommand="{Binding CommandNavigate}">
    </ListView>
</ContentPage>

XF vs PWA: Getting Started With XF

Setting Up Your Project

In my Xamarin Forms vs PWA experiment, I thought I would get started with Xamarin Forms first. The first thing we are going to do is create the project. For those that don’t know, you can find the Xamarin Forms project templates under cross-platform in the category tree on the left.

ProjectSetupXF1

Next you will have to select the type of project. I prefer to use the blank app template and the platforms depend on what I am doing. I find that even if I don’t need a UWP app, I select it anyways as I find it easiest for debugging. I am also a fan of using the standard library for the common code instead of the shared project: you are only compiling the shared project once instead of including it to be compiled for each of the clients. But both work so use whatever you prefer.

ProjectSetupXF2

Alright, so after we let it restore all of the necessary packages, we can get started. If you have read any of my other posts, you know that I am a big fan of the work that the team with Prism Library do, and back it up with a Patreon pledge (if you love Prism, you should consider it as well). So the next step will be to setup Prism with my app.

Adding Prism

The easiest thing to do here is obviously to use NUGET to add Prism to your project. You can search for Prism.Unity and that will bring in the packages that use Unity.Container as the dependency injection container.

PrismUnityPackage

I should note here that I am going to use the pre-release version of the packages. As such, I am going to go to the GitHub repository and download the packages and use them in my workspace. Go to the 7.1.0-Pre tag to download the latest that I used. Why would I download and include the projects manually? If you haven’t done this before, I would recommend trying it sometime with a library of your choice. If you are relying on a package of some kind, I think it is a good idea to have at least a base understanding of how things are working within the code that you are relying on. And if something isn’t working as expected, it is pretty easy to step right into the library code itself and see what is going on. This is the first time that I have used the 7.x version of Prism so I want to see what the changes are.

If you do download the source and add it to your project manually, you will have to include the projects in your solution. Once they are in the solution, remember to go the core project and each of the platform projects and add them as project references.

Bootstrapping Your App

If you have done any Xamarin Forms projects in the past, you know that there is an Application object that is used to start up your app. This object is contained in the core project common to all the platforms. We are going to change our Application object to derive from the PrismApplication object. If you are poking around, you will probably find a PrismApplicationBase object in the Prism.Forms assembly and a PrismApplication object in the Prism.Unity.Forms assembly. We want to use the one that is derived for the container of our choice: Unity.Container.

Head on over to your core project and open up the App.xaml file. You are going to need to update the root tag to be PrismApplication and do that you will need to add the appropriate namespace to the XAML namespace declarations. Your XAML would then look like the following:

    

Don’t forget the code behind.  In addition to change the base class, Prism imposes a pair of methods that you must define: RegisterTypes and OnInitialized. First, let’s fix up the class declaration and the constructor. For now, ignore the IPlatformInitializer, we will talk more about that in another post.

public partial class App : PrismApplication
{
    public App(IPlatformInitializer initializer = null)
        : base(initializer)
    {
    }

    /// ...
}

The RegisterTypes method is used to register all the navigation pages that the navigation service uses and all of the services that you want to consume in your app. An example might be the service that calls an external web api. Although we haven’t gotten to that point yet, this sample project will call a web api that gets data from the local transit authority. We will see that a bit later.

For now, all we want to do is to register our pages for navigation, of which we only have one.

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation("main");
}

That was pretty easy. If we had a view model for our MainPage defined yet, we could also register it as part of the above call. And then whenever the navigation service created the page, it would also create the view model and inject it for us.

Next, we look at the OnInitialized function. This gets called after all of the initialization has happened and your app is ready to show the first page. For us it will be very simple, we just call the base class InitializeComponent method and then ask the navigation service to go the first page.

protected override void OnInitialized()
{
    InitializeComponent();
    NavigationService.NavigateAsync("main");
}

In the above, the NavigationService looks for the page type that you registered against the “main” key, creates it and pops it up on to the Xamarin Forms navigation stack. Just to make sure everyone grasps the coolness part of the navigation service, you perform your navigation using arbitrary strings, therefore your objects are not coupled together and it is dead easy to swap in new pages without affecting the rest of your code.

Excellent! This should get you going with a shell app that you can run on each of the platforms that you created for. Once caveat though: I sometimes find Visual Studio to be a bit finicky when you start changing the XAML base class in the app object. I usually find that some combination of cleaning the solution and restarting Visual Studio clears this up, so be aware of that. Since I specified a UWP project as well, I haven’t tried to open it up in Visual Studio for Mac to see if that is less fragile. Once Visual Studio wraps its mind around it though, you should be good to go.

Next thing we will look at is adding in our master/detail, hamburger menu and place holder pages for the different options on the menu.