views:

202

answers:

1

My Application layer uses DialogPresenters to show some ViewModels in various dialogs (modal, splash screen, etc..).

    public DataImportDialogPresenter(DataImportViewModel viewModel, IDialogView shellView, IDialogView owner)
        : base(viewModel, shellView, owner)
    {
        //Base sets the view data context etc.
        //Monitor CancelCommand and close the dialog
        viewModel.CancelCommand = new DelegateCommand(() => Terminate());
    }

This setup works really well except for the fact that if my ViewModel decides it needs to do something on the CancelCommand (which is perfectly reasonable) then it will replace the presenter's call to Terminate() or vice-versa.

What I would like to do is:

viewModel.CancelCommand += new DelegateCommand(() => Terminate());

In the same spirit as attaching event handlers.

  1. Is this possible in C#.NET 3.5?
  2. How would I achieve it?
  3. Is this bad MVVM practice?

Thanks

D

+2  A: 

You could use another implementation of the ICommand interface, that would wrap the original CancelCommand of the ViewModel :

public class WrapperDelegateCommand : ICommand
{
    private Action<object> _action;
    private ICommand _originalCommand;

    public WrapperDelegateCommand(Action<object> action, ICommand original)
    {
        _action = action;
        _originalCommand = original;
    }

    public bool CanExecute(object param)
    {
        if (originalCommand != null)
            return _originalCommand.CanExecute(param);
        return true;
    }

    public void Execute(object param)
    {
        if (_originalCommand != null)
            _originalCommand.Execute(param);
        _action(param);
    }

    public ICommand OriginalCommand { get { return _originalCommand; } }
}

You can then assign this command to the ViewModel's command :

viewModel.CancelCommand = new WrapperDelegateCommand(() => Terminate(), viewModel.CancelCommand);

And you should probably restore the original command in the Terminate method :

viewModel.CancelCommand = (viewModel.CancelCommand as WrapperDelegateCommand).OriginalCommand;
Thomas Levesque
That will work in my current use case. My only concern is that the viewmodel could unknowingly overwrite the command.
Daniel Skinner
I see your point... I usually initialize the command lazily in the getter. If you do that, and never change the command afterwards, it should work fine
Thomas Levesque