Click here to Skip to main content
Click here to Skip to main content

Silverlight View Model Style Popup

, 1 Sep 2010 Ms-PL
Rate this:
Please Sign up or sign in to vote.
An example of an easy to use View Modal Style Popup and Silverlight Value Converter

A Silverlight View Model Style Popup

Live example: http://silverlight.adefwebserver.com/mvvmpopup/default.aspx

How to Unit Test the PopUp: SMVVMUnitTest.aspx

Note: Also see this newer version that is easier to use: Silverlight : Simple PopUp Behavior for VM, MVVM

See this version that is fully MVVM: HisowaModPopUpBehavior

The View Model pattern allows a programmer to create an application that has absolutely no UI (user interface). The programmer only creates a ViewModel and a Model. A designer with no programming ability at all, is then able to start with a blank page and completely create the View (UI) in Microsoft Expression Blend 4 (or higher). If you are new to View Model it is suggested that you read Silverlight View Model: An (Overly) Simplified Explanation for an introduction.

This article demonstrates how you can easily implement a Modal popup. It also demonstrates the implementation of a Value Converter. We will use graphics from Alan Beasley’s 10 Cool Buttons for Download in Expression Blend & Silverlight.

The Basic Popup

You click the Show Window button and the modal popup appears. You select Yes or No and click OK or Cancel.

The results of the Combo Box selection, and the button clicked, will show up on the main page.

The Popup Meets the Designer

We use View Model because, we want to allow a Designer, to easily change the design of an application, without requiring any code changes.

When the Designer opens the project up in Microsoft Expression Blend, they will see the MainPage.xaml file and the PopUpWindow.xaml file. The Designer knows that they can alter any file with a .xaml extension to re-design the application.

When the Designer opens the PopUpViewModel.xaml file, and they also open the Data window, they see that there is a Data Context associated with this control. The arrows in the graphic above, indicate what is currently bound to what.

The Re-Design

The Designer deletes the existing items and replaces them with a new design (the graphics are from Alan Beasley’s 10 Cool Buttons for Download in Expression Blend & Silverlight. I was also able to get Alan Beasley to do the actual layout of the popup).

Hooking the new OK and Cancel buttons is easy, The Designer simply drops a InvokeCommandAction behavior on each button.

In the Properties for each button, Click is selected for EventName, and the DataBind button is clicked next to Command.

The button is then bound to the appropriate ICommand in the associated View Model.

Dude We Need A Value Converter!

One of the reasons we use View Model, is that it allows a "separation of concerns". A Designer can completely change a design without the Developer needing to change any code.

However, in this case, the original design had a Combo Box bound to a String value (SelectedPopUpValueProperty), in the View Model. In the new design, the Designer wants to use a Toggle Button control that uses a boolean (IsChecked). Expression Blend will not allow the Designer to bind IsChecked to SelectedPopUpValueProperty.

So the Designer calls the Developer up, who is vacationing in Aruba after turning in his View Model (after unit testing it to assure he met the requirements), and explains the problem. The Developer responds:

"Dude are you serious? If I had any idea a Toggle Button was going to be in the design I would have simply made a boolean property for you to bind to in the View Model, and that property would have set the SelectedPopUpValueProperty that the main page is using."

"The problem is, the View Model is now being worked on by the New York office and you don't want to deal with those guys. We have to fix this without changing the View Model at all. I will whip up a Value Converter and you can just use that."

"When you check-in your .xaml page into source control, you will also check-in the file I give you. The guys in New York will not have to change what they are doing at all, it will just work."

The Value Converter

The Designer drops the Value Converter file (BoolToStringConverter.cs), into the project and hits the F5 key to build the project (so the file will be built and it can be used). The Designer then uses the following steps to create the binding:

  • Clicks the Use a custom path expression box
  • Enters the name of the property to bind to (SelectedPopUpValueProperty) in the box
  • Selects the BoolToStringConverter in the Value converter drop down.
  • Clicks OK

The application is complete!

The Code - Making a Popup

When you create a new Silverlight Child Window control...

It creates a control with a code behind and OK and Cancel buttons with event handlers.

Remove the event handlers from the buttons and clear out all the methods in the code behind.

