Thursday, May 17, 2012    
Blog  

OpenLight Blog

Silverlight View Model (MVVM) - A Play In One Act

Dec 11

Written by:
12/11/2010 3:30 PM  RssIcon

I read one of the greatest blog posts ever by Brad Schulz called A Second in the Life of a Query Operator,  This is my attempt to honor his post on SQL server execution plans with a character based story about View Model (MVVM).

Note: If you are new to View Model (MVVM) it is suggested that you read Silverlight View Model Style : An (Overly) Simplified Explanation for an introduction.

Introduction

I wrote a article called Simple View Model / MVVM drag and drop upload control. In the project I tried out a few new ideas. I purposely made the View Model as simple as possible. I put all the “real work” into the Behaviors. I also used a lot of Behaviors, more than I had ever used in a single project.

Many developers tend to think of the View Model as “code behind, but with bindings”. Usually this thinking works, but with this project there was a lot of UI (the View) “stuff happening” and I wanted to avoid a lot of complex maneuvers to make the application work without using code behind.

image

The project is a simple Upload Control. You can select a file using the Browse button, or drop a file on the space marked Drop File Here.

image

The control uses the Visual State Manager and has these three Visual States:

  • NoFileSelected
  • FileSelectedState
  • FileUploadingState

Using Behaviors for most of the functionality really simplified things for me. I plan to use this style on future projects. however, it was hard to convey this “mindset change” in a Blog.

However, in the style of Brad Schultz, I will attempt to dramatize the process.

The Cast - The Stars (M,V and VM)

image

The Cast - The Co-Stars (The Behaviors)

image

The View Model (MVVM) Story In One Act

Browsing For A File

The View is just sitting there, waiting for something to happen. That is what the View does, it waits. When something happens, it tells something else what to do. That something else is usually the View Model. Well actually it doesn’t tell the View Model what to do, it notifies the View Model. The response from the View Model is usually to respond with something it then wants the View to do.

However, this project also has Behaviors. Behaviors are dumb. they usually only do one thing. However, like the View Model, while the View tells them what to do, they sometimes tell the View what to do. This is all very annoying to the View because the View sees itself in charge. The only one that never tells the View what to do is the Model… but,it never talks to the View anyway…

Something just happened! The View is excited. The “User” pressed the Browse button.

image

View (to OpenFileDialogBehavior): Wake up! Wake Up! Do your thing, (whatever it is)!

OpenFileDialogBehavior (to View): Got it! Give me a millisecond… hello?

But the View is not paying attention to the Behavior, The View already returned to waiting for new events.

The OpenFileDialogBehavior looks at it’s properties and sees that all required parameters are properly bound to it. it then looks at it’s code and sees that it only needs to open a File dialog box, and if the User selects a File, it is to passes that File to the View Model.

It runs this code:

    // Only proceed if a file was selected
    if (FileDialogDialogResult != null)
    {
        SelectedFileName = ShortenFileName(FileDialogDialogResult.Name);
 
        // Change to selected file Visual State
        VisualStateManager.GoToState((Control)ParentControl, "FileSelectedState", true);
    }

OpenFileDialogBehavior (to View): Hey I need you to change to FileSelectedState.

The View simply does this without comment. It is used to being told what to do by other elements in the application.

OpenFileDialogBehavior (to View Model): Hey I got a File and a File Name.

View Model (to OpenFileDialogBehavior): Got it, Thanks.

The View Model is a confidant being. It knows that it is the heart of this application. It’s only frustration is that it cannot show anything without going through the View, and it cannot access any server resources without going through the Model.

It exposes Properties that others can bind to, and it is the SelectedFileProperty that the OpenFileDialogBehavior has placed the selected File.

The View Model also has ICommands that others can call when they want the View Model to do something.

The View Model looks at the code for the Properties and sees that they contain code such as:

NotifyPropertyChanged("SelectedFileProperty");

NotifyPropertyChanged("SelectedFileNameProperty");

This means that it needs to notify its worker INotifyPropertyChanged (think a ‘harried stock trader’ with a bunch of order slips all over his desk).

View Model (to INotifyPropertyChanged): Hey buddy, I just changed SelectedFileProperty and SelectedFileNameProperty.

INotifyPropertyChanged (to View Model): Oh man I got a ton of bindings, let me look through this pile and see what I got. Yeah got something hooked up to both of those Properties. I will raise the notice that they changed.

The OpenFileDialogBehavior is actually bound to both properties (that is how it was able to change them), but it ignores these notifications.

image

The View, however is bound to the SelectedFileNameProperty and it gets the notification and updates the name of the file displayed.

Removing A File

image

The “User” presses the Remove File button.

View (to RemoveSelectedFileBehavior): Wake up! Wake Up! Do your thing!

RemoveSelectedFileBehavior (to View): Got it! Give me a millisecond… hello?… never mind… No, wait, I have code that removes the Selected File that is bound to the View Model, but I also have this code to talk to you:

    // Change to selected file Visual State
    VisualStateManager.GoToState((Control)ParentControl, "NoFileSelectedState", true);

View (to RemoveSelectedFileBehavior): Ok I have changed the Visual State to NoFileSelectedState.

RemoveSelectedFileBehavior (to View Model): Hey, I am clearing your File and a File Name properties.

