MVVM Tips: How to close the current window / dialog?

To keep your ViewModel separated from the View we would like to make sure the ViewModel knows as little about the UI as possible, this includes no hard references. So how do we close the window?

I like to create a abstract ViewModel class specifically for this purpose which extends from my ViewModel base class and adds an event called RequestClose. Lets call it CloseableViewModel.

public abstract class CloseableViewModel : ViewModel
{
    public event EventHandler RequestClose;

    protected OnRequestClose()
    {
        if (RequestClose != null)
            RequestClose(this, EventArgs.Empty);
    }
}

Now just make sure your view model extends the CloseableViewModel. When you are linking your ViewModel to your view add a listener to the event

public partial class DialogView : ChildWindow
{
    public DialogView(DialogViewModel model)
    {
        this.DataContext = model;
        model.RequestClose += delegate (object sender, EventArgs args) { this.Close(); }
    }
}

When you want to close the window from your ViewModel call OnRequestClose();

Easy as that, and your ViewModel doesn’t need to know about your View 🙂

Advertisements

MVVM Tips: How to show a message box or dialog in MVVM Silverlight?

The key to successfully separating the concerns of your application is all in the abstraction.

Of course we do not want to call MessageBox.Show() from within our ViewModel as this will not allow us to automatically test it. We will need to abstract the call to MessageBox.Show() so that you can swap it out for testing. A simple way to do this is to use a service implementing an interface that we can swap out depending on whether we are testing or running the application.


public interface IMsgBoxService
{
    ShowNotification(string message);
    bool AskForConfirmation(string message);
    //... etc
}

public class MsgBoxService : IMsgBoxService
{
    public void ShowNotification(string message)
    {
        MessageBox.Show(message, "Notification", MessageBoxButton.OK)
    }

    public bool AskForConfirmation(string message)
    {
            MessageBoxResult result = MessageBox.Show(message, "Are you sure?", MessageBoxButton.OKCancel);
            return result.HasFlag(MessageBoxResult.OK);
    }
}

Now that we have implemented our message box service we just need to get an instance of it and call the appropriate method in our ViewModel


private IMsgBoxService messageService;
public TestViewModel(IMsgBoxService msgboxService)
{
   this.messageService = msgboxService;
}

public void SomeMethod()
{
    messageService.ShowNotification("Hey!");
}

There it is, a few lines of code and you have a message box you can safely use throughout your application in a MVVM way that will allow for testability and seperation of concerns.

Lots more MVVM tips to come so subscribe if you would like to stay updated. Thanks!

MVVM Tips: ViewModel INotifyPropertyChanged compile time errors with Visual Studio Refactoring

Ok so I’m not too much of a fan of strings used to represent variable/property/method names. Say, INotifyPropertyChanged, no Visual Studio Refactor support for renaming and you could accidentally type the wrong string, resulting in no compile error as shown below.

    private string name;
    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
            RaisePropertyChanged("Names");
        }
    }

I came across a great little helper function created by the Microsoft Patterns and Practices guys to fix this problem. In your ViewModel base class, try adding this:


        protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpresssion)
        {
            var propertyName = ExtractPropertyName(propertyExpresssion);
            this.RaisePropertyChanged(propertyName);
        }

        private string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            if (propertyExpression == null)
            {
                throw new ArgumentNullException("propertyExpression");
            }

            var memberExpression = propertyExpression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new ArgumentException("The expression is not a member access expression.", "propertyExpression");
            }

            var property = memberExpression.Member as PropertyInfo;
            if (property == null)
            {
                throw new ArgumentException("The member access expression does not access a property.", "propertyExpression");
            }

            if (!property.DeclaringType.IsAssignableFrom(this.GetType()))
            {
                throw new ArgumentException("The referenced property belongs to a different type.", "propertyExpression");
            }

            var getMethod = property.GetGetMethod(true);
            if (getMethod == null)
            {
                // this shouldn't happen - the expression would reject the property before reaching this far
                throw new ArgumentException("The referenced property does not have a get method.", "propertyExpression");
            }

            if (getMethod.IsStatic)
            {
                throw new ArgumentException("The referenced property is a static property.", "propertyExpression");
            }

            return memberExpression.Member.Name;
        }

Now you can do this:

    private string name;
    public string Name
    {
        get  {  return name; }
        set
        {
            name = value;
            RaisePropertyChanged(() => this.Name);
        }
    }

and get compile time error handling of INotifyPropertyChanged