I am currently working on ‘Case In Point‘, a Silverlight application which is available online and if you want to know more about it and why I chose to build it, please check out this previous post. In more recent times I have moved beyond the layout / UI Design stage (the main point in building this app) and have just now moved into preparing the ground for structuring my approach to the Business Logic and Data Access and how I was going to affect loosely coupled layers.
My first instinct was to tackle the task by using the recently devised Model-View View-Model pattern however I chose not to go down that path because this applications primary objective was to provide a learning exercise in UI skills and ultimately I thought that implementing the Model View Presenter pattern in a Silverlight application would provide me a solid foundation to compare when I do finally try out MVVM.
Over the past couple of years I have become accustomed to using a home grown MVP Framework that was fully templated in Visual Studio and offered a lot of benefit in speed of use by cutting out a lot of the repetitive file creational stuff that such an approach requires. Using this templated framework meant that creating a ‘new item’ in Visual Studio would trigger the creation of the Model, View (user control, page, form etc) and Presenter, wiring their dependencies (via injection) together in the process. One of the benefits of this homegrown MVP framework was it’s ability to deal with what effectively handled two way Databinding between the views and the model, something that we now get from Silverlight for free, which gave me a chance to really see how MVP would benefit or from this aspect.
So far my standard MVP approach for Win Forms and Web Forms seems to sit equally as well with Silverlight so I am pleased that I can move forward quickly with completing this learning exercise, which as I have pointed out was completely about getting comfortable with Silverlight in respect to gaining familiarity with the new UI paradigm.
Setting up the Model View Presenter.
public partial class CaseInPoint : UserControl
{
//The main UI View (control) that loads all the tabs views)
public CaseInPoint()
{
InitializeComponent();
//new up the model for the tabbed application
PointInCaseProject model = new PointInCaseProject();
//new up all the presenters
CaseInPointPresenter mainPagePresenter =
new CaseInPointPresenter(this, model);
ProjectDetailPresenter projDetailsPresenter =
new ProjectDetailPresenter(this.AppTabs.ctlProjectCalculator, model);
FactorsPresenter factorPresenter =
new FactorsPresenter(this.AppTabs.ctlFactorList, model);
UserStoryPresenter storyPresenter =
new UserStoryPresenter(this.AppTabs.ctlUserStoryView, model);
ActorsPresenter actorsPresenter =
new ActorsPresenter(this.AppTabs.ctlActorsView, model);
}
}
The Presenter.
internal class ProjectDetailPresenter : IPresenter
{
private ProjectDetailCalculator _view;
private PointInCaseProject _model;
private CaseInPoint _viewParentWindow;
internal ProjectDetailCalculator View
{
get { return _view; }
set { _view = value; }
}
internal PointInCaseProject Model
{
get { return _model; }
set { _model = value; }
}
internal ProjectDetailPresenter(ProjectDetailCalculator view,
PointInCaseProject model)
{
//set the view and model
_view = view;
_model = model;
//wire up the events of the view and its parent window
WireUpEventsOnInit();
//do any initial data binding
InitialBindUiToEntity();
}
}
And finally the Model
[XmlRoot()]
internal class PointInCaseProject : INotifyPropertyChanged
{
private ProjectDetails _details;
private List<EnvironmentalFactor> _environmentalFactors;
private List<TechnicalFactor> _technicalFactors;
private List<UserStory> _userStories;
private List<Actor> _actors;
/// <summary>
/// The list of User Stories contained
/// within the point case estimate project.
/// </summary>
[XmlElement()]
internal List<UserStory> UserStories
{
get { return _userStories; }
set
{
NotifyPropertyChanged(“UserStories”);
_userStories = value;
}
}
/// <summary>
/// The list of Technical Factors
/// within the point case estimate project.
/// </summary>
[XmlElement()]
internal List<TechnicalFactor> TechnicalFactors
{
get { return _technicalFactors; }
set
{
NotifyPropertyChanged(“TechnicalFactors”);
_technicalFactors = value;
}
}
/// <summary>
/// The list of Environmental Factors
/// within the point case estimate project.
/// </summary>
[XmlElement()]
internal List<EnvironmentalFactor> EnvironmentalFactors
{
get { return _environmentalFactors; }
set
{
NotifyPropertyChanged(“EnvironmentalFactors”);
_environmentalFactors = value;
}
}
/// <summary>
/// The list of Actors within the
/// point case estimate project.
/// </summary>
[XmlAnyElement()]
internal List<Actor> Actors
{
get { return _actors; }
set
{
NotifyPropertyChanged(“Actors”);
_actors = value;
}
}
/// <summary>
/// The details of the
/// point case estimate project.
/// </summary>
[XmlElement()]
internal ProjectDetails Details
{
get { return _details; }
set
{
_details = value;
NotifyPropertyChanged(“Details”);
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void Clear()
{
if (this._details != null) { this._details.Clear(); }
if (this._actors != null) { this._actors.Clear(); }
if (this._environmentalFactors != null)
{
this._environmentalFactors.Clear();
}
if (this._technicalFactors != null) { this._technicalFactors.Clear(); }
if (this._userStories != null) { this._userStories.Clear(); }
}
}
NOTE: This is not the entire code base and some things above have been left out or assumed, things such as the entities that are contained in generic<> lists in the model and all the subscribing handlers for view events that would be present in the presenters. At the end of the exercise I will follow up by implementing a small application using MVVM framework, putting me in a better position to discuss the differences and merits of both approaches. I have read some opinion that suggests that the Databinding abilities present in Silverlight and WPF are not equally as available to pre-exiting UI development frameworks such as MVC and MVP so I consider this is step one in putting that assertion to the test for my own sanity.
Of course a happy by-product of this exercise is getting a tool to manage my point case estimations for real world projects and in so doing I will be able to remove the dependence on the spreadsheet that currently manages this task for me. As it stands today, the project details tab has it’s data being persisted and I have decided to take a document centric approach to the persistence. Each project will save it’s estimation data in XML format locally in Isolated Storage and each file is saved as a .pce (point case estimate) file. I will post the Visual Studio solution when the project is complete.