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: 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>

JSON to C#

Do you ever get tired of translating JSON to the equivalent C# shape for your app? I do. One of the tools that I like to use is quicktype. It is a web app that will allow you to paste in some JSON and it will generate the C# classes for you. That’s a pretty good start.

But it gets better than that. If you are like most, and you use NewtonSoft Json.NET (if you don’t, you should check it out), it will decorate the properties it generates with the [JsonProperty] attributes with the property name from JSON while the C# property has the standard casing.

It also has features for handling things like enums, maps, lists or arrays among others.

https://app.quicktype.io/#l=cs&r=json2csharp

Check it out, I love it.