Posted by: Zeeshan Amjad | July 15, 2010

Switching to MVVM


Apply MVVM is on existing project is multistep process and i will try to apply one step at a time (of course on existing code base).

Step 1. Prerequisites. If code is using field not properties, then convert those from field to properties. (This should have no or minimal effect on existing source code, because i choose the property name very similar (or same) as fields.

Step 2. Next step is to change the data model to make is WPF friendly. To do this i will either implement INotifyPropertyChange interface or make them dependency property. If we already havea properties, then this should have no effect at all for rest of the project. Your rest of the code should be same and should work same, but at least now you have your model ready.

Step 3. Next step is use Data Binding. This will reduce lots of codebase. Now i shouldn’t have any code like

txtName.Text = firstName;

This is a major change in the codebase. But at this step i focus only on data not on behavior. My code still have event handler and should work fine, but now i don’t have to worry about updating the data into control or getting data from control to my variable. (No more control to variable interaction).

Step 3. This is intermediate step. Now I already have all the data handling in the form of data binding with no control/variable code in it. I am going to iterate through all event handler and whatever code is written there, moved them into a method and call that method from the event handler. It would be something like this

Suppose I have the following event handler to calculate the depreciation value.

private void btnCalculate_Click(object sender, RoutedEventArgs e)
{
	depreciation.Clear();
	
	year = Convert.ToInt32(txtYear.Text);
	cost = Convert.ToDouble(txtCost.Text);
	scrap = Convert.ToDouble(txtScrapValue.Text);
	
	if (year <= 0)
	{
		MessageBox.Show("Number of years can not be zero or negative.");
		return;
	}
	if (cost <= 0 || scrap <= 0)
	{
		MessageBox.Show("Either Cost or Scrap value is not correct.");
		return;
	}
	
	double accDepreciation = 0;
	double bookValue = cost -scrap;
	double depExpense = 0;

	int sum = year * (year + 1) / 2;
	int totalYears = year;

	for (int iIndex = 0; iIndex < year; iIndex++)
	{
		double percentage = (double)totalYears / (double)sum;
		depExpense = bookValue * percentage;
		cost -= depExpense;
		accDepreciation += depExpense;

		DepreciationInfo dpInfo = new DepreciationInfo();
		dpInfo.Year = (iIndex + 1);
		dpInfo.Depreciation = depExpense;
		dpInfo.AccDepreciation = accDepreciation;
		dpInfo.BookValue = cost;
		dpInfo.Percentage = percentage * 100;

		depreciation.Add(dpInfo);
		totalYears--;
	}

	list.ItemsSource = depreciation;
}


I moved all the code inside the method and call that method from the event handler.

It would be something like this.

private void btnCalculate_Click(object sender, RoutedEventArgs e)
{
	calculateDepreciation();
}

private calculateDepreciation()
{
	depreciation.Clear();
	
	year = Convert.ToInt32(txtYear.Text);
	cost = Convert.ToDouble(txtCost.Text);
	scrap = Convert.ToDouble(txtScrapValue.Text);
	
	if (year <= 0)
	{
		MessageBox.Show("Number of years can not be zero or negative.");
		return;
	}
	if (cost <= 0 || scrap <= 0)
	{
		MessageBox.Show("Either Cost or Scrap value is not correct.");
		return;
	}
	
	double accDepreciation = 0;
	double bookValue = cost -scrap;
	double depExpense = 0;

	int sum = year * (year + 1) / 2;
	int totalYears = year;

	for (int iIndex = 0; iIndex < year; iIndex++)
	{
		double percentage = (double)totalYears / (double)sum;
		depExpense = bookValue * percentage;
		cost -= depExpense;
		accDepreciation += depExpense;

		DepreciationInfo dpInfo = new DepreciationInfo();
		dpInfo.Year = (iIndex + 1);
		dpInfo.Depreciation = depExpense;
		dpInfo.AccDepreciation = accDepreciation;
		dpInfo.BookValue = cost;
		dpInfo.Percentage = percentage * 100;

		depreciation.Add(dpInfo);
		totalYears--;
	}

	list.ItemsSource = depreciation;
}

Theoretically i didn’t change anything major here. My program should work fine.

Step 5. In next step i am going to introduce the ICommand interface and implement it. Here is one example of it

public class MyCommand : ICommand
{
  public Func<int> Function
  { get; set; }

  public MyCommand()
  {

  }

  public MyCommand(Func<int> function)
  {
    Function = function;
  }

  public bool CanExecute(object parameter)
  {
    if (Function != null)
    {
      return true;
    }

    return false;
  }

  public void Execute(object parameter)
  {
    if (Function != null)
    {
      Function();
    }
  }

  public event EventHandler CanExecuteChanged
  {
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
  }
}

Adding new class doesn’t have any effect at all on my existing code. It should work as it was working earlier. But i lay the foundation of using Command Binding. The other part of of MVVM.

Step 6. Now i am going to add properties in my class (which has event handler earlier). The type of that property is ICommand. This again should not have any effect on rest of the code. Number of properties should be at least same as the method i called inside the event handler and i choose the similar name.

public ICommand CalculateDepreciation
{ get; set; }

Step 7. I have already created method to calculate depreciation (or doing other work).  Create object of MyCommand class and assign it to our ICommand properties in constructor

CalculateDepreciation = new MyCommand(calculateDepreciation);

Still no effect at all should be rest of the code.

Now i have prepare the stage for command binding but not using it. In next step i am going to replace event handler with Command binding.

 

Step 8. Remove the event handler from code as well as from XAML and instead of it use the command binding. This is again a major change in the code (both code and XAML).

This way i plan to convert non MVVM application to MVVM application. Here i set few milestone for myself and in few steps i didn’t break the existing application but come closer to MVVM.

Advertisements

Responses

  1. Good one. As we started our project without MVVM. i always wonder if we need to move toward MVVM, what we need to do.
    You give me a good start up to read.
    Thanks,
    Nash

    • Thanks to like it Nash.

  2. […] already saw the implementation of ICommand interface here, here and here. That was very naïve implementation. The biggest problem with this implementation is that […]

  3. What if your events have some very view specific code (like updating the drawable area of a chart, or creating and displaying a dialog window), which can’t be moved to the view model? How that could be handled?

    • In that case one solution is to expose the event from the View Model and then werite the delegate for this in View class to wirte view specific functionality. You can see one example of exposing the Close event here

      https://zamjad.wordpress.com/2011/03/09/implement-close-window-functionality-in-viewmodel/

      Regards
      Zeeshan Amjad

      • Gotcha! Thanks for the quick reply.

        Do you mind if i ask you another question?

        I have the need to expose from the viewmodel a custom list based in the model. For instance, think of a scenario where you have a list of servers, and in each server you have a list of clients to which you can connect to. That topological structure is important in the model, and in the view while adding a new client, but for showing the data to the user the view only cares about the clients themselves, no matter where they are connected to, so my viewmodel needs to expose a Clients list. Currently, since my application can update servers lists and their clients from both the interface and a background thread that accesses a external server i wrapped my model around something that i called a ModelView and ensuring that all the accesses to the model were channeled to the same modelview i could intercept the changes and maintain that custom list in sync with the model.

        That works, but requires quite a lot of wrapping (that for the most part is just for repeating the same properties), and i don’t like to mix the viewmodel having direct access to the model to some classed with it having to go through a proxy for others… I tried creating a custom list from linq, but the result list remains static after changes are made to the model, also, i believe that if my model can’t be edited (for example using an external library) i have no choice but to wrap it, right? And if the model can be modified from either the view or for a background thread, is there a cleaner way than wrapping the model in a modelview and sharing that instance with everyone that needs to access it?

        Sorry for the long question, hope you can help 😛

      • Hi

        I am sorry i might not understand your problem completely without looking at the code. But usually when i cam across lots of similar wrapping classes i usually end up making generic classes. Have you tried generic classes to create wrapper?

        Regards
        Zeeshan Amjad

  4. […] saw one example to see how can we move the existing project using MVVM here. But those are just the first steps in that direction not a complete solution. In any big project […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: