A reference architecture for large WPF projects
Introduction
Choosing an adequate architecture is crucial for the success of a software project. You can have the best concepts, if your architecture does not perform, the user will have bad experiences while waiting for the application to load. Also aspects like it's robustness, maintainability or testability are important to address.
WPF provides a powerful databinding framework. If we could take advantage of this by using the MVVM pattern and decouple our views by dependency injection, we can build a powerful scaleable architecture.
These are the key components or patterns we want to use:
- WPF DataBinding
- Model-View-ViewModel pattern
- Dependency Container (e.g. Unity)
- Actions from the System.Windows.Interactivity library
How it works
The basic idea is to have a dependency container that builds up a view. The view has a viewmodel injected, that is bound to the DataContext. The viewmodel concentrates and provides data and commands for the view that it gets from services, that are injected by the constructor. The services live as singletons within the container.
Using this architecture allows you to build up loosely coupled views that interact magically together over common data coming from services in the background. It's very simple to rearrange or replace views, since they have to dependencies among each other.
Advantages of this architecture:
- UI elements are easily replaced because of flexible databinding
- The views are loosely coupled and quickly composed together
- The viewmodel can be tested with conventional unit testing
- Each service has a single purpose. They are easy to develop and make the architecture scalable.
Initializing the container and build up the main window
public class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<ICustomerService, CustomerService>();
container.RegisterType<IShoppingCartService, ShoppingCartService>();
MainWindow mainWindow = container.Resolve<MainWindow>();
mainWindow.Show();
}
}
Injecting the viewmodel to the view
By adding a [Dependency] attribute to the property, the dependency container resolves and injects the specified type after creating the view. The injected viewmodel is directly set to the data context of the view. The view itself contains no other logic.
public class MainWindow : Window
{
[Dependency]
public MainWindowViewModel ViewModel
{
set { DataContext = value; }
}
public MainWindow()
{
InitializeComponent();
}
}
Implementing the viewmodel
public class MainWindowViewModel
{
private ICustomerService _customerService;
public MainWindowViewModel(ICustomerService customerService)
{
_customerService = customerService;
Customers = new ListCollectionView(customerService.Customers);
}
public ICollectionView Customers { get; private set; }
}
Binding the data to the view
<Window x:Class="WpfTutorial.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox ItemsSource="{Binding Customers}" />
</Window>
Last modified: 2010-02-10 10:34:15
Copyright (c) by Christian Moser, 2011.
Comments on this article
Show all comments
|
chinnappa | |
|
Commented on 13.January 2010 |
awesome !!
|
|
|
|
Alec | |
|
Commented on 26.January 2010 |
Great post. One thing I would change is rather than having a write-only ViewModel property, pass it as a parameter to the constructor of the window class.
WPF doesn't require parameterless constructors.
|
|
|
|
mukesh | |
|
Commented on 4.February 2010 |
thanks..
|
|
|
|
sagar tambe | |
|
Commented on 23.February 2010 |
This is think i m looking from long time. Architecture wise WPF make sense isn't it?
|
|
|
|
Jeremy | |
|
Commented on 18.March 2010 |
@Sagar
DI was around LONG before WPF. You should look at Martin Folwers articles from the beginning of this decade.
|
|
|
|
rashmin | |
|
Commented on 13.May 2010 |
great job...
|
|
|
|
Chris Bellew | |
|
Commented on 5.June 2010 |
Can this be done with MEF? Gotta love MEF.
|
|
|
|
Bill | |
|
Commented on 19.July 2010 |
Doesn't Prism wrap this functionality?
|
|
|
|
Manish K | |
|
Commented on 21.July 2010 |
Good Explanation
can we have source code to download?
|
|
|
|
StevenH77 | |
|
Commented on 23.July 2010 |
Downloadable source would be great!
|
|
|
|
San | |
|
Commented on 28.July 2010 |
we can make good ny having code , from where we can have this souce code
|
|
|
|
San | |
|
Commented on 28.July 2010 |
we can make good practice having code , from where we can have this souce code
|
|
|
|
JIm | |
|
Commented on 11.August 2010 |
What a great idea, palagarize other peoples material, have ads and make money.. who says crime doesn't pay.
|
|
|
|
Jak | |
|
Commented on 5.September 2010 |
better if you provide a Sample of this Explnation.
|
|
|
|
Viral Dave | |
|
Commented on 8.September 2010 |
Great work...
|
|
|
|
Gopal | |
|
Commented on 16.October 2010 |
Why MainWindow knows about the view Model(have logical reference though property)
|
|
|
|
Donny Brasco | |
|
Commented on 15.November 2010 |
Great posts, wanted to see PRISM in the works and how would start my project using it,this clears up a lot of things. May you please provide source code so as to see it in code and study how this all ties up together
|
|
|
|
Donny Brasco | |
|
Commented on 15.November 2010 |
Great posts, wanted to see PRISM in the works and how would start my project using it,this clears up a lot of things. May you please provide source code so as to see it in code and study how this all ties up together
|
|
|
|
Sushil | |
|
Commented on 28.December 2010 |
Describe some thing more for new commers
|
|
|
|
Achim Koch | |
|
Commented on 11.February 2011 |
Thank you for your post. But, sorry, charts (modelling) and code doesent fit at all. There is no ShoppingCartService in your charts and there is no OrderService in your code. Can you please post some more consistent stuff? It's a little hard to put all pieces togehter, otherwise.
|
|
|
|
Achim Koch | |
|
Commented on 14.February 2011 |
I have coded it a little - not exactly the above modele but some of it.
But I don't know where to put the code. Can you help me out?
|
|
|
|
pouyan | |
|
Commented on 8.August 2011 |
these kinda articles ain't a tutorial. you have explained very short abour dependency injection and your code and diagrams are not useful at all. if you would uploaded a sample project for each article that would helped a lot.
|
|
|
|
nagarjunareddy | |
|
Commented on 9.August 2011 |
chala bagundhi....
|
|
|
|
alireza | |
|
Commented on 30.August 2011 |
thanks my dear!
|
|
|
|