Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Silverlight : Simple PopUp Behavior for VM, MVVM

0.00/5 (No votes)
1 Sep 2010 2  
Behavior that will create a simple PopUp and run some ICommands when closed

A Behavior created by Haruhiro Isowa with assistance from Michael Washington.

Introduction

This article will show you how to use my PopUp Behavior that will launch a simple Yes/No Popup and explain how it works so you will be able to tune it to your needs. This PopUp should make creating PopUps in MVVM / VM style easier by generating the PopUp for you which will save you the time of creating a View and View Model for a Popup, remove the need for complexity shown by other solutions that uses messaging / services and so forth. This also allows designers to have some control to create PopUps without waiting for the programmers to make a View and VM for them.

What HisowaSimplePopUpBehavior Do

This is the PopUp that it generates, but you can customize by modding the code or by properties on behavior.

sample\

These are the Properties. (All properties under Miscellaneous are bindable).

Properties

  • Brushes are to set your background of the Buttons and PopUp Window, gradients, images, etc. are ok.
  • CustomParameter: object, you pass to the behavior and when the PopUp closes it will return that to you. You can pass selected object or ID, etc.
  • PopUpMessage: string, set the message for the PopUp
  • PopUpNoMessage: string, set the text on the No button
  • PopUpYesMessage: string, set the text on the Yes button
  • ReturnDialogResult: bool?, exposes the result of the PopUp (You can use two-way binding to pass back results. I used it to set IsChecked on a checkbox.
  • ReturnICommand: ICommand, The command to run when PopUp closes. It will pass in a dataholder class HisowaSimplePopUpBehaviorResult which will contain the DialogResult (bool?), DataContext of the Popup (Probably will not be used for this Popup Behavior ver), and InputParameter which is your CustomParameter you have set above.

By the properties of the behavior, you probably can guess what is going to happen. This Behavior will generate a simple Popup that you can set text, background values; pass in a parameter (probably useful to put the object in question); allow you to bind the DialogResult of the PopUp; and Most importantly run an ICommand when the PopUp Closes and passes you the DialogResult, DataContext, and the parameter you have passed so your ICommand can consume it.

Using my HisowaSimplePopUpBehavior

Start by opening a new Silverlight Application. Name it SimplePopUpBehaviorSample. Add my HisowaSimplePopUpBehavior class to your solution. Add a reference to System.Windows.Interactivity, and System.Windows.Controls. System.Windows.Interactivty is in Blend SDK. Build your project and open your MainPage.xaml in Expression Blend.

Before we can get started, we will need to have a View and ViewModel. Delete the MainPage.xaml in Blend. Add a new Item to the project by Right Clicking on the Project, select Add New Item. On the dialog, set User Control with ViewModel, name the file MainPage.xaml.

New Vm

Open the MainPage.xaml.

Drag a button on the page. Then look for my behavior HisowaSimplePopUpBehavior and drag it on the Button.

.behavior

Now Build and run it from Blend. You should now have a simple Popup. At this point, it's not doing anything cool.

ViewModel Code

We need to setup some code in the ViewModel. But before we get started, we will use John Papa's DelegateCommand.cs file. Get it from Delegate Command From John Papa.

Replace MainPageModel.cs code with this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using HisowaPopUpBehaviors;

namespace SimplePopUpBehaviorSample
{
    public class MainPageModel : INotifyPropertyChanged
    {
        public MainPageModel()
        {
            PopupSimpleResultCommand = new DelegateCommand
            (PopupSimpleResult, CanPopupSimpleResult);
        }

        #region PopupSimpleResultCommand
        public ICommand PopupSimpleResultCommand { get; set; }
        public void PopupSimpleResult(object param)
        {
            //cast to my DataContainer
            HisowaSimplePopUpBehaviorResult _result = 
            (HisowaSimplePopUpBehaviorResult)param;

            //get the dialogResult
            PopUpResult = _result.DialogResult;

            //get the input if exists
            if (_result.InputParameter != null)
            {
                Message = _result.InputParameter.ToString();
            }
        }

        private bool CanPopupSimpleResult(object param)
        {
            return true;
        }
        #endregion

        #region PopUpResult
        private bool? _PopUpResult;
        public bool? PopUpResult
        {
            get
            {
                return _PopUpResult;
            }
            set
            {
                _PopUpResult = value;
                this.NotifyPropertyChanged("PopUpResult");
            }
        }
        #endregion

        #region Message
        private string _Message;
        public string Message
        {
            get { return _Message; }
            private set
            {
                if (Message == value)
                {
                    return;
                }
                _Message = value;
                this.NotifyPropertyChanged("Message");
            }
        }
        #endregion

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
    }
}

This is just a simple VM that has single ICommand that sets the Popup result to the properties (string Message, bool? PopupResult). It also implements INotifyPropertyChanged.

*Note: You might need to fix namespaces if you didn't use the same name for the project.

Now Build and let's get back to Blend.

Using the Behavior part2, with Properties

Now that we got all the groundwork done, we can start using the HisowaSimplePopUpBehavior to its full potential.

First, we will need to make a UI similar to this for this demo.

UI

Bind these Text Values with Element Property Binding.

  • PopUpMessage: Your message Textbox's Text property
  • PopUpYes/NoMessage: Your Textbox's Text property
  • CustomParameter: Your Input Textbox's Text property (this allows object, it can be anything)

elemntbind

Bind ReturnDialogResult to Checkbox's IsChecked Property, two-way binding.

two

Build and Run. Now you should be able to change the text on your TextBox to what you typed in the textbox. The CheckBox should be checked if the popup was closed by the yes button.

sample

Should look like this.

Now we would like to set ReturnICommand the most important part of the Behavior. To do this, Databind the ReturnIcommand to the PopUpSimpleResultCommand and Build.

icom - Click to enlarge image

To check that it's working, go back to Visual Studio and put a breakpoint somewhere in the ICommand you binded. Then Debug in Visual Studio.

deb

Notice that Icommand is getting HisowaPopUpBehaviors class which holds the DialogResult, InputParameter(CustomParameter) and DataContext. You should be able to do a lot with these in your ICommand.

My Behavior Explained

In this section, I will explain the code of the Behavior. Most of them are dependency properties that allow the databindings, so I will skip over those.

This is the Invoke method, this gets called when the trigger is fired.

#region Invoke

        //Shows popup on event trigger you set in designer

        protected override void Invoke(object parameter)
        {
            ChildWindow _childWindow = new ChildWindow();
            _grid = new Grid();

            _grid.Width = 300;
            _grid.Height = 100;

            //width 3 cols
            _grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star) });
            _grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star) });
            _grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star) });

            //height 3 rows
            _grid.RowDefinitions.Add(new RowDefinition() 
        { Height = new GridLength(1, GridUnitType.Star) });
            _grid.RowDefinitions.Add(new RowDefinition());
            _grid.RowDefinitions.Add(new RowDefinition());

            //add message
            TextBlock tbkMessage = new TextBlock();
            tbkMessage.Text = PopUpMessage;
            tbkMessage.SetValue(Grid.RowProperty, 0);
            tbkMessage.SetValue(Grid.ColumnProperty, 0);
            tbkMessage.SetValue(Grid.ColumnSpanProperty, 3);

            _grid.Children.Add(tbkMessage);

            //add Yes button
            Button btnYes = new Button();
            btnYes.Content = PopUpYesMessage;
            btnYes.SetValue(Grid.ColumnProperty, 0);
            btnYes.SetValue(Grid.RowProperty, 1);
            btnYes.Name = "btnYes";
            btnYes.Click += new RoutedEventHandler(btnYes_Click);

            _grid.Children.Add(btnYes);

            //add No Button
            Button btnNo = new Button();
            btnNo.Content = PopUpNoMessage;
            btnNo.SetValue(Grid.ColumnProperty, 2);
            btnNo.SetValue(Grid.RowProperty, 1);
            btnNo.Name = "btnNo";
            btnNo.Click += new RoutedEventHandler(btnNo_Click);

            _grid.Children.Add(btnNo);

            //style
            _grid.Background = BackGroundColorParameter;
            btnYes.Background = YesColorParameter;
            btnNo.Background = NoColorParameter;

            //Make it a PopUp
            _childWindow.Content = _grid;

            PopUp = _childWindow;

            PopUp.Closing += new EventHandler<canceleventargs />(PopUp_Closing);

            PopUp.Show();

        }

        #endregion    

