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

Simple Silverlight Configurator/Pivot (View Model/MVVM)

Rate me:
Please Sign up or sign in to vote.
4.88/5 (16 votes)
5 Sep 2010Ms-PL3 min read 57.1K   343   20   28
The application allows your users to query a collection using Silverlight using an animated display

A Simple Silverlight Configurator

Live example:

The application allows your users to query a collection (over web services), using drop downs and sliders. The results appear in a animated display.

You may ask, why not just use Microsoft Pivot? The main reasons are:

  • This one uses View Model / MVVM so the user interface can be completely designed by a designer.
  • There is not a lot of code, you can adapt this for your own use quickly.
  • This does not focus on images. Microsoft Pivot is designed to display high quality images. However, you can adapt this to display images.
  • This is a smaller application and it loads faster.
  • This is designed to work with your data coming directly from a database.

If the above does not apply to you, you may wish to use Microsoft Pivot instead.

The Application

image

Basically you choose Gender, Weight, and Age, and the people who fall into the selected criteria display as boxes that are animated, and re-order themselves.

With help from Adam Kinney

Funny story when I was hanging out on the Microsoft campus. I ran into Adam Kinney (Former Microsoft Evangelist). I told him about a idea I was working on for a Silverlight configurator, and if he had any ideas on how to best display the data. He suggested using the Silverlight Wrap Panel with the FluidMoveBehavior. He started to describe it to me, and I started taking notes, then he felt sorry for me, and since he had his laptop, he whipped up some code and emailed it to me.

The boxes flying around, and fading in and out, is from his example. It is all done with no code, and everything can be easily altered using Microsoft Expression Blend.

Building The Application – The Web Application

image

First, we we create a People collection:

public static class People
{
    public static List<Person> GetPeople()
    {
        List<Person> colPeople = new List<Person>();

        colPeople.Add(new Person { Name = "Tom", Description = "Cook", Age = 44, Weight = 224, Gender = "M" });
        colPeople.Add(new Person { Name = "Mary", Description = "Taxi Driver", Age = 22, Weight = 114, Gender = "F" });
        colPeople.Add(new Person { Name = "Jane", Description = "Nurse", Age = 28, Weight = 109, Gender = "F" });
        colPeople.Add(new Person { Name = "Lex", Description = "Doctor", Age = 51, Weight = 194, Gender = "M" });
        colPeople.Add(new Person { Name = "Paul", Description = "Saleman", Age = 23, Weight = 208, Gender = "M" });
        colPeople.Add(new Person { Name = "Frank", Description = "Butler", Age = 32, Weight = 184, Gender = "M" });
        colPeople.Add(new Person { Name = "Joe", Description = "Programmer", Age = 30, Weight = 290, Gender = "M" });
        colPeople.Add(new Person { Name = "John", Description = "Clerk", Age = 25, Weight = 202, Gender = "M" });
        colPeople.Add(new Person { Name = "Mark", Description = "Student", Age = 14, Weight = 102, Gender = "M" });
        colPeople.Add(new Person { Name = "Paula", Description = "Student", Age = 12, Weight = 98, Gender = "F" });
        colPeople.Add(new Person { Name = "Beth", Description = "Student", Age = 18, Weight = 119, Gender = "F" });
        colPeople.Add(new Person { Name = "Jack", Description = "Butcher", Age = 31, Weight = 114, Gender = "M" });
        colPeople.Add(new Person { Name = "Bob", Description = "Student", Age = 13, Weight = 114, Gender = "M" });
        colPeople.Add(new Person { Name = "Robert", Description = "Student", Age = 12, Weight = 99, Gender = "M" });
        colPeople.Add(new Person { Name = "Tony", Description = "Student", Age = 10, Weight = 105, Gender = "M" });
        colPeople.Add(new Person { Name = "Ray", Description = "Lawyer", Age = 35, Weight = 212, Gender = "M" });

        return colPeople;
    }
}

Next, we create a web service that will query this collection:

public class WebService : System.Web.Services.WebService
{
    [WebMethod]
    public List<Person> SearchPeople(string Gender, int AgeHigh, int AgeLow, int WeightHigh, int WeightLow)
    {
        List<Person> colPeople = new List<Person>();

        var result = from objPeople in People.GetPeople().AsQueryable()
                     where objPeople.Age <= AgeHigh
                     where objPeople.Age >= AgeLow
                     where objPeople.Weight <= WeightHigh
                     where objPeople.Weight >= WeightLow
                     select objPeople;

        if (Gender != "All")
        {
            colPeople = (from finalresult in result
                         where finalresult.Gender == Gender
                         select finalresult).ToList();
        }
        else
        {
            colPeople = result.ToList();
        }

        return colPeople;
    }
}

Note, this is where you can have your web service simply connect to your database.

That's it! Hopefully you find all this easy so far, and can see where you can easily alter this to pull in your own data.

Building The Application – The Silverlight Application

image

The Model, that calls the web service, is very simple:

public class Model
{
    #region SearchPeople
    public static void SearchPeople(string Gender, int AgeHigh, int AgeLow, int WeightHigh, int WeightLow,
                                     EventHandler<SearchPeopleCompletedEventArgs> eh)
    {
        // Set up web service call
        WebServiceSoapClient WS = new WebServiceSoapClient();

        // Set the EndpointAddress
        WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());

        WS.SearchPeopleCompleted += eh;
        WS.SearchPeopleAsync(Gender, AgeHigh, AgeLow, WeightHigh, WeightLow);
    }
    #endregion

    // Utility

    #region GetBaseAddress
    private static Uri GetBaseAddress()
    {
        // Get the web address of the .xap that launched this application
        string strBaseWebAddress = App.Current.Host.Source.AbsoluteUri;
        // Find the position of the ClientBin directory
        int PositionOfClientBin =
            App.Current.Host.Source.AbsoluteUri.ToLower().IndexOf(@"/clientbin");
        // Strip off everything after the ClientBin directory
        strBaseWebAddress = Strings.Left(strBaseWebAddress, PositionOfClientBin);
        // Create a URI
        Uri UriWebService = new Uri(String.Format(@"{0}/WebService.asmx", strBaseWebAddress));
        // Return the base address
        return UriWebService;
    }
    #endregion
}

image

The View Model, contains all the logic for the application. Hopefully, this demonstrates the power of View Model / MVVM style programming and how you can end up using less code than if you coded this using code behind.

First, we create a property to hold the main collection. This collection is the only thing that Adam Kinney's code is looking at. All the rest of the code in the application is simply changing this collection:

#region ColPeople
private ObservableCollection<Person> _ColPeople = new ObservableCollection<Person>();
public ObservableCollection<Person> ColPeople
{
    get { return _ColPeople; }
    private set
    {
        if (ColPeople == value)
        {
            return;
        }
        _ColPeople = value;
        this.NotifyPropertyChanged("ColPeople");
    }
}
#endregion

Next, we have Properties to hold the other parameters. These parameters are what the Sliders and the ComboBox are bound to:

#region AgeLow
private int _AgeLow = 10;
public int AgeLow
{
    get { return _AgeLow; }
    set
    {
        if (AgeLow == value)
        {
            return;
        }
        _AgeLow = value;
        this.NotifyPropertyChanged("AgeLow");
    }
}
#endregion

#region AgeHigh
private int _AgeHigh = 100;
public int AgeHigh
{
    get { return _AgeHigh; }
    set
    {
        if (AgeHigh == value)
        {
            return;
        }
        _AgeHigh = value;
        this.NotifyPropertyChanged("AgeHigh");
    }
}
#endregion

#region WeightLow
private int _WeightLow = 90;
public int WeightLow
{
    get { return _WeightLow; }
    set
    {
        if (WeightLow == value)
        {
            return;
        }
        _WeightLow = value;
        this.NotifyPropertyChanged("WeightLow");
    }
}
#endregion

#region WeightHigh
private int _WeightHigh = 300;
public int WeightHigh
{
    get { return _WeightHigh; }
    set
    {
        if (WeightHigh == value)
        {
            return;
        }
        _WeightHigh = value;
        this.NotifyPropertyChanged("WeightHigh");
    }
}
#endregion

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

Now, for the complex part (it is not really complex, that is my point). This is the method that calls the Model. Note, that it does not take parameters, it simply passes to the Model, whatever the values are set for the various properties:

#region GetPeopleFromModel
private void GetPeopleFromModel()
{
    // Call the Model to get People
    Model.SearchPeople(Gender, AgeHigh, AgeLow, WeightHigh, WeightLow, (Param, EventArgs) =>
    {
        if (EventArgs.Error == null)
        {
            // Remove people who are not part of the recent query
            var DeletedPeople = (from people in ColPeople
                                 where !EventArgs.Result.Select(x => x.Name).Contains(people.Name)
                                 select people).ToList();

            // loop thru each item
            foreach (var Person in DeletedPeople)
            {
                // Add to the colTasks collection
                ColPeople.Remove(Person);
            }

            // Add people that are not part of ColPeople
            var NewPeople = from people in EventArgs.Result
                            where !ColPeople.Select(x => x.Name).Contains(people.Name)
                            select people;

            // loop thru each item
            foreach (var Person in NewPeople)
            {
                // Add to the colTasks collection
                ColPeople.Add(Person);
            }
        }
    });
}
#endregion

This class implements INotifyPropertyChanged, so we use this method to call the GetPeopleFromModel() method whenever one of the properties changes:

#region MainPageModel_PropertyChanged
void MainPageModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (
        e.PropertyName == "AgeLow" ||
        e.PropertyName == "AgeHigh" ||
        e.PropertyName == "WeightLow" ||
        e.PropertyName == "WeightHigh" ||
        e.PropertyName == "Gender")
    {
        GetPeopleFromModel();
    }
}
#endregion

That's it!

If you are not used to View Model Style programming, you may be wondering “how do the properties for things like Age and Weight get set?”. The answer is, that we will bind controls in the View to these properties. All of that is done in Microsoft Expression Blend, using no code at all.

image

The View looks like this in Expression Blend

image

This diagram shows what is bound to what:

image

Note, that the Range Sliders are from and article posted by Josh Twist.

Further Reading

Adam Kinney suggested I pass these URL’s on if you want to know how he did the animated list:

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

 
GeneralMy vote of 5 Pin
Richard Waddell17-Sep-10 15:44
Richard Waddell17-Sep-10 15:44 
GeneralMy vote of 5 Pin
Marcelo Ricardo de Oliveira8-Sep-10 4:10
Marcelo Ricardo de Oliveira8-Sep-10 4:10 
GeneralRe: My vote of 5 Pin
defwebserver8-Sep-10 5:14
defwebserver8-Sep-10 5:14 
Thank you for your vote!
GeneralMy vote of 5 Pin
venugopalm8-Sep-10 0:26
venugopalm8-Sep-10 0:26 
GeneralRe: My vote of 5 Pin
defwebserver8-Sep-10 2:28
defwebserver8-Sep-10 2:28 
GeneralExcellent, if only you weren’t colour blind (and could spell color) :-) Pin
Alan Beasley7-Sep-10 4:12
Alan Beasley7-Sep-10 4:12 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pin
defwebserver7-Sep-10 7:41
defwebserver7-Sep-10 7:41 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pin
Dewey8-Sep-10 14:55
Dewey8-Sep-10 14:55 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pin
defwebserver8-Sep-10 16:13
defwebserver8-Sep-10 16:13 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pin
Dewey8-Sep-10 22:42
Dewey8-Sep-10 22:42 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pin
defwebserver9-Sep-10 2:12
defwebserver9-Sep-10 2:12 
GeneralVery Nice Article Pin
Sushant Joshi6-Sep-10 17:27
Sushant Joshi6-Sep-10 17:27 
GeneralRe: Very Nice Article Pin
defwebserver6-Sep-10 17:47
defwebserver6-Sep-10 17:47 
QuestionWhy is the latest version required? Pin
Dewey5-Sep-10 14:48
Dewey5-Sep-10 14:48 
AnswerRe: Why is the latest version required? Pin
defwebserver5-Sep-10 15:05
defwebserver5-Sep-10 15:05 
GeneralRe: Why is the latest version required? Pin
defwebserver5-Sep-10 15:19
defwebserver5-Sep-10 15:19 
GeneralRe: Why is the latest version required? Pin
Dewey5-Sep-10 22:04
Dewey5-Sep-10 22:04 
GeneralMy vote of 5 Pin
Eric Xue (brokensnow)5-Sep-10 11:44
Eric Xue (brokensnow)5-Sep-10 11:44 
GeneralRe: My vote of 5 Pin
defwebserver5-Sep-10 13:22
defwebserver5-Sep-10 13:22 
AnswerRe: My vote of 5 Pin
Eric Xue (brokensnow)5-Sep-10 13:37
Eric Xue (brokensnow)5-Sep-10 13:37 
GeneralRe: My vote of 5 Pin
defwebserver5-Sep-10 13:43
defwebserver5-Sep-10 13:43 
AnswerRe: My vote of 5 Pin
Eric Xue (brokensnow)5-Sep-10 14:03
Eric Xue (brokensnow)5-Sep-10 14:03 
QuestionI have a problem Pin
tamash_ionut5-Sep-10 8:17
tamash_ionut5-Sep-10 8:17 
AnswerRe: I have a problem Pin
defwebserver5-Sep-10 8:37
defwebserver5-Sep-10 8:37 
GeneralRe: I have a problem Pin
tamash_ionut5-Sep-10 9:19
tamash_ionut5-Sep-10 9:19 

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.