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: XF Setting Up the Dashboard Page

The Goal

In this post we are going to setup the Dashboard page. The purpose of this page is to list the users favorite routes and stops so that no matter where they are, they can proceed straight to that information. It will be a relatively simple page, really just two lists. Tapping an item on one of the lists will navigate to the appropriate page and display the favorite route or stop.

Laying out the Page

This will be a pretty simple layout. Just use a grid, four rows, an auto height row for each title and an equal expanding height row for each of the lists.

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

    <Label Grid.Row="0" Text="My Favorite Stops" />
    <ListView Grid.Row="1" ItemsSource="{Binding Stops}"></ListView>

    <Label Grid.Row="2" Text="My Favorite Routes" />
    <ListView Grid.Row="3" ItemsSource="{Binding Routes}"></ListView>
</Grid>

ViewModel

The view model is going to be just as simple. Two ObservableCollections to handle the lists and a pair of commands to handle the user tapping on a list item. If you remember from setting up the hamburger menu, we are going to derive our view model from the BaseViewModel class.

public class DashboardPageViewModel : BaseViewModel
{
    private INavigationService _navigationService = null;
    private IFavoriteService _favoriteService = null;


    public DashboardPageViewModel(INavigationService navigationService, IFavoriteService favoriteService)
    {
        _navigationService = navigationService;
        _favoriteService = favoriteService;
    }


    // binds to the routes list view
    private ObservableCollection<FavoriteRouteViewModel> _routes = new ObservableCollection<FavoriteRouteViewModel>();
    public ObservableCollection<FavoriteRouteViewModel> Routes
    {
        get => _routes;
        set => SetProperty<ObservableCollection<FavoriteRouteViewModel>>(ref _routes, value);
    }

    // binds to the stops list view
    private ObservableCollection<FavoriteStopViewModel> _stops = new ObservableCollection<FavoriteStopViewModel>();
    public ObservableCollection<FavoriteStopViewModel> Stops
    {
        get => _stops;
        set => SetProperty<ObservableCollection<FavoriteStopViewModel>>(ref _stops, value);
    }


    // user taps on one of the stops
    private DelegateCommand<FavoriteStopViewModel> _commandGoToStop = null;
    public DelegateCommand<FavoriteStopViewModel> CommandGoToStop
    {
        get
        {
            return _commandGoToStop ??
                (_commandGoToStop = new DelegateCommand<FavoriteStopViewModel>((stop) => { }));
        }
    }

    // user taps on one of the routes
    private DelegateCommand<FavoriteRouteViewModel> _commandGoToRoute = null;
    public DelegateCommand<FavoriteRouteViewModel> CommandGoToRoute
    {
        get
        {
            return _commandGoToRoute ??
                (_commandGoToRoute = new DelegateCommand<FavoriteRouteViewModel>((route) => { }));
        }
    }
}

So how do we get the view model into the page itself? If you remember from the first post, we have to register all of our pages that we navigate to with the container, and we do that in our PrismApplication RegisterTypes method. In this case, we will register the dashboard page and the view model as follows:

public partial class App : PrismApplication
{
    // other stuff here

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        containerRegistry.Register<IFavoriteService, TestFavoriteService>();
        containerRegistry.RegisterForNavigation<Views.DashboardPage, ViewModels.DashboardPageViewModel>(Pages.Dashboard);
        /// other registrations
    }
}

In the above code, we are telling the navigation service that when we navigate to the DashboardPage, we should also inject the view model into the page’s DataContext member. Of course the navigation service will make use of the Container to resolve any dependencies that might be required for the view model, such as IFavoriteService and INavigationService. Notice that we also register the IFavoriteService implementation in the RegisterTypes function. We don’t have to do that for INavigationService as it is a core part of the Prism framework and already taken care of in the PrismApplication base class.

Initializing the View Model

Things are looking pretty good, but how do we initialize the data in our view model? This is another part where the navigation service in Prism really helps us. After it finishes constructing the page, injecting the view model and making it the active view, it will test to see if the view model that was injected in the data context implements the INavigationAware interface (check out INavigatedAware and INavigatingAware for more granular implementations). INavigationAware looks like this:

public interface INavigationAware
{
    void OnNavigatingTo(INavigationParameters parameters);
    void OnNavigatedFrom(INavigationParameters parameters);
    void OnNavigatedTo(INavigationParameters parameters);
}

We will have our viewmodel implement the INavigationAware interface and then load our data when the ‘OnNavigatedTo’ method is called.

public class DashboardPageViewModel : BaseViewModel, INavigationAware
{
    /// all the other stuff from above here



    public void OnNavigatedFrom(INavigationParameters parameters)
    {
        // nothing doing here
    }

    public async void OnNavigatedTo(INavigationParameters parameters)
    {
        var favStops = await _favoriteService.GetFavoriteStopsAsync();
        /// do something here with the collection
        var favRoutes = await _favoriteService.GetFavoriteRoutesAsync();
        /// do something here with the routes collection
    }

    public void OnNavigatingTo(INavigationParameters parameters)
    {
        // nothing happening here
    }
}

And that is most of the work for the dashboard page. Really the only thing left to do is to make sure that the event that is raised from tapping one of the listview items is routed to our DelegateCommand objects in the view model. For an example of that, check out my article here.

Storing the Favorites Data

By now, you might be thinking, how am I going to store the data for the favorites in a platform independant way and still be able to use it with my shared view model? I am glad you asked, because I think that will be the next post!

code in GitHub

Using IValueConverter

I was down in Las Vegas all of last week for the Autodesk Forge DevCon and Autodesk University: a full four days of learning about all of the up and coming Autodesk products and technologies and networking. Lots of fun, lots of new people to talk to. I had a chat with a somewhat new’sh dev and he was complaining about the difficulties of using XAML. We delved into a bit of MVVM and he wanted to know, in effect, how to bind visual properties.

From there we went to the use of value converters and all the potential they have for presentation without having to embed visual elements and other complex logic into your view model. And it is available across WPF, UWP and Xamarin Forms.

A Simple Case

My first value converter was in WPF and making visual elements visible or not based on a value in my view model. Lets pretend we have some additional controls in our window that are only visible if the user is an accounting user. In our view model, it is a bool property named IsAccounting. If we try to bind the IsAccounting property to the control Visibility property, a binding error occurs that says the type of the value is incorrect for the target property: because of the error we won’t see the UI change.


<!-- fails -->
<TextBox Text="{Binding AccountCode}" Visibility="{Binding IsAccounting}" />

We need a value converter that will change the bool value to a Visibility value.


public class BoolToVisConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool v = (bool) value;
        return v ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

To use it, make sure that you have the namespace that the value converter resides in declared in your Window XAML and then the converter itself referenced in the resource dictionary:

xmlns:local="clr-namespace:Demo"
<Window.Resources>
    <ResourceDictionary>
        <local:BoolToVisConverter x:Key="boolVisConverter" />
    </ResourceDictionary>
</Window.Resources>

Finally you add the converter to the binding expression of the control:


<TextBox Text={Binding SecretAccountCode} Visibility={Binding IsAccounting,Converter={StaticResource boolVisConverter}}" />

And the application looks like this:

2017-11-19boolvisconverter

I like this because it keeps the app logic free of the presentation code, and this makes your view model simpler, testable and portable.

Something More Powerful

Let’s take a look at where the IValueConverter can really help. In this example we will change the color of the text in a textbox based and an image based on the selected item in a combo box. I setup an enum with some employee types:

public enum EmployeeTypeEnum
{
	CEO,
	VicePres,
	EngDirector,
	Engineer,
}

and added EmployeeTypes and SelectedEmployeeType properties to the view model.


/// initialize this collection in the constructor with the enum values.
public ObservableCollection<EmployeeTypeEnum> EmployeeTypes { get; private set; } =
    new ObservableCollection<EmployeeTypeEnum>();

private EmployeeTypeEnum _selectedEmployeeType = EmployeeTypeEnum.CEO;
public EmployeeTypeEnum SelectedEmployeeType
{
    get => _selectedEmployeeType;
    set => SetProperty<EmployeeTypeEnum>(ref _selectedEmployeeType, value);
}

Here are our value converters, one of them will convert the SelectedEmployeeType value to a foreground color and the other will convert the SelectedEmployeeType value to an image.

public class EmployeeColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        EmployeeTypeEnum empType = (EmployeeTypeEnum) value;
        switch(empType)
        {
            case EmployeeTypeEnum.CEO:
                return Brushes.Aqua;
            case EmployeeTypeEnum.EngDirector:
                return Brushes.Green;
            case EmployeeTypeEnum.Engineer:
                return Brushes.Red;
            case EmployeeTypeEnum.VicePres:
                return Brushes.Blue;
            default:
                return Brushes.Black;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class EmployeeImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        EmployeeTypeEnum empType = (EmployeeTypeEnum) value;
        switch (empType)
        {
            case EmployeeTypeEnum.CEO:
                return new Uri("/ceo.png", UriKind.Relative);
            case EmployeeTypeEnum.EngDirector:
                return new Uri("/director.png", UriKind.Relative);
            case EmployeeTypeEnum.Engineer:
                return new Uri("/engineer.png", UriKind.Relative);
            case EmployeeTypeEnum.VicePres:
                return new Uri("/vicepres.png", UriKind.Relative);
	    default:
	        return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Add our converters to the resource dictionary:

<local:EmployeeColorConverter x:Key="empColorConverter" />
<local:EmployeeImageConverter x:Key="empImageConverter" />

The markup for our XAML looks like this


<ComboBox ItemsSource="{Binding EmployeeTypes}" SelectedItem="{Binding SelectedEmployeeType}" />
<TextBox Text="{Binding SelectedEmployeeType}" Foreground="{Binding SelectedEmployeeType,Converter={StaticResource empColorConverter}}" Margin="0,2" />

<Image Width="48" Height="48" Margin="4" Source="{Binding SelectedEmployeeType,Converter={StaticResource empImageConverter}}" />

And that is it. We have a simple and portable view model that can be used on other platforms.

2017-11-19_6-35-24

Feel free to check out the sample code in GitHub.

I also would like to give a shout-out to SyncFusion as I used their free MetroStudio icon generator to build my icons.