Dropping A File

image

The “User” drops a file on the Drop File Here box.

View (to DropFilesToUploadBehavior): Wake up! Wake Up! Do your thing!

DropFilesToUploadBehavior (to View): Got it! Give me a millisecond… hello?

But the View is not paying attention to the Behavior, The View already returned to waiting for new events.

DropFilesToUploadBehavior (to View): Hey! I have this code to talk to you:

    // Change to selected file Visual State
    VisualStateManager.GoToState((Control)ParentControl, "FileSelectedState", true);

View (to DropFilesToUploadBehavior ): Ok I have changed the Visual State to FileSelectedState.

DropFilesToUploadBehavior (to View Model): Hey, I am setting your File and a File Name properties.

Uploading A File

image

The Main Page actually hosts the Upload Control and has an instance of the Upload Control’s View Model. When it wants the Upload Control to upload any file it has, it calls the Upload Control’s View Model.

Main Page (Actually the Main Page’s View Model) (to View Model): Hey, upload your file (if you have one)

In the View Model, this is the ICommand that the Main Page calls to communicate with it:

    public ICommand UploadFileCommand { get; set; }
    public void UploadFile(object param)
    {
        // Can only upload if there is a selected File
        if (SelectedFileProperty != null)
        {         
            // Turn on Uploading Flag
            Uploading = true;
 
            UploadFile();
        }
    }
 
    private bool CanUploadFile(object param)
    {
        // Only allow uploading if not already uploading
        return (Uploading != true);
    }

 

Two things will happen. the first thing is that the Uploading property will change to true

View Model (to INotifyPropertyChanged): Hey buddy, I just changed the Uploading property.

INotifyPropertyChanged (to View Model): I will raise the notice that it changed.

image

There is a DataTrigger that is bound to the Uploading property. This DataTrigger will only notify the UploadingStateBehavior if the Uploading property is changed to True.

DataTrigger (to UploadingStateBehavior): Wake up! Wake Up! Do your thing.

image

UploadingStateBehavior (to View): I have this code to talk to you:

    // Change Visual State
    VisualStateManager.GoToState((Control)ParentControl, "FileUploadingState", true);

View (to UploadingStateBehavior ): Ok I have changed the Visual State to FileUploadingState.

The next thing that happens, is that the View Model tells the Model to upload the file to the server.

View Model (to Model): Hey upload the file in my SelectedFileProperty.

The Model only talks to the View Model. It just sits there waiting for commands from the View Model. The only other thing that it does, is it sometimes returns responses to the View Model.

Model (to View Model): Ok, I will let you know when I am done.

(time passes – Also note, that the file that does the actual uploading in this example is “FileUpload.cs”)

Model (to View Model): Ok, I am done

The following code runs in the View Model:

    void upload_StatusChanged(object sender, EventArgs e)
    {
        FileUpload fu = sender as FileUpload;
            
        // Is upload complete?
        if (fu.Status == FileUploadStatus.Complete)
        {                
            // Clear the Selected File
            SelectedFileProperty = null;
 
            // Turn off Uploading Flag
            Uploading = false;
 
            // Refresh Files on the Main page
            MainViewModell_VM.GetFilesCommand.Execute(null);
        }
    }

In that code, the View Model changes the Uploading property to false

View Model (to INotifyPropertyChanged): Hey buddy, I just changed the Uploading property.

INotifyPropertyChanged (to View Model): I will raise the notice that it changed.

image

There is another DataTrigger that is bound to the Uploading property. This DataTrigger will only notify the NoFileSelectedStateBehavior if the Uploading property is changed to False.

DataTrigger (to NoFileSelectedStateBehavior): Wake up! Wake Up! Do your thing.

image

NoFileSelectedStateBehavior (to View): I have this code to talk to you:

    // Change Visual State
    VisualStateManager.GoToState((Control)ParentControl, "NofileSelectedState", true);

View (to NoFileSelectedStateBehavior): Ok I have changed the Visual State to NoFileSelectedState.

And the application lived happily ever after Smile

6 comment(s) so far...


Gravatar

Re: Silverlight View Model (MVVM) - A Play In One Act

This was very amusing to read :)

By Marco on   12/12/2010 8:33 PM
Gravatar

Re: Silverlight View Model (MVVM) - A Play In One Act

@Marco - Thanks for the feedback. It was meant to be amusing :)

By Michael Washington on   12/12/2010 8:40 PM
Gravatar

Re: Silverlight View Model (MVVM) - A Play In One Act

A very nice read! Thanks

By Ricardo Fiel on   12/13/2010 5:04 PM
Gravatar

Re: Silverlight View Model (MVVM) - A Play In One Act

@Ricardo Fiel - Thanks!

By Michael Washington on   12/13/2010 5:05 PM
Gravatar

Re: Silverlight View Model (MVVM) - A Play In One Act

Nice buddy

By Atif Shahzad on   12/18/2010 6:19 AM
Gravatar

Re: Silverlight View Model (MVVM) - A Play In One Act

@Atif Shahzad - Thanks for leaving a comment.

By Michael Washington on   12/18/2010 6:20 AM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
  
Copyright 2009 by OpenLightGroup.net   |  Privacy Statement  |  Terms Of Use