Nikhil Kothari Software Architect Microsoft Corporation Session Code: WUX312
Agenda A practical look at patterns for developing and designing well structured applications ViewModel (data-binding, commanding) Supporting Application Patterns Triggers, Actions and Behaviors Inversion of Control EventAggregator
Why Bother with Patterns? Guidelines and prescriptive approaches based on prior success Not rules Common vocabulary, nomenclature for describing building blocks, and their relationships Enable better tools support
Patterns for Separating UI and Logic MVC, MVP, ViewModel, … General approach Separate interaction logic from view Decouple components of app Motivations Loosely coupled building blocks Designer-developer workflow Greater degree of testability Data Model User Interface Interaction Logic
ViewModel Pattern MVVM (Model – View – ViewModel), Presentation Model Basic idea View model encapsulates application behavior independent of view View is responsible for rendering and user input Leverage data-binding and commanding to hook up view to its view model
Hello World From code-behind to ViewModel
Interaction Logic in Code-behind Data Model ViewView XAMLXAML Code-Behind Event Handlers Code-Behind
Interaction Logic in View Model Data Model ViewView XAMLXAML Code-BehindCode-Behind View Model State + Operations + Notifications Property change and other event notifications Data-binding and commands
Binding View – HelloWorldView.xaml View Model – HelloWorldViewModel.cs public class HelloWorldViewModel : INotifyPropertyChanged { public string Greeting { get; } public string Greeting { get; } public string Name { get; set; } public string Name { get; set; }} public class HelloWorldViewModel : INotifyPropertyChanged { public string Greeting { get; } public string Greeting { get; } public string Name { get; set; } public string Name { get; set; }}
Commanding View – HelloWorldView.xaml View Model – HelloWorldViewModel.cs public class HelloWorldViewModel : INotifyPropertyChanged { public ICommand HelloCommand { get; } public ICommand HelloCommand { get; } private void SayHello() { … } private void SayHello() { … } private bool CanSayHello() { … } private bool CanSayHello() { … } private DelegateCommand _helloCommand = private DelegateCommand _helloCommand = new DelegateCommand(SayHello, CanSayHello); new DelegateCommand(SayHello, CanSayHello);} interface ICommand { bool CanExecute(object parameter); bool CanExecute(object parameter); void Execute(object parameter); void Execute(object parameter); event EventHandler CanExecuteChanged; event EventHandler CanExecuteChanged;} public class HelloWorldViewModel : INotifyPropertyChanged { public ICommand HelloCommand { get; } public ICommand HelloCommand { get; } private void SayHello() { … } private void SayHello() { … } private bool CanSayHello() { … } private bool CanSayHello() { … } private DelegateCommand _helloCommand = private DelegateCommand _helloCommand = new DelegateCommand(SayHello, CanSayHello); new DelegateCommand(SayHello, CanSayHello);} interface ICommand { bool CanExecute(object parameter); bool CanExecute(object parameter); void Execute(object parameter); void Execute(object parameter); event EventHandler CanExecuteChanged; event EventHandler CanExecuteChanged;}
ViewModel-based Application TwitterBug
Declarative Interactivity Implement View-specific Logic Repeating patterns in code-behind encapsulated into components Reuse and less repetition Simplify design experience When an event occurs, perform some work… Triggers and Actions Encapsulation of specific triggers and actions Attach a Behavior to an existing UI element
Encapsulating View Logic Behaviors, Actions and Triggers
Triggers, Actions and Behaviors View – TweetBoxView.xaml <UserControl> </UserControl> </TextBox><UserControl> </UserControl> </TextBox>
Inversion of Control Managing Dependencies View models are very likely coupled to data models Coupling can get in the way of maintainability and testability View model should not instantiate its dependencies Inversion of Control Dependencies are handed to the view model through some form of initialization or dependency injection
Dependency Injection Using the Managed Extensibility Framework
DI by Hand View Code-behind – TweetBoxView.xaml.cs public class TweetBoxView : UserControl { public TweetBoxView() { public TweetBoxView() { InitializeComponent(); InitializeComponent(); ITwitterService svc = new ServerTwitterService(); ITwitterService svc = new ServerTwitterService(); DataContext = new TweetBoxViewModel(svc); DataContext = new TweetBoxViewModel(svc); }} public class TweetBoxView : UserControl { public TweetBoxView() { public TweetBoxView() { InitializeComponent(); InitializeComponent(); ITwitterService svc = new ServerTwitterService(); ITwitterService svc = new ServerTwitterService(); DataContext = new TweetBoxViewModel(svc); DataContext = new TweetBoxViewModel(svc); }}
DI with an IoC Container ServerTwitterService.csServerTwitterService.cs [Export(typeof(ITwitterService))] public class ServerTwitterService : ITwitterService { }[Export] public class TweetBoxViewModel { [ImportingConstructor] [ImportingConstructor] public TweetBoxViewModel(ITwitterService twitterService) { … } public TweetBoxViewModel(ITwitterService twitterService) { … }} TweetBoxViewModel viewModel = container.GetExport ().Value; container.GetExport ().Value;[Export(typeof(ITwitterService))] public class ServerTwitterService : ITwitterService { }[Export] public class TweetBoxViewModel { [ImportingConstructor] [ImportingConstructor] public TweetBoxViewModel(ITwitterService twitterService) { … } public TweetBoxViewModel(ITwitterService twitterService) { … }} TweetBoxViewModel viewModel = container.GetExport ().Value; container.GetExport ().Value;
Visual Representation of DI View Model #2 View Model #1 IoC Container ServicesServices ViewView ViewModelRegistryViewModelRegistry Binding Lookup Contains
EventAggregator Enable View Model Communication View models may want to talk to each other Unwanted coupling between event publisher and subscriber Use an event aggregator for light-weight pub/sub View Model Event Aggregator
View Model Communication using an EventAggregator
Using EventAggregator TweetBoxViewModel.cs, TwitterProfileViewModel.cs public class TweetBoxViewModel { public TweetBoxViewModel(IEventAggregator eventAggregator) { … } public TweetBoxViewModel(IEventAggregator eventAggregator) { … } … _eventAggregator.Publish(new TweetPostedEventArgs(…)); _eventAggregator.Publish(new TweetPostedEventArgs(…));} public class TwitterProfileViewModel { public TwitterProfileViewModel(IEventAggregator eventAggregator) { public TwitterProfileViewModel(IEventAggregator eventAggregator) { eventAggregator.Subscribe (OnTweet); eventAggregator.Subscribe (OnTweet); } private void OnTweet(TweetPostedEventArgs e) { … } private void OnTweet(TweetPostedEventArgs e) { … }} public class TweetBoxViewModel { public TweetBoxViewModel(IEventAggregator eventAggregator) { … } public TweetBoxViewModel(IEventAggregator eventAggregator) { … } … _eventAggregator.Publish(new TweetPostedEventArgs(…)); _eventAggregator.Publish(new TweetPostedEventArgs(…));} public class TwitterProfileViewModel { public TwitterProfileViewModel(IEventAggregator eventAggregator) { public TwitterProfileViewModel(IEventAggregator eventAggregator) { eventAggregator.Subscribe (OnTweet); eventAggregator.Subscribe (OnTweet); } private void OnTweet(TweetPostedEventArgs e) { … } private void OnTweet(TweetPostedEventArgs e) { … }}
Summary ViewModel is simple and natural fit for separating view and logic Application behavior in view model Data-binding and commanding as the glue between view and its model Decouple individual parts of application Use an IoC container and event aggregator Think about encapsulating view logic into triggers, actions and behaviors
Resources Slides + Demo Code + ViewModel-related blog posts Managed Extensibility Framework Silverlight Unit Testing Framework Other ViewModel-related reading Josh Smith’s MSDN article us/magazine/dd aspx
International Content & Community Resources for IT Professionals Resources for Developers Microsoft Certification & Training Resources Resources Tech ·Ed Africa 2009 sessions will be made available for download the week after the event from:
Complete a session evaluation and enter to win! 10 pairs of MP3 sunglasses to be won
© 2009 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION. Required Slide