Basically it creates the UI, sets the event handlers and assigns the properties from the behavior such as background and message. This is where you will tweak to change the UI.

Now the event handling code for the Yes/No buttons.

#region BtnClicks

        void btnNo_Click(object sender, RoutedEventArgs e)
        {
            RemoveButtonHandlers();
            PopUp.DialogResult = false;
        }

        void btnYes_Click(object sender, RoutedEventArgs e)
        {
            RemoveButtonHandlers();
            PopUp.DialogResult = true;
        }

        private void RemoveButtonHandlers()
        {
            Button btnYes = (Button)_grid.FindName("btnYes");
            btnYes.Click -= new RoutedEventHandler(btnYes_Click);

            Button btnNo = (Button)_grid.FindName("btnNo");
            btnNo.Click -= new RoutedEventHandler(btnNo_Click);
        }

        #endregion

This sets the DialogResults which also closes the PopUp, and removes the event handlers.

Now the code for PopUpClosing event:

#region ChildwindowClosing

        //Runs an Icommand when the Popup is closing
        //you can change what it passes to Icommand to whatever you like
        //be sure that your method can consume them


        void PopUp_Closing(object sender, CancelEventArgs e)
        {
            PopUp.Closing -= new EventHandler<canceleventargs />(PopUp_Closing);

            ReturnDialogResultCommand = PopUp.DialogResult;

            if (ReturnICommand != null)
            {
                HisowaSimplePopUpBehaviorResult _result = 
			new HisowaSimplePopUpBehaviorResult();
                _result.DialogResult = PopUp.DialogResult;
                _result.DataContext = PopUp.DataContext;
                _result.InputParameter = CustomParameter;

                ReturnICommand.Execute(_result);
            }
        }

        #endregion

