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

Simple Silverlight Configurator/Pivot (View Model/MVVM)

By , 5 Sep 2010
Rate this:
Please Sign up or sign in to vote.

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)

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 http://LightSwitchHelpWebsite.com
 
He has a son, Zachary and resides in Los Angeles with his wife Valerie.
Follow on   Twitter

Comments and Discussions

 
GeneralMy vote of 5 PinmemberRichard Waddell17-Sep-10 15:44 
GeneralMy vote of 5 PinmemberMarcelo Ricardo de Oliveira8-Sep-10 4:10 
GeneralRe: My vote of 5 Pinmemberdefwebserver8-Sep-10 5:14 
GeneralMy vote of 5 Pinmembervenugopalm8-Sep-10 0:26 
GeneralRe: My vote of 5 Pinmemberdefwebserver8-Sep-10 2:28 
GeneralExcellent, if only you weren’t colour blind (and could spell color) :-) PinmemberAlan Beasley7-Sep-10 4:12 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pinmemberdefwebserver7-Sep-10 7:41 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) PinmemberDewey8-Sep-10 14:55 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pinmemberdefwebserver8-Sep-10 16:13 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) PinmemberDewey8-Sep-10 22:42 
GeneralRe: Excellent, if only you weren’t colour blind (and could spell color) :-) Pinmemberdefwebserver9-Sep-10 2:12 
GeneralVery Nice Article PinmemberSushant Joshi6-Sep-10 17:27 
GeneralRe: Very Nice Article Pinmemberdefwebserver6-Sep-10 17:47 
QuestionWhy is the latest version required? PinmemberDewey5-Sep-10 14:48 
AnswerRe: Why is the latest version required? Pinmemberdefwebserver5-Sep-10 15:05 
GeneralRe: Why is the latest version required? Pinmemberdefwebserver5-Sep-10 15:19 
GeneralRe: Why is the latest version required? PinmemberDewey5-Sep-10 22:04 
GeneralMy vote of 5 PinmemberEric Xue (brokensnow)5-Sep-10 11:44 
GeneralRe: My vote of 5 Pinmemberdefwebserver5-Sep-10 13:22 
AnswerRe: My vote of 5 PinmemberEric Xue (brokensnow)5-Sep-10 13:37 
GeneralRe: My vote of 5 Pinmemberdefwebserver5-Sep-10 13:43 
AnswerRe: My vote of 5 PinmemberEric Xue (brokensnow)5-Sep-10 14:03 
QuestionI have a problem Pinmembertamash_ionut5-Sep-10 8:17 
AnswerRe: I have a problem Pinmemberdefwebserver5-Sep-10 8:37 
GeneralRe: I have a problem Pinmembertamash_ionut5-Sep-10 9:19 

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 | Mobile
Web02 | 2.8.140415.2 | Last Updated 5 Sep 2010
Article Copyright 2010 by defwebserver
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid