Click here to Skip to main content
15,860,859 members
Articles / Programming Languages / C# 4.0

Silverlight View Model Style Popup

Rate me:
Please Sign up or sign in to vote.
4.86/5 (10 votes)
1 Sep 2010Ms-PL7 min read 129.4K   2K   28   42
An example of an easy to use View Modal Style Popup and Silverlight Value Converter

Image 1

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

Image 2

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

Image 3

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.

Image 4

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.

Image 5

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

Image 6

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).

Image 7

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

Image 8

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

Image 9

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.

Image 10

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

Image 11

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

Image 12

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

Image 13

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.

Image 14

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

Image 15

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

Image 16

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:

Image 17

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)


Written By
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
AiHelpWebsite.com,
LightSwitchHelpWebsite.com, and
HoloLensHelpWebsite.com.

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

He is the Author of:

Comments and Discussions

 
Question[My vote of 1] Misinformation Pin
Austin Harris25-Jul-12 12:24
Austin Harris25-Jul-12 12:24 
AnswerRe: [My vote of 1] Misinformation Pin
defwebserver25-Jul-12 12:49
defwebserver25-Jul-12 12:49 
GeneralRe: [My vote of 1] Misinformation Pin
Austin Harris30-Jul-12 10:34
Austin Harris30-Jul-12 10:34 
GeneralRe: [My vote of 1] Misinformation Pin
defwebserver30-Jul-12 11:39
defwebserver30-Jul-12 11:39 
QuestionNeed right guideline Pin
sumantamca30-Nov-10 18:22
sumantamca30-Nov-10 18:22 
AnswerRe: Need right guideline Pin
defwebserver30-Nov-10 18:39
defwebserver30-Nov-10 18:39 
GeneralRe: Need right guideline Pin
sumantamca1-Dec-10 16:49
sumantamca1-Dec-10 16:49 
GeneralRocking Example Pin
saranyan.y@gmail.com6-Jul-10 0:07
saranyan.y@gmail.com6-Jul-10 0:07 
GeneralRe: Rocking Example Pin
defwebserver6-Jul-10 2:56
defwebserver6-Jul-10 2:56 
GeneralYou've Made a Classic Mistake Pin
EisenbergEffect1-May-10 2:20
EisenbergEffect1-May-10 2:20 
GeneralRe: You've Made a Classic Mistake [modified] Pin
EisenbergEffect1-May-10 2:26
EisenbergEffect1-May-10 2:26 
GeneralRe: You've Made a Classic Mistake Pin
defwebserver1-May-10 3:09
defwebserver1-May-10 3:09 
GeneralRe: You've Made a Classic Mistake Pin
defwebserver1-May-10 2:41
defwebserver1-May-10 2:41 
GeneralRe: You've Made a Classic Mistake Pin
EisenbergEffect1-May-10 3:54
EisenbergEffect1-May-10 3:54 
GeneralRe: You've Made a Classic Mistake Pin
EisenbergEffect1-May-10 3:56
EisenbergEffect1-May-10 3:56 
GeneralRe: You've Made a Classic Mistake Pin
EisenbergEffect1-May-10 4:23
EisenbergEffect1-May-10 4:23 
GeneralRe: You've Made a Classic Mistake Pin
defwebserver1-May-10 6:04
defwebserver1-May-10 6:04 
GeneralRe: You've Made a Classic Mistake Pin
Robert Kozak4-May-10 1:24
Robert Kozak4-May-10 1:24 
GeneralRe: You've Made a Classic Mistake Pin
defwebserver4-May-10 16:30
defwebserver4-May-10 16:30 
GeneralNice Article Pin
linuxjr30-Apr-10 13:00
professionallinuxjr30-Apr-10 13:00 
GeneralRe: Nice Article Pin
defwebserver30-Apr-10 14:02
defwebserver30-Apr-10 14:02 
GeneralWhilst I like what you do generally I do not like this approach for the following reasons [modified] Pin
Sacha Barber30-Apr-10 6:00
Sacha Barber30-Apr-10 6:00 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons Pin
defwebserver30-Apr-10 6:45
defwebserver30-Apr-10 6:45 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons Pin
Sacha Barber30-Apr-10 22:39
Sacha Barber30-Apr-10 22:39 
GeneralRe: Whilst I like what you do generally I do not like this approach for the following reasons Pin
defwebserver1-May-10 3:00
defwebserver1-May-10 3:00 
The View Model is still a class exposes interfaces so it can be tested. Perhaps not with your chosen methods.

Sacha Barber wrote:
Like I say I do not mean you any disrespect, but I just have a passion for MVVM is all.


I have a passion too. When others make their own MVVM framework that does things differently, should the other guy tell the first guy that he is "not MVVM"? The first step in ideology is to tell the other guy that he "is not" something.

I work hard to create good code that works. If my code has a bug, I will fix it. Otherwise I strongly believe that this is good, and correct and it is MVVM.

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

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