Create a class file (PopUpViewModel.cs) that will serve as the View Model for the Popup:

    public class PopUpViewModel : INotifyPropertyChanged
    {
        private ChildWindow PopUP;
 
        public PopUpViewModel()
        {
            // Set the command property
            SetPopUpCommand = new DelegateCommand(SetPopUp, CanSetPopUp);
            OKButtonCommand = new DelegateCommand(OKButton, CanOKButton);
            CancelButtonCommand = new DelegateCommand(CancelButton, CanCancelButton);
 
            SelectedPopUpValueProperty = "Yes";
        }
 
        // Commands
 
        #region SetPopUpCommand
        public ICommand SetPopUpCommand { get; set; }
        public void SetPopUp(object param)
        {
            PopUP = (ChildWindow)param;
        }
 
        private bool CanSetPopUp(object param)
        {
            return true;
        }
        #endregion
 
        #region OKButtonCommand
        public ICommand OKButtonCommand { get; set; }
        public void OKButton(object param)
        {
            PopUP.DialogResult = true;
        }
 
        private bool CanOKButton(object param)
        {
            return true;
        }
        #endregion
 
        #region CancelButtonCommand
        public ICommand CancelButtonCommand { get; set; }
        public void CancelButton(object param)
        {
            PopUP.DialogResult = false;
        }
 
        private bool CanCancelButton(object param)
        {
            return true;
        }
        #endregion
 
        // Properties
 
        #region SelectedPopUpValueProperty
        private string _SelectedPopUpValueProperty;
        public string SelectedPopUpValueProperty
        {
            get
            {
                return this._SelectedPopUpValueProperty;
            }
            set
            {
                this._SelectedPopUpValueProperty = value;
                this.NotifyPropertyChanged("SelectedPopUpValueProperty");
            }
        }
        #endregion
 
        // Utility
           
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
 
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion        
    }

This class does the following:

  • Implements INotifyPropertyChanged so that the UI is automatically updated when values in the View Model are updated
  • Creates a property for the Selected PopUp Value (SelectedPopUpValueProperty)
  • Creates ICommands for the OK and Cancel buttons
  • Creates an ICommand that allows an instance of the PopUp UI to be set (SetPopUpCommand)

Databind The Popup UI to the View Model

The Popup is simple because we are basically passing an instance of the entire Popup UI to the View Model. The View Model then has access to all the functionality of the Popup. Programming the Popup is as easy as if it were done using normal code behind, however, it's still View Model, so the Designer has full control over the UI.

In Blend, in the Objects and Timeline window, you drop a InvokeCommandAction behavior on childWindow.

In the Properties for the InvokeCommandAction behavior, you set the EventName to Loaded, and Data bind the Command to SetPopUpCommand.

You then bind the CommandParameter to the PopUpWindow.

Calling The PopUp From The Main View

Calling the Popup from the View Model of the main View (MainViewModel.xaml) is easy:

Drop a InvokeCommandAction behavior on the button, and configure it to call the ShowPopUPCommand method in the View Model.

Here is the complete code for the View Model:

    public class MainViewModel : INotifyPropertyChanged
    {
        private ChildWindow PopUP;
 
        public MainViewModel()
        {
            // Create popup(s)
            PopUP = new PopUpWindow();
 
            // Set the command property
            PopUP.Closed += new EventHandler(PopUP_Closed);
            ShowPopUPCommand = new DelegateCommand(ShowPopUP, CanShowPopUP);
        }
 
        // Commands
 
        #region ShowPopUPCommand
        public ICommand ShowPopUPCommand { get; set; }
        public void ShowPopUP(object param)
        {
            // Show PopUP
            PopUP.Show();
        }
 
        private bool CanShowPopUP(object param)
        {
            return true;
        }
        #endregion
 
        // Properties
 
        #region SelectedPopUpValueProperty
        private string _SelectedPopUpValueProperty;
        public string SelectedPopUpValueProperty
        {
            get
            {
                return this._SelectedPopUpValueProperty;
            }
            set
            {
                this._SelectedPopUpValueProperty = value;
                this.NotifyPropertyChanged("SelectedPopUpValueProperty");
            }
        }
        #endregion
 
        // Events
 
        #region PopUP_Closed
        void PopUP_Closed(object sender, EventArgs e)
        {
            // Was there a response at all?
            if (PopUP.DialogResult != null)
            {
                // Set the selected value
                bool boolDialogResult = (PopUP.DialogResult != null) ?
                    Convert.ToBoolean(PopUP.DialogResult) : false;
                PopUpViewModel objPopUpViewModel = (PopUpViewModel)PopUP.DataContext;
 
                SelectedPopUpValueProperty = String.Format("{0} - {1}",
                    objPopUpViewModel.SelectedPopUpValueProperty,
                    (boolDialogResult) ? "OK" : "Cancel");
            }
        }
        #endregion
 
        // Utility
           
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
 
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion        
    }

The Type Converter

Oh yes, that file that the Developer whipped up in Aruba, here it is:

    public class BoolToStringConverter : IValueConverter
    {
        #region IValueConverter Members
 
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if ((string)value == "No")
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if ((bool)value == true)
            {
                return "No";
            }
            else
            {
                return "Yes";
            }
        }
 
        #endregion
    }

This Seems Too Easy...

Some would argue that creating Popups like this, is tying your View Model to the Popup, and that is wrong because the Popup is a UI element. However, the Popup is a function that the View Model is performing, not the View (the View only requested the PopUp to be shown). It is displayed in front of the View and it sends values back to the View thru bindings, but it belongs to the View Model. So, it is perfectly fine for the View Model to directly instantiate a Popup class just as it would another class such as a web service.

Hey We Added Code!

