Ok cancel Dialog MVVM Pattern wpf.How can I do it

here is a barebones dialog with OK and Cancel buttons. I have included the XAML, View, and ViewModel:

XAML:

<Window
    x:Class="TestProject.Views.OKCancelDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
    Title="Window Title"
    Height="300"
    Width="600"
    WindowStartupLocation="CenterOwner"
    WindowStyle="ToolWindow"
    ResizeMode="CanResize"
    UseLayoutRounding="True"
    TextOptions.TextFormattingMode="Display">

    <Grid>
        <Button
            Name="OKButton"
            Content="OK"
            Height="23"
            HorizontalAlignment="Right" 
            Margin="0,0,93,12"
            VerticalAlignment="Bottom" 
            Width="75" 
            Click="OKButton_Click"
            IsDefault="True"
            Command="{Binding OKButtonCommand}" />

        <Button
            Name="CancelButton"
            Content="Cancel" 
            Height="23" 
            HorizontalAlignment="Right" 
            Margin="0,0,12,12"
            VerticalAlignment="Bottom"
            Width="75" 
            IsCancel="True" />
    </Grid>
</Window>

Codebehind:

using System.Windows;
using TestProject.ViewModel;

namespace TestProject.Views
{
    public partial class OKCancelDialog : Window
    {
        private readonly OKCancelViewModel viewModel;

        //I use DI to inject the ViewModel into the View
        //This will allow you to use the view for different ViewModels if you need to.
        //Create an Interface for your ViewModel to implement to make ViewModel unit testing
        //easier. Testing frameworks such as rhino mock require Interfaces to test methods
        //in a class under test and it allows you to use an IoC Container to create the
        //ViewModel for you.                 
        public OpenReturnDialog(IOKCancelViewModel viewModel)
        {
            InitializeComponent();
            this.viewModel = viewModel; //Do this if you need access to the VM from inside your View. Or you could just use this.Datacontext to access the VM.
            this.DataContext = viewModel;
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }

    }
}

ViewModel

using Microsoft.Practices.Composite.Presentation.Commands;


namespace TestProject.ViewModel
{
    public class OKCancelViewModel
    {
        public OKCancelViewModel()
        {
            OKButtonCommand = new DelegateCommand<object>(HandleOKButtonCommand, CanExecuteOKButtonCommand);
        }

        public DelegateCommand<object> OKButtonCommand { get; private set; }

        public void HandleOKButtonCommand(object obj)
        {
             //Here is where your code for OK button clicks go.

        }

        public bool CanExecuteOKButtonCommand(object obj)
        {
            //Put code to determine when the OK button will be enabled/disabled.
        } 

        //You may want to add a command for the Cancel button also if you have a need to 
        //enable/disable the cancel button
        //The command will look just like the OK button command above.
    }
}

Now, you will most likely want to have your ViewModel implement INotifyPropertyChanged in the event you have other controls in your UI that will bind to properties in the ViewModel.

Hope this helps...


I think everyone else that uses an IDialogService or actually creates their own dialogs is over engineering the problem. I really like the simplistic approach of using Funcs. Here is an example. First add this to your ViewModel:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    /** Other ViewModel Code *//

    public Func<string, string, bool> OkCancelDialog { get; set; }
}

Then when you instantiate your derived class of your ViewModel, you just attach the following code: (I typically do this in the startup like Program.cs)

var myVM = new SomeSuperViewModel();
myVM.OkCancelDialog = (msg, caption) => MessageBox.Show(msg, caption, MessageBoxButton.OkCancel) == MessageBoxResult.OK;

In your actual ViewModel code, all you have to do is call:

if (OkCancelDialog("Some crazy message.", "Caption"))
    //do something if true
else
    //else do something if false

In your unit tests you can do this:

var myVMToTest = new SomeSuperViewModel();
myVMToTest.OkCancelDialog = (msg, caption) => true; //could be false too if you need to test that functionality.

I prefer this approach, as it's simple and easy to test. What do other's think?

Tags:

Wpf

Mvvm