22 February 2012

Behavior to show a MessageBox from a ViewModel

Since I am a very lazy programmer and I not always want to register or define services and whatnot for showing a simple message I created this extremely simple behavior for showing a MessageBox from a ViewModel. I wrote the code for Windows Phone 7, but I suppose it could be used in Silverlight as well.

The behavior itself is as simple as this:

using System.Windows;
using System.Windows.Interactivity;

namespace Wp7nl.Behaviors
{
  public class MessageBoxDisplayBehavior : Behavior<FrameworkElement>
  {
    public const string MessagePropertyName = "Message";

    public string Message
    {
      get { return (string)GetValue(MessageProperty); }
      set { SetValue(MessageProperty, value); }
    }

    public static readonly DependencyProperty MessageProperty =
      DependencyProperty.Register(
        MessagePropertyName,
        typeof(string),
        typeof(MessageBoxDisplayBehavior),
        new PropertyMetadata(string.Empty, MessageChanged));

    public static void MessageChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e)
    {
      var msg = e.NewValue as string;
      if (!string.IsNullOrEmpty(msg))
      {
        MessageBox.Show(msg);
      }
    }
  }
}

Easiest way to use it is to just drag it onto about any control in your Page using Blend, as long as it has the right data context, and select a string property to bind it to. In XAML, it usage looks something like this:

<Grid DataContext="{Binding ChooserViewModel}">
 <i:Interaction.Behaviors>
  <Wp7nl_Behaviors:MessageBoxDisplayBehavior 
    Message="{Binding MessageBoxMessage, Mode=TwoWay}"/>
 </i:Interaction.Behaviors>

Just one the one thing you might want to consider is how you define “MessageBoxMessage” in your ViewModel. I defined it as follows:

private string messageBoxMessage;
public string MessageBoxMessage
{
  get { return messageBoxMessage; }
  set
  {
    messageBoxMessage = value;
    RaisePropertyChanged(() => MessageBoxMessage);
  }
}
as opposed to what you would normally do, which is
private string messageBoxMessage;
public string MessageBoxMessage
{
  get { return messageBoxMessage; }
  set
  {
    if (messageBoxMessage != value)
    {
      messageBoxMessage = value;
      RaisePropertyChanged(() => MessageBoxMessage);
    }
  }
}
I intentionally left out the value check (in red), so RaisePropertyChanged always fires. This gives the real stupid mentally challenged users that make the same error multiple times multiple message boxes as well ;-)

3 comments:

Pedro Lamas said...

Please don't call the users "stupid": they are just mentally challanged!!! :)

Joost van Schaik said...

@Pedro thank you - updated ;-)

Wiyono Aten said...

Nice utility! Thanks! I found an issue though, that the messagebox can be triggered multiple times successively because the Behavior is never detached from the page and as the page (new instance) is revisited, multiple MessageChanged subscriptions will be fired. I found that I needed to make sure to call ClearValue(MessageProperty) to clear the binding on AssociatedObject.Unloaded to prevent that.