We care about View Model, because we want to allow the Designer the freedom to design the application without code changes, and this example achieves that. Ok perhaps a Value Converter may need to be added is some situations, but, even in this case, the View Model did not need to be changed.

If the Developer is wearing both hats, and is also the Designer, it may be easier to just alter the View Model if a property type needs to be added or changed, however, you have options. A Value Converter allows you to bind UI elements to the View Model when the View Model is faced with an unexpected change.

How Do I Get Started With Silverlight?

To learn how to use Expression Blend, all you have to do is go to:

http://www.microsoft.com/design/toolbox/

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

defwebserver
Software Developer (Senior) http://ADefWebserver.com
United States United States
Michael Washington is a Microsoft MVP. He is a ASP.NET and
C# programmer.
He is the founder of
LightSwitchHelpWebsite.com

He has a son, Zachary and resides in Los Angeles with his wife Valerie.

He is the Author of:
Follow on   Twitter

Comments and Discussions

 
Question[My vote of 1] Misinformation PinmemberAustin Harris25-Jul-12 13:24 
AnswerRe: [My vote of 1] Misinformation Pinmemberdefwebserver25-Jul-12 13:49 
GeneralRe: [My vote of 1] Misinformation PinmemberAustin Harris30-Jul-12 11:34 
GeneralRe: [My vote of 1] Misinformation Pinmemberdefwebserver30-Jul-12 12:39 
QuestionNeed right guideline Pinmembersumantamca30-Nov-10 19:22 
AnswerRe: Need right guideline Pinmemberdefwebserver30-Nov-10 19:39 
GeneralRe: Need right guideline Pinmembersumantamca1-Dec-10 17:49 
GeneralRocking Example Pinmembersaranyan.y@gmail.com6-Jul-10 1:07 
GeneralRe: Rocking Example Pinmemberdefwebserver6-Jul-10 3:56 
GeneralYou've Made a Classic Mistake PinmemberEisenbergEffect1-May-10 3:20 
GeneralRe: You've Made a Classic Mistake [modified] PinmemberEisenbergEffect1-May-10 3:26 
GeneralRe: You've Made a Classic Mistake Pinmemberdefwebserver1-May-10 4:09 
GeneralRe: You've Made a Classic Mistake Pinmemberdefwebserver1-May-10 3:41 
GeneralRe: You've Made a Classic Mistake PinmemberEisenbergEffect1-May-10 4:54 
GeneralRe: You've Made a Classic Mistake PinmemberEisenbergEffect1-May-10 4:56 
GeneralRe: You've Made a Classic Mistake PinmemberEisenbergEffect1-May-10 5:23 
GeneralRe: You've Made a Classic Mistake Pinmemberdefwebserver1-May-10 7:04 
GeneralRe: You've Made a Classic Mistake PinmemberRobert Kozak4-May-10 2:24 
GeneralRe: You've Made a Classic Mistake Pinmemberdefwebserver4-May-10 17:30 
GeneralNice Article Pinmemberlinuxjr30-Apr-10 14:00 
GeneralRe: Nice Article Pinmemberdefwebserver30-Apr-10 15:02 
GeneralWhilst I like what you do generally I do not like this approach for the following reasons [modified] PinmvpSacha Barber30-Apr-10 7:00 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons Pinmemberdefwebserver30-Apr-10 7:45 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons PinmvpSacha Barber30-Apr-10 23:39 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons Pinmemberdefwebserver1-May-10 4:00 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons PinmvpSacha Barber1-May-10 21:15 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons Pinmemberdefwebserver2-May-10 19:11 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons PinmvpSacha Barber2-May-10 22:43 
GeneralOhhh, A bun fight, can I play? :-) [modified] PinmemberAlan Beasley30-Apr-10 9:02 
GeneralRe: Ohhh, A bun fight, can I play? :-) Pinmemberdefwebserver30-Apr-10 9:15 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmemberAlan Beasley30-Apr-10 9:36 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmemberDewey30-Apr-10 23:02 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmvpSacha Barber30-Apr-10 23:44 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmemberAlan Beasley1-May-10 1:51 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmvpSacha Barber30-Apr-10 23:41 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmemberAlan Beasley1-May-10 2:00 
GeneralRe: Ohhh, A bun fight, can I play? :-) PinmvpSacha Barber1-May-10 3:51 
GeneralIt's MVVM tastic!!! PinmemberAlan Beasley30-Apr-10 0:30 
GeneralRe: It's MVVM tastic!!! Pinmemberdefwebserver30-Apr-10 3:22 
GeneralRe: It's MVVM tastic!!! PinmemberAlan Beasley30-Apr-10 3:41 
GeneralYou've gone MVVM Crazy... PinmemberDewey29-Apr-10 21:14 
GeneralRe: You've gone MVVM Crazy... Pinmemberdefwebserver30-Apr-10 3:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141216.1 | Last Updated 1 Sep 2010
Article Copyright 2010 by defwebserver
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid