I recently started playing with Silverlight again, and wanted to share one way of doing MVC.
To keep things simple, I created an app that basically updates one textbox when you start typing something in the other (salary calculates taxes).
Let’s first go through the code at a high-level, and then walk through what actually happens sequentially behind the scenes.
Step 1: Define your model.
public interface ICalculatorModel { double Salary { get; set; } double Taxes { get; set; } event EventHandler<CalculatorEventArgs> TaxesChanged; }
In MVC our model defines our data. Here we are saying we’ve got two pieces of information we are interested in (salary and taxes) and an event to notify people when one of these values change.
Here’s what the actual model looks like.
public class CalculatorModel : ICalculatorModel { private double salary; private double taxes; public readonly double TAX_RATE = 0.3d; public double Salary { get { return salary; } set { if (value == this.salary) return; salary = value; Taxes = salary*TAX_RATE; } } public double Taxes { get { return taxes; } set { if (value == this.taxes) return; taxes = value; OnTaxesChanged(new CalculatorEventArgs(this)); } } public event EventHandler<CalculatorEventArgs> TaxesChanged; protected void OnTaxesChanged(CalculatorEventArgs e) { if (TaxesChanged != null) TaxesChanged(this, e); // fire event } }
It basically sets values for it’s properties, and fires off an event when someone changes the Taxes property value (this is the event our view registers for so it knows when to update it’s value on the screen).
Step 2: Define your view.
public partial class CalculatorView : Page { private ICalculatorModel model; private ICalculatorController controller; public CalculatorView() { InitializeComponent(); } public void SetModel(ICalculatorModel calculatorModel) { model = calculatorModel; SalaryTextBox.TextChanged += SalaryTextBoxChanged; model.TaxesChanged += ModelTaxesChanged; } private void ModelTaxesChanged(object sender, CalculatorEventArgs e) { TaxesTextBox.Text = e.Taxes.ToString(); } private void SalaryTextBoxChanged(object sender, TextChangedEventArgs e) { controller.SetSalary(Double.Parse(SalaryTextBox.Text)); } public void SetController(ICalculatorController calculatorController) { controller = calculatorController; } }
The view fires events off (letting models and controllers know when something interesting has happened). And it registers for events it is interested in (so it knows when to update itself).
In this example we are interested in two events:
- When does the SalaryTextBox text change.
- When does our model Taxes value change.
SalaryTextBox.TextChanged += SalaryTextBoxChanged;
model.TaxesChanged += ModelTaxesChanged;
Let’s now take a look at the controller.
Step 3: Hooking up the controller.
public class CalculatorController : ICalculatorController { private CalculatorView view; private ICalculatorModel model; public CalculatorController(CalculatorView view, ICalculatorModel model) { this.view = view; this.model = model; view.SetModel(model); view.SetController(this); } public void SetSalary(double salary) { model.Salary = salary; } public void SetTaxes(double taxes) { model.Taxes = taxes; } }
The controller basically just coordinates things between the model and the view.
Here it passes on the setting of model values to the model itself (which then fires events telling people the model is changed).
But actual hookup for the controller occurs in the MainPage.xaml.cs
code behind.
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); ICalculatorModel model = new CalculatorModel(); ICalculatorController controller = new CalculatorController(view, model); } }
That’s it for setup. Now let’s see how this all actually works.
Step 4: Let the events fly.
Because we have registered for the SalaryTextBox.TextChanged
and model.TaxesChanged
events in our view …
public partial class CalculatorView : Page { public void SetModel(ICalculatorModel calculatorModel) { ... SalaryTextBox.TextChanged += SalaryTextBoxChanged; model.TaxesChanged += ModelTaxesChanged; ... } }
when someone starts typing in the salary textbox
public partial class CalculatorView : Page { private void SalaryTextBoxChanged(object sender, TextChangedEventArgs e) { controller.SetSalary(Double.Parse(SalaryTextBox.Text)); } }
our controller gets notified which passes the message onto our model
public class CalculatorModel : ICalculatorModel { public double Salary { ... set { if (value == this.salary) return; salary = value; Taxes = salary*TAX_RATE; } } public double Taxes { ... set { if (value == this.taxes) return; taxes = value; OnTaxesChanged(new CalculatorEventArgs(this)); } } }
Now when the model sets it’s salary, it’s actually doing two things. First it sets the value of the salary if it’s changed, secondly it sets the Taxes property down below which in turn fires the OnTaxesChanged
changed event:
public class CalculatorModel : ICalculatorModel { protected void OnTaxesChanged(CalculatorEventArgs e) { if (TaxesChanged != null) TaxesChanged(this, e); }
This is how our Taxes textbox gets update. Because we registered for this event way back in our view, when it gets fired our Taxes textbox gets updated.
public partial class CalculatorView : Page { private void ModelTaxesChanged(object sender, CalculatorEventArgs e) { TaxesTextBox.Text = e.Taxes.ToString(); }
Phew!
That’s a lot of work to update one textbox based on the contents of another, but you could see how if you had a complicated UI, the benefits of separating the model from the view would start to pay off.
It jury is still out for me on how best to use MVC in Silverlight. Coming from a web background, all this eventing can get pretty confusing (the statelessness of the HTTP is nice).
But this is a start. I’ll post more when I get a chance to play with some other models like Model-View-Presenter.
You can download and play with source SilverLight-MVC here.
Note: WordPress doesn’t allow *.zip files so rename the *.doc to *.zip when you download.
You’ll need Visual Studios 2010 with Silverlight4.
In the mean time, here are some others Silverlight model view examples:
- Another MVC example.
- Model-View-Presenter example.
- Model-View-ViewModel example.
Sean Feldman
Sep 18, 2010 @ 15:27:24
Interesting implementation. Looks a lot like MVP I did in the past for regular ASP.NET. I’m new to Silverlight as well, though IMO MVVP suites Silverlight technology better.
Code in the View like:
controller.SetSalary(Double.Parse(SalaryTextBox.Text));
or
TaxesTextBox.Text = e.Taxes.ToString();
becomes obsolete when you leverage binding. As well as minimized code in the view – something that always makes me happy. A few things with MVVM that look poor (like INotifyPropertyChanged), but those can be worked around or implemented with AOP.
Thanks for sharing idea.
JR
Sep 19, 2010 @ 14:49:27
Hi Sean,
Good points.
I am currently working through an MVP implementation (just to see what that looks like) and then after that I would like to try the MVVM for the binding advantages you describe.
+1 to minimized code in the view.
Cheers – JR
Silverlight Model-View-Presenter (MVP) example « The Agile Warrior
Sep 20, 2010 @ 18:44:04
Michael L Perry
Sep 21, 2010 @ 16:59:04
I borrowed your example to demonstrate a way of doing this without raising events. Imagine how you would solve this problem with Excel. Consider what that solution would look like in code. Then read MVC without eventing.
JR
Sep 22, 2010 @ 14:02:38
Hi Michael,
Love your MVC without eventing example. Really cleans things up.
I am going to go over this in detail this weekend to see how everything connects (specifically the binding).
Great example. Thanks for sharing
JR
David J Kelley (@DavidJKelley)
Mar 01, 2012 @ 23:05:26
so I know I’m drinking a lot of XAML related koolaide for a long time meaning I’m a bit biased as to silverlight implementation, however as a Microsoft Silverlight MVP I’d have to say the standard (and best practice) is MVVM in silverlight and any other XAML based technologies (ie, silverlight, wp7, wpf and win8 or winRT/Metro) Coming from a MVC background, MVVM is typically difficult to get until you get it (much of this problem is due to all the intellectual potification amoung xaml devs, where the problem is they mix a bunch of other pattern into their MVVM like mediator, and commands etc) but MVVM is much much cleaning then the above method for build and designing apps. part of the benefit of MVVM is there is virtually no code and the abstraction between the backend and front end using bindings and view models so virtually absolute and very loosely coupled.
Roger
Mar 02, 2012 @ 18:35:23
Am unable to open the source code word document you attached. Get this error message:
The sile silverlight-mvc.doc cannot be opened because there are problems with the contents.
Details
Microsoft Office cannot open this file because some parts are missing or invalid.
Roger
Mar 02, 2012 @ 20:06:59
Sorry, I had missed the convert *.doc to *.zip comment.