WPF MVVM – Simple ‘MessageBox.Show’ With Action & Func

by Dean 6. May 2010 08:08

In the MVVM world, things like message boxes (MessageBox.Show) and Dialogs (open file, save file etc), don't naturally fit.

These popups are closely tied to the ‘View’ part of MVVM, but they can only really be invoked from the ‘ViewModel’ which will break the clean separation in MVVM.

If you google this issue, you will find a wide range of elaborate solutions, many of which are significant engineering projects in their own right.

I am a huge fan of implementing simple solutions wherever possible, as verbose code is the number one culprit in un-maintainable projects, so I was keen to find a solution that is simple, robust, elegant and doesnt break the MVVM pattern

The solution I came up with, is to use generic Action and Func Delegates.

OK, to illustrate my solution, I have created a new project using the ‘WPF Model-View-ViewModel Toolkit’, (http://wpf.codeplex.com/wikipage?title=WPF%20Model-View-ViewModel%20Toolkit), which installs a project template in VS2008

Here is my altered ‘MainViewModel'.cs’ class

public class MainViewModel : ViewModelBase
{
    private DelegateCommand exitCommand;
    private Action<string> popup;
    private Func<string, string, bool> confirm;
 
    public MainViewModel(Action<string> popup, Func<string, string, bool> confirm)
    {
        this.popup = popup;
        this.confirm = confirm;
    }
 
    public ICommand ExitCommand
    {
        get
        {
            if (exitCommand == null)
                exitCommand = new DelegateCommand(Exit);
            return exitCommand;
        }
    }
 
    private void Exit()
    {
        if (confirm("Are you sure you want to exit", "confirm exit"))
            Application.Current.Shutdown();
    }
}

As you can see, the MainViewModel’s constructor takes 2 delegates, 1 for popup and 1 for confirm

Now take a look at App.xaml.cs, where the View and the ViewModel get instantiated

private void OnStartup(object sender, StartupEventArgs args)
{
    // messagebox
    var popup = (Action<string>)(msg => MessageBox.Show(msg));
 
    // confirm box
    var confirm = (Func<string, string, bool>)((msg, capt) => 
        MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes);
 
    Views.MainView view = new Views.MainView();
    view.DataContext = new ViewModels.MainViewModel(popup,confirm);
    view.Show();
}

If you look closely, you’ll see that my delegates actually map to methods in the static class ‘MessageBox’, which will give us the popups we need. The popup delegate will instantiate a simple message popup, and the confirm delegate will instantiate a message popup with confirm buttons.

And this is what happens when we click on the Exit menu item (note: this menu is created by default when you create a new project using the toolkit)

popup

Now, when we want to run unit tests on our ViewModel, we can just pass in dummy delegates

[TestMethod()]
public void MainViewModelConstructorTest()
{
    var dummyPopup = (Action<string>)((a) => {return;});
    var dummyConfirm = (Func<string,string,bool>)((a,b) => {return true;});
    ViewModels.MainViewModel target = new ViewModels.MainViewModel(dummyPopup, dummyConfirm);
    Assert.Inconclusive("TODO: Implement code to verify target");
}

Dean

Tags: ,

MVVM | C# | WPF | Unit Tests

F# And MVVM – A Simple ViewModel

by Dean 12. April 2010 20:51

For many years, OOP abstractions and design patterns have been the cornerstones of my development methodology as a senior C# developer in investment banking.

However, over the last year or so I have taken quite a shine to Microsoft’s new FP language (F#), not just because purely functional program code is concise powerful and elegant, but because the eclectic mix of functional and OOP paradigms in F# enable me to develop better, faster, stronger and more maintainable applications.

In investment banking, the business has been changing fast, and being able to get production quality WPF apps onto the trader desks has been a big priority, and with F# I find myself more able to meet that challenge.

The WPF design pattern ‘du jour’ is MVVM. Anyone who’s serious about enterprise-strength development in WPF would have come across this pattern and probably have used it at some point in the recent past.

Detailed below is a very basic implementation where :-

  1. There is a WPF project that contains only Views
  2. There is a C# ‘model’ project that contains only the generated classes from SqlMetal (for Linq to SQL)
  3. The is an F# code library project that contains my ViewModel

The F# ViewModel is a very simple one, but it covers all the main bases:-

  1. It has a generic ICommand implementation for command binding
  2. It implements INotifyPropertyChanged for change notifications
  3. It has Data for binding

So here it is

#light
module FSharpMVVM
 
open System
open System.Windows.Input
open System.Data.SqlClient
open System.ComponentModel
open FsMVVM.DAL
 
// below is our Linq-SQL data context, created via SqlMetal and in a separate
// C# project - as SqlMetal doesnt generate F# yet *)
 
let ctx = new DataClassesDataContext()
 
// an implemnentation of a generic ICommand, that takes two functions
// one to see if the command can be executed, and one to execute the command 
 
type FuncCommand (canExec:(obj -> bool),doExec:(obj -> unit)) =
    let cecEvent = new DelegateEvent<EventHandler>()
    interface ICommand with
        [<CLIEvent>]
        member x.CanExecuteChanged = cecEvent.Publish
        member x.CanExecute arg = canExec(arg)
        member x.Execute arg = doExec(arg)
 
// Our ViewModel is below
 
type MainViewModel() =  
    let mutable prods = Seq.toList ctx.Products 
    let a =  new PropertyChangedEventArgs("ProductData")
    let propChangedEvent = new DelegateEvent<PropertyChangedEventHandler>()
    interface INotifyPropertyChanged with 
        [<CLIEvent>]
        member x.PropertyChanged = propChangedEvent.Publish
    member x.ProductData with get() = prods
    member x.FilterCommand = 
        new FuncCommand(
            (fun d -> not(Seq.isEmpty ctx.Products)),
            (fun e -> prods <- Seq.toList ctx.Products 
                    |> List.filter (
                        fun p -> p.ProductName.Contains(e.ToString()));
                        propChangedEvent.Trigger([| box x; box a|])))

 

and below is the simple View (XAML)

 

<Window x:Class="FsMVVM.WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="5">
            <TextBox Name="searchText" MinWidth="100" />
            <Button Content="Search" Command="{Binding FilterCommand}" 
                    CommandParameter="{Binding ElementName=searchText, Path=Text}" />
        </StackPanel>
        <ListView ItemsSource="{Binding ProductData}" Grid.Row="1">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding ProductName}" />
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

 

and finally, its wired up in the code-behind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new FSharpMVVM.MainViewModel();
    }
}

and that's all it takes

Now, I know that there isnt a great deal of functional programming in this example, but now I have the building blocks for a more complex ViewModel, that will no doubt include a great deal more FP before it is finished

 

Dean

Tags: ,

DataBinding | F# | MVVM

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010 Dean Chalk's Blog