All this does is remove the handler, get the Icommand from the dependency property, create my datacontainer HisowaSimplePopUpBehaviorResult, and run the Icommand passing the HisowaSimplePopUpBehaviorResult.

Lastly, the DataContainer HisowaSimplePopUpBehaviorResult class which is in the same file.

public class HisowaSimplePopUpBehaviorResult
    {
        public bool? DialogResult { get; set; }
        public object DataContext { get; set; }
        public object InputParameter { get; set; }
    }

This is just a simple data holder.

Full Code

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.ComponentModel;
using System.Reflection;

namespace HisowaPopUpBehaviors
{
    [System.ComponentModel.Description("Launches a Simple Popup on Event Trigger")]
    public class HisowaSimplePopUpBehavior : TargetedTriggerAction<frameworkelement />, 
    INotifyPropertyChanged
    {
        private ChildWindow PopUp;
        Grid _grid = new Grid();

        //constructor
        public HisowaSimplePopUpBehavior()
        { }

        #region CustomParameterProperty
        public static readonly DependencyProperty CustomParameterProperty = 
    DependencyProperty.Register("CustomParameter", typeof(object), 
    typeof(HisowaSimplePopUpBehavior), null);

        public object CustomParameter
        {
            get
            {
                return base.GetValue(CustomParameterProperty);
            }
            set
            {
                base.SetValue(CustomParameterProperty, value);
            }
        } 
        #endregion

        #region ReturnDialogResultCommandProperty

        public static readonly DependencyProperty ReturnDialogResultCommandProperty = 
    DependencyProperty.Register("ReturnDialogResultCommand", typeof(bool?), 
    typeof(HisowaSimplePopUpBehavior), null);

        public bool? ReturnDialogResultCommand
        {
            get
            {
                return (bool?)base.GetValue(ReturnDialogResultCommandProperty);
            }
            set
            {
                base.SetValue(ReturnDialogResultCommandProperty, value);
                this.NotifyPropertyChanged("ReturnDialogResultCommand");
            }
        }
        #endregion

        #region ReturnICommandProperty

        public static readonly DependencyProperty ReturnICommandProperty = 
    DependencyProperty.Register("ReturnICommand", typeof(ICommand), 
    typeof(HisowaSimplePopUpBehavior), null);

        public ICommand ReturnICommand
        {
            get
            {
                return (ICommand)base.GetValue(ReturnICommandProperty);
            }
            set
            {
                base.SetValue(ReturnICommandProperty, value);
            }
        }
        #endregion

        #region PopUpMessageProperty

        public static readonly DependencyProperty PopUpMessageProperty = 
    DependencyProperty.Register("PopUpMessage", typeof(string), 
    typeof(HisowaSimplePopUpBehavior), null);

        public string PopUpMessage
        {
            get
            {
                if (base.GetValue(PopUpMessageProperty) == null)
                {
                    return "Are you sure?";
                }
                else
                {
                    return (string)base.GetValue(PopUpMessageProperty);
                }
            }
            set
            {
                base.SetValue(PopUpMessageProperty, value);
            }
        }

        #endregion

        #region PopUpYesMessageProperty

        public static readonly DependencyProperty PopUpYesMessageProperty = 
    DependencyProperty.Register("PopUpYesMessage", typeof(string), 
    typeof(HisowaSimplePopUpBehavior), null);

        public string PopUpYesMessage
        {
            get
            {
                if (base.GetValue(PopUpYesMessageProperty) == null)
                {
                    return "Yes";
                }
                else
                {
                    return (string)base.GetValue(PopUpYesMessageProperty);
                }
            }
            set
            {
                base.SetValue(PopUpYesMessageProperty, value);
            }
        }

        #endregion

        #region PopUpNoMessageProperty

        public static readonly DependencyProperty PopUpNoMessageProperty = 
    DependencyProperty.Register("PopUpNoMessage", typeof(string), 
    typeof(HisowaSimplePopUpBehavior), null);

        public string PopUpNoMessage
        {
            get
            {
                if (base.GetValue(PopUpNoMessageProperty) == null)
                {
                    return "No";
                }
                else
                {
                    return (string)base.GetValue(PopUpNoMessageProperty);
                }
            }
            set
            {
                base.SetValue(PopUpNoMessageProperty, value);
            }
        }

        #endregion

        #region BackgroundColor
        public static readonly DependencyProperty BackGroundColorParameterProperty = 
    DependencyProperty.Register("BackGroundColorParameter", 
    typeof(System.Windows.Media.Brush), typeof(HisowaSimplePopUpBehavior), null);

        public System.Windows.Media.Brush BackGroundColorParameter
        {
            get
            {
                return (System.Windows.Media.Brush)base.GetValue
            (BackGroundColorParameterProperty);
            }
            set
            {
                base.SetValue(BackGroundColorParameterProperty, value);
            }
        }
        #endregion

        #region YesColor
        public static readonly DependencyProperty YesColorParameterProperty = 
    DependencyProperty.Register("YesColorParameter", 
    typeof(System.Windows.Media.Brush), typeof(HisowaSimplePopUpBehavior), null);

        public System.Windows.Media.Brush YesColorParameter
        {
            get
            {
                return (System.Windows.Media.Brush)base.GetValue
            (YesColorParameterProperty);
            }
            set
            {
                base.SetValue(YesColorParameterProperty, value);
            }
        }
        #endregion

        #region NoColor
        public static readonly DependencyProperty NoColorParameterProperty = 
    DependencyProperty.Register("NoColorParameter", 
    typeof(System.Windows.Media.Brush), typeof(HisowaSimplePopUpBehavior), null);

        public System.Windows.Media.Brush NoColorParameter
        {
            get
            {
                return 
		(System.Windows.Media.Brush)base.GetValue(NoColorParameterProperty);
            }
            set
            {
                base.SetValue(NoColorParameterProperty, value);
            }
        }
        #endregion

        #region Invoke

        //Shows popup on event trigger you set in designer

        protected override void Invoke(object parameter)
        {
            ChildWindow _childWindow = new ChildWindow();
            _grid = new Grid();

            _grid.Width = 300;
            _grid.Height = 100;

            //width 3 cols
            _grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star) });
            _grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star) });
            _grid.ColumnDefinitions.Add(new ColumnDefinition() 
        { Width = new GridLength(1, GridUnitType.Star) });

            //height 3 rows
            _grid.RowDefinitions.Add(new RowDefinition() 
        { Height = new GridLength(1, GridUnitType.Star) });
            _grid.RowDefinitions.Add(new RowDefinition());
            _grid.RowDefinitions.Add(new RowDefinition());

            //add message
            TextBlock tbkMessage = new TextBlock();
            tbkMessage.Text = PopUpMessage;
            tbkMessage.SetValue(Grid.RowProperty, 0);
            tbkMessage.SetValue(Grid.ColumnProperty, 0);
            tbkMessage.SetValue(Grid.ColumnSpanProperty, 3);

            _grid.Children.Add(tbkMessage);

            //add Yes button
            Button btnYes = new Button();
            btnYes.Content = PopUpYesMessage;
            btnYes.SetValue(Grid.ColumnProperty, 0);
            btnYes.SetValue(Grid.RowProperty, 1);
            btnYes.Name = "btnYes";
            btnYes.Click += new RoutedEventHandler(btnYes_Click);

            _grid.Children.Add(btnYes);

            //add No Button
            Button btnNo = new Button();
            btnNo.Content = PopUpNoMessage;
            btnNo.SetValue(Grid.ColumnProperty, 2);
            btnNo.SetValue(Grid.RowProperty, 1);
            btnNo.Name = "btnNo";
            btnNo.Click += new RoutedEventHandler(btnNo_Click);

            _grid.Children.Add(btnNo);

            //style
            _grid.Background = BackGroundColorParameter;
            btnYes.Background = YesColorParameter;
            btnNo.Background = NoColorParameter;

            //Make it a PopUp
            _childWindow.Content = _grid;

            PopUp = _childWindow;

            PopUp.Closing += new EventHandler<canceleventargs />(PopUp_Closing);

            PopUp.Show();
        }

        #endregion

        #region BtnClicks

        void btnNo_Click(object sender, RoutedEventArgs e)
        {
            RemoveButtonHandlers();
            PopUp.DialogResult = false;
        }

        void btnYes_Click(object sender, RoutedEventArgs e)
        {
            RemoveButtonHandlers();
            PopUp.DialogResult = true;
        }

        private void RemoveButtonHandlers()
        {
            Button btnYes = (Button)_grid.FindName("btnYes");
            btnYes.Click -= new RoutedEventHandler(btnYes_Click);

            Button btnNo = (Button)_grid.FindName("btnNo");
            btnNo.Click -= new RoutedEventHandler(btnNo_Click);
        }

        #endregion

        #region ChildwindowClosing

        //Runs an Icommand when the Popup is closing
        //you can change what it passes to Icommand to whatever you like
        //be sure that your method can consume them


        void PopUp_Closing(object sender, CancelEventArgs e)
        {
            PopUp.Closing -= new EventHandler<canceleventargs />(PopUp_Closing);

            ReturnDialogResultCommand = PopUp.DialogResult;

            if (ReturnICommand != null)
            {
                HisowaSimplePopUpBehaviorResult _result = 
            new HisowaSimplePopUpBehaviorResult();
                _result.DialogResult = PopUp.DialogResult;
                _result.DataContext = PopUp.DataContext;
                _result.InputParameter = CustomParameter;

                ReturnICommand.Execute(_result);
            }
        }

        #endregion

        // Utility

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
    }

    public class HisowaSimplePopUpBehaviorResult
    {
        public bool? DialogResult { get; set; }
        public object DataContext { get; set; }
        public object InputParameter { get; set; }
    }
} 

Also see: HisowaModPopUpBehavior

This variation will allow you to use your own View and View Model and inject it into the popup.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here