Version 1.0.18 has been released of my Type Visualiser Tool. This release contains some cool new features but the biggest change was by far shifting to a more strict MVVM approach.
When writing the first release the agile-ist in me wanted to get a prototype up and running as quickly as possible. This resulted in a great deal of code behind to dynamically draw the visualisation. The driver behind the change was the increasing number of bugs, inconsistency of behaviour and ultimately difficultly of adding new features.
By changing to a strict MVVM approach and heavily leveraging data-binding most of the code behind shifted into controllers and the model. Once complete the justification was evident by the ease of adding new some new features.
Here's a summary of the new features:
Showing posts with label Mvvm. Show all posts
Showing posts with label Mvvm. Show all posts
Friday, August 24, 2012
Saturday, April 23, 2011
How to show a dialog in MVVM
In Mvvm you do not want direct references from your controllers (aka View-Models, I find it easier to call them controllers for simplicity). This means you don't want code that specifically calls Window.Show or MessageBox.Show. The reason is basically two-fold:
Message Box Usage
Message boxes pose a problem for unit testing because when open they block the thread from completing, meaning user intervention is required to continue a test. This is not acceptable. To circumvent this, MessageBox use can be accessed via an interface.
The above code works in production, but during testing a mock will need to be injected into the MessageBox property.
- First you will be unable to unit test the controller. Message-boxes or Dialogs popping open will halt the test.
- If you decide to share some code with another project that uses a different UI technology, then not following Mvvm explicitly will prevent this. Also common is stakeholders changing their minds.
The solution is to make use of an Inversion of Control container (aka factory).
Message Box Usage
Message boxes pose a problem for unit testing because when open they block the thread from completing, meaning user intervention is required to continue a test. This is not acceptable. To circumvent this, MessageBox use can be accessed via an interface.
private IMessageBoxService backingMessageBoxService;
public IMessageBoxService MessageBox {
get {
return this.backingMessageBoxService ?? (this.backingMessageBoxService = new WpfMessageBoxService());
}
private set {
// Provided for testing
this.backingMessageBoxService = value;
}
}
}
The above code works in production, but during testing a mock will need to be injected into the MessageBox property.
[Test(Description = "The save action should trigger a message box")]
[Timeout(500)]public void SuccessfulSaveMessage() {
var controller = new FormController(new ContactDataServiceStub());
var accessor = new FormController_Accessor(controller);
var messageBoxMock = new MessageBoxServiceMock();
accessor.MessageBox = messageBoxMock; // Click the save button in the same way the View xaml would in production.
controller.SaveCommand.Execute(controller.CurrentContact); Assert.IsTrue(messageBoxMock.WasShowCalled); }public interface IGlassDemoDialog {
event EventHandler Closed;
void Show();
}And from within your controller you can get a reference to the dialog through the use of an object factory (or using an interfaced property shown previously in this document).
var glassDialog = ObjectFactory.Container.GetInstance<IGlassDemoDialog>();
glassDialog.Show();This of course assumes you have a registration with the object factory either in the app.config or in startup.
ObjectFactory.Initialize(init => {// Other config lines here
init.For<IGlassDemoDialog>().Use<WpfGlassWindowDemo>();});Finally, your custom interface must be implemented by your View.
public partial class WpfGlassWindowDemo : Window, IGlassDemoDialog { }
[Test]public void ShowGlassWindowTest() {
var controller = new RighthandController();
var mockRepository = new MockRepository(); // Rhino Mock
var dialogMock = mockRepository.StrictMock<IGlassDemoDialog>(); dialogMock.Expect(dialog => dialog.Show());mockRepository.ReplayAll(); // Prepare mocks.
ObjectFactory.Initialize(init => { init.For<IGlassDemoDialog>().Use(dialogMock); });Assert.IsTrue(controller.GlassCommand.CanExecute(null));
controller.GlassCommand.Execute(null);
mockRepository.VerifyAll(); // Guarantee all mocks were used appropriately.
}
Saturday, April 16, 2011
MEF versus IoC
The Microsoft Extensibility Framework (MEF) has been around for a couple of years now and is used to allow extension to Windows applications without changing the original code (Recomposition). It can be used with either Silverlight, WPF, and WinForms. MEF is not a replacement to PRISM. The PRISM toolkit to help you implement the MVVM pattern and is similar to MVVM Light or any of the other MVVM Toolkits. PRISM is also only intended for WPF and Silverlight. So what is MEF? The MEF Website describes it as
"Application requirements change frequently and software is constantly evolving. As a result, such applications often become monolithic making it difficult to add new functionality. The Managed Extensibility Framework (MEF) is a new library in .NET Framework 4 and Silverlight 4 that addresses this problem by simplifying the design of extensible applications and components."
I've been a long standing fan of IoC, and after reading many articles about MEF and writing a few test applications, there seems to be a cross over with IoC. IoC is far more generic and is a more broad pattern to use across your entire system, whereas MEF is specifically targeting extending and recomposition of the UI. So where's the cross over? MEF is a kind of object factory (aka container), it makes replacement of UI Views and Controllers (aka View-Models) easy. By decorating a public property with an attribute the MEF framework with find all subclasses of (or a chosen one) and instantiate it and inject it into the property. Very much like an IoC container. But MEF does have some cool features for searching application folders for runtime add-ins etc. But so does StructureMap.
"Application requirements change frequently and software is constantly evolving. As a result, such applications often become monolithic making it difficult to add new functionality. The Managed Extensibility Framework (MEF) is a new library in .NET Framework 4 and Silverlight 4 that addresses this problem by simplifying the design of extensible applications and components."
I've been a long standing fan of IoC, and after reading many articles about MEF and writing a few test applications, there seems to be a cross over with IoC. IoC is far more generic and is a more broad pattern to use across your entire system, whereas MEF is specifically targeting extending and recomposition of the UI. So where's the cross over? MEF is a kind of object factory (aka container), it makes replacement of UI Views and Controllers (aka View-Models) easy. By decorating a public property with an attribute the MEF framework with find all subclasses of (or a chosen one) and instantiate it and inject it into the property. Very much like an IoC container. But MEF does have some cool features for searching application folders for runtime add-ins etc. But so does StructureMap.
Here's an excellent comparison from MSDN:
My take on it, is MEF will suit people new to IoC better, and might be more approachable. The documentation for MEF is pretty good, better than StructureMap's documentation for sure. Using a mature feature rich IoC container like StructureMap however you get most of the functionality of MEF, but it requires a little more work to use. But it gives you the advantage of a unified approach and good consistency.
Wednesday, February 16, 2011
Using MEF to expose interfaces in your Silverlight Mvvm Apps
Great article on building composable applications in MEF and using the MVVM pattern.
Using MEF to expose interfaces in your Silverlight MVVM Applications.
Using MEF to expose interfaces in your Silverlight MVVM Applications.
Wednesday, January 5, 2011
Visual State Manager in WPF4
One of the questions I hear as a Silverlight Developer is why are there no Triggers in Silverlight? This question has been answered a few times (one of which is in references below). Mainly because Silverlight has always had the Visual State Manager (VSM) which is far more powerful than triggers.
Triggers were a great tool for developers in WPF for a while, and were really easy to implement in code. Developers loved them but designers hated them. Designers had no way of applying easing animations or "softer" transitions rather than just a snap into another state. In fact now, WPF4 has the VSM as well and combined with Blend 4 the VSM is easy to use and very fast to create different visual representations of a button for default and mouse over and animations in between for example.
If you are starting a new WPF application you would be wise to prefer VSM over triggers. Even in the most basic state changes, there may be a time when someone will want to add animation or edit it in Blend. Blend doesn't play nicely with triggers I have found.
I wrote a quick little demo to show how the VSM works and how to use it with the MVVM pattern.
Download the code here.
Screen shots:
You can't see the easing animation in the screenshots obviously, but its there in the code. There are 2 states for this sample application, there is either an incoming call, or you are on a call. Depending on the state the button color and text changes.
The challenge with MVVM is that you want the controller to own and control the state. This is done by the magic of binding to an attached property.
Here's the State property on the controller:
The return type is a simple custom enum (with 2 possible values). The MainActionLabel is where the button gets its text from, which in my simple example is using a switch case to return appropriate text.
Here's the Xaml binding for Visual State:
Here you can see the binding to a custom attached property, this is done at the control level. In my case the control is the entire panel showing a button on the right and some text on the left. In this example the state applies to the whole user control.
Here's the code for the attached property:
The critical piece here is the OnVisualStateNameChanged, this is triggered when the controller changes the underlying value. When it does the VisualStateManager.GoToState static method is called, and the magic begins.
Summary
Using the VSM is even easier if you choose not to use MVVM, but even using MVVM it is pretty straight forward. Even for quick simple applications I find myself regretting using triggers and not using VSM straight off, just like when I think using code behind might be quicker than using MVVM.
It might be a little more code than using triggers but it is definitely more flexible and easier to get right. Designers can use Blend to perfect animations and colours leaving us developers to get the real work done ;-)
References:
Triggers were a great tool for developers in WPF for a while, and were really easy to implement in code. Developers loved them but designers hated them. Designers had no way of applying easing animations or "softer" transitions rather than just a snap into another state. In fact now, WPF4 has the VSM as well and combined with Blend 4 the VSM is easy to use and very fast to create different visual representations of a button for default and mouse over and animations in between for example.
If you are starting a new WPF application you would be wise to prefer VSM over triggers. Even in the most basic state changes, there may be a time when someone will want to add animation or edit it in Blend. Blend doesn't play nicely with triggers I have found.
I wrote a quick little demo to show how the VSM works and how to use it with the MVVM pattern.
Download the code here.
Screen shots:
You can't see the easing animation in the screenshots obviously, but its there in the code. There are 2 states for this sample application, there is either an incoming call, or you are on a call. Depending on the state the button color and text changes.
The challenge with MVVM is that you want the controller to own and control the state. This is done by the magic of binding to an attached property.
Here's the State property on the controller:
public CallCardState CurrentState { get { return this.currentState; } private set { this.currentState = value; NotifyPropertyChange("CurrentState"); NotifyPropertyChange("MainActionLabel"); } }
The return type is a simple custom enum (with 2 possible values). The MainActionLabel is where the button gets its text from, which in my simple example is using a switch case to return appropriate text.
Here's the Xaml binding for Visual State:
<UserControl
x:Class="VSMTest.CallCard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
d:DesignHeight="200"
d:DesignWidth="300"
local:VisualStateHelper.VisualStateName="{Binding CurrentState}"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VSMTest" >
...</UserControl>
Here you can see the binding to a custom attached property, this is done at the control level. In my case the control is the entire panel showing a button on the right and some text on the left. In this example the state applies to the whole user control.
Here's the code for the attached property:
namespace VSMTest { using System; using System.Windows; using System.Windows.Controls; public class VisualStateHelper : DependencyObject { public static readonly DependencyProperty VisualStateNameProperty = DependencyProperty.RegisterAttached( "VisualStateName", typeof(string), typeof(VisualStateHelper), new PropertyMetadata(OnVisualStateNameChanged)); public static string GetVisualStateName(DependencyObject target) { return target.GetValue(VisualStateNameProperty).ToString(); } public static void SetVisualStateName(DependencyObject target, string visualStateName) { // This may throw an exception if an enum is used. However, it shouldn't be used as the user control // should not set its own state, the controller will always set it. try { target.SetValue(VisualStateNameProperty, visualStateName); } catch (Exception ex) { throw new NotSupportedException("Setting visual states from within the user control or from binding is not supported. It should be set by the controller", ex); } } private static void OnVisualStateNameChanged(object sender, DependencyPropertyChangedEventArgs args) { var visualStateName = args.NewValue.ToString(); var control = sender as Control; // Must be a control, ie an input control. if (control == null) { throw new InvalidOperationException("This attached property only supports types derived from Control (ie UserControl)."); } // Apply the visual state. VisualStateManager.GoToState(control, visualStateName, true); } } }
Summary
Using the VSM is even easier if you choose not to use MVVM, but even using MVVM it is pretty straight forward. Even for quick simple applications I find myself regretting using triggers and not using VSM straight off, just like when I think using code behind might be quicker than using MVVM.
It might be a little more code than using triggers but it is definitely more flexible and easier to get right. Designers can use Blend to perfect animations and colours leaving us developers to get the real work done ;-)
References:
Monday, December 13, 2010
Microsoft WPF 2010 Ribbon
I've been looking into implementing a ribbon control, and found that Microsoft have released the source for there 2010 ribbon! (The 2010 Ribbon is also known as a "Scenic" Ribbon style). Great stuff, thanks Microsoft!
Check out these links for more information:
I've also started reviewing the Fluent Ribbon. See these links:
Check out these links for more information:
- Announcing the Wpf Ribbon
- Download the Ribbon and Samples
- Ribbon Home Page
- WPF Blog - Building a Simple Ribbon App
Microsoft also have a page describing what the different components of the ribbon are and when it should be used: Ribbon WPF and also some common application UI patterns and usage recommendations.
There is full support for the MVVM pattern in the ribbon and support for ICommand.
Screenshots:
Here's one I have started to customise to push the ribbon to the right to make space for companion panel I want to sit next to the ribbon.
I've also started reviewing the Fluent Ribbon. See these links:
Looking at it from a code difficulty point of view and amount of code required, Fluent is definitely easier and you write about 30% less code than what is required for the Microsoft WPF Ribbon. However, the Microsoft offering seems to be faster, and has better support for MVVM.
I am also looking into Infragistics .NetAdvantage 2010 Volume 3, which includes (as of October 2010 I believe) a "Scenic" Office 2010 style Ribbon Bar. It also has a cool feature called ColorWash which allows a measure of control over the color scheme of the bar.
It looks pretty cool on the surface but it doesn't give you exact control over the resulting color. Which I found quite annoying. I found it far too hard to restyle this to be a black scheme. Infragistics have only given one simple Office 2010 style, the blue "Scenic" style. Seems like the Henry Ford approach, "...you can have any color as long as its black...". Finally the overall style does not seem to match closely the Office 2010 style, it seems a little over simplified.
The above example has set the Wash Color to Black. But this is still no where near dark enough, and doesn't give me the control I want. For example changing the background to a different gradient fill. You can also see the style is subtly simpler than the Fluent and Microsoft images above.
My verdict? In my humble opinion Infragistics comes in at third on this one. It feels like they have retro fitted 2010 styling rather than considering all the features in the Office 2010 Ribbon. Fluent is very good and seems easy to use but there are a few tiny things missing in comparison to Microsoft. However, if ease of implementation is what you're after Fluent looks like the way to go. Me personally, I need all the features Microsoft has over Fluent (Keyboard Navigation, full control of Backstage, and mini-toolbar and shortcut tool-bar).
I am also looking into Infragistics .NetAdvantage 2010 Volume 3, which includes (as of October 2010 I believe) a "Scenic" Office 2010 style Ribbon Bar. It also has a cool feature called ColorWash which allows a measure of control over the color scheme of the bar.
It looks pretty cool on the surface but it doesn't give you exact control over the resulting color. Which I found quite annoying. I found it far too hard to restyle this to be a black scheme. Infragistics have only given one simple Office 2010 style, the blue "Scenic" style. Seems like the Henry Ford approach, "...you can have any color as long as its black...". Finally the overall style does not seem to match closely the Office 2010 style, it seems a little over simplified.
The above example has set the Wash Color to Black. But this is still no where near dark enough, and doesn't give me the control I want. For example changing the background to a different gradient fill. You can also see the style is subtly simpler than the Fluent and Microsoft images above.
My verdict? In my humble opinion Infragistics comes in at third on this one. It feels like they have retro fitted 2010 styling rather than considering all the features in the Office 2010 Ribbon. Fluent is very good and seems easy to use but there are a few tiny things missing in comparison to Microsoft. However, if ease of implementation is what you're after Fluent looks like the way to go. Me personally, I need all the features Microsoft has over Fluent (Keyboard Navigation, full control of Backstage, and mini-toolbar and shortcut tool-bar).
Thursday, September 2, 2010
Microsoft Patterns & Practice's Prism Demo
References:
- Microsoft Composite WPF Home Page
- Channel 9 Video: What is Prism? Blaine Wastell, Bob Brumfield
- Download Prism v2.2
- Community Codeplex site
- Quick Start Demos
Summary (from the official Microsoft Site)
Prism (Composite Application Guidance for WPF and Silverlight) is designed to help you more easily build enterprise-level Windows Presentation Foundation (WPF) client applications. This guidance will help you design and build flexiblecomposite client applications-composite applications use loosely coupled, independently evolvable pieces that work together in the overall application.The Composite Application Guidance can help you develop your client application in a modular fashion. With this approach, you manage the complexity of a large application by breaking it down into smaller, simpler modules. The modules can evolve independently while working together as a unified application.
This version of the Composite Application Guidance is designed to help you build applications in WPF and Silverlight that have a single code base.
Architectural Goals
The Composite Application Library is designed to help architects and developers achieve the following objectives:- Create a complex application from modules that can be built, assembled, and, optionally, deployed by independent teams using WPF or Silverlight.
- Minimize cross-team dependencies and allow teams to specialize in different areas, such as user interface (UI) design, business logic implementation, and infrastructure code development.
- Use an architecture that promotes reusability across independent teams.
- Increase the quality of applications by abstracting common services that are available to all the teams.
- Incrementally integrate new capabilities.
Messaging and Event Aggregators
Comparing the Prism offering of Event Aggregator and with Mvvm Light, is clear that Mvvm Light is a far nicer syntax.
Mvvm Light Event Aggregator - Send a Message / Event Notification
Messenger.Default.Send(new NotificationMessage(this, "Show Modal Dialog"));
Mvvm Light Event Aggregator - Receive a Message / Event
Messenger.Default.Register<NotificationMessage>(this, SomeEventHandlerMethod);
Compare that with the Prism Event Aggregator:
Sender:
NotificationEvent x = eventAggregator.GetEvent<NotificationEvent>();x.Publish("Show Modal Dialog");
Listener:
NotificationEvent x = eventAggregator.GetEvent<NotificationEvent>();x.Subscribe(message => SomeEventHandlerMethod(message));
Yep... I know which one I prefer.
I don't think I'll look any closer at Prism (or MEF or whatever its called this month) until I need more loose coupling with internal components.
Tuesday, June 22, 2010
Wpf Animations and Mvvm
One of the many topics I have been wanting to look into in more detail lately has been how animations specifically work with MVVM. It seems to be more complicated than it first appears on the surface. If the state of a controller (ViewModel) changes then the view follows suit by binding to a state property or at least using a DataTrigger etc. The View either changes immediately to the new visual state (like show/hiding a panel) or beginning an animation to show or hide something. But what if you wanted to play the animation storyboard and once it finished then allow the state to change?
One of the best MVVM resources I have read recently is Josh Smith's Advanced MVVM mini-book.
In this book he talks about this very topic among many other relevant topics under the heading Advanced MVVM.
You can download his source code for this book here. Its a rather simple but cool game.
If I was to approach this, my simplistic approach simply would be to expose events on the controller for each phase passing through any necessary information as an EventArgs subclass. This isn't as elegant, but would still be suitable. The challenge is effectively communicating back to the controller the view has completed its animation transition. This could be achieved one of two ways:
1) Use the completed event on the storyboard to call a method on the controller.
2) Pass a delegate as a event args parameter which is called when on the storyboard complete event is raised.
The real question here is: Is there a better way using Blend4 with visual states? Like most things in life the question to one answer simply leads to at least 2 more questions. I suspect not, as a visual state cannot help you define dynamic storyboards that change.
Wednesday, April 28, 2010
Mvvm Resources
Here is a great list of Mvvm (Model, View, View-Model pattern) resources:
- Josh Smith's MSDN article on MVVM (Good introduction of Mvvm)
- Karl Schifflett's Begining to Explore WPF's MVVM and another validation demo, and one more, from Karl (good demo of validation and presentation of validation errors)
- Dan Crevier's Data-Model, View, View-Model series (nice explanation and demo of commands)
- Josh Smith's Using Tree View with Mvvm (and easy searching code)
- Josh Smith's Controlling focus from a view-model
- Josh Smith & Karl Schifflett Creating an Internationalised Wizard
- Karl Schifflett's BBQ Shack Demo Application (Excellent demo of what I would call a "marshalled" navigation strategy, and also Windows ALT-TAB style task switching).
- Another Josh Smith Article on Testing where the subject under test uses a Dispatch Timer.
Thursday, February 25, 2010
Mvvm Pattern
Overview:
MVVM stands for Model-View-ViewModel. This is a variation of the MVC pattern, and although MVVM has a controller like component called the ViewModel, I personally find it easier to still call this the controller.
The basic premise of any derivative of the MVC Pattern.
The main idea of MVVM is to take full advantage of WPF Data-Binding to allow very loose coupling between the Controller and the View. This means the Controller does not have a reference to the View and the View only has an 'object' typed reference to the controller using its DataContext property. This makes the Controller a POCO that can easily be tested and its dependencies mocked/stubbed (ie it doesn't have a reference to a Window/UserControl/Page object that is difficult to mock).
More Info Links:
Here's a quick reference list of resources on the WPF MVVM pattern.
2) Microsoft Patterns And Practises for Composite Application Design (Ms Patterns and Practise Dev Center)
Here's a diagram from Karl Shifflett giving a good overview of what each component of the MVVM model contains:
Coupling Between Views and Controllers
There are two schools of thought on how exactly to link your views to your controllers. It depends on how purist you are on maintaining loose coupling between views and controllers, and how reusable you would like your views (xaml) to be. Most of the time, despite best efforts, I have found that reusing Xaml occurs pretty infrequently, except of course in the case of properly designed controls, for example a customised Drop-Down-List is highly reusable, but a User-Control isn't that reusable.
The Purist Loose Couple Approach
Following the loose coupling purist path neither the views nor the controllers have links to each other. Its only the use case that links them together. The downside of this, is that instantiating the view and controller can be a wordy process. This can be simplified a little however.
I found the process of instantiating the views and controllers in pairs and setting close handlers a little tedious; and possibly forgetting a step results in annoying but obvious bugs. The process of constructing the pairs and initializing can be simplified with a Builder Pattern.
The code before:
9 var window = new MainWindow();
10 var viewModel = new MainWindowViewModel("Data/customers.xml");
11
12 EventHandler handler = null;
13 handler = delegate {
14 viewModel.RequestClose -= handler;
15 window.Close();
16 };
17 viewModel.RequestClose += handler;
18
19 window.DataContext = viewModel;
20 window.Show();
The code after:
9 var builder = new ViewControllerPairBuilder(() => new MainWindow(), () => newMainWindowViewModel("Data/customers.xml"));
10 var viewModel = builder.BuildViewAndController();
11 builder.ShowView();
The Simplistic Approach
This involves creating less than loose coupling between the view and the controller. There are several ways to do this depending on what is easy in the use case.
In the constructor of the view it instantiates the controller and sets its own DataContext.
7 public partial class Shell : IDisposable {
8 private readonly IViewController controller;
9 private CommandBinding applicationCloseBinding;
10
11 /// <summary>
12 /// Initializes a new instance of the <see cref="Shell"/> view class.
13 /// </summary>
14 public Shell() {
15 this.InitializeComponent();
16 this.controller = new ShellController();
17 this.DataContext = this.controller;
18 this.Closing += this.MainWindowClosingHandler; // Notify controller of closing
19 this.Loaded += (s, e) =>this.SetWindowSize(Properties.Settings.Default.WindowPosition);
20 this.controller.RequestClose += this.ControllerRequestClose;
21 }
22 public void Dispose() {
23 var disposable = this.controller as IDisposable;
24 if (disposable != null) {
25 disposable.Dispose();
26 }
27 }
Or better yet, the DataContext can be set with binding from a parent control. This is better because the coupling between view and controller is on a per-use-case basis. Therefore in the case of the BannerView view there will be no reference to the controller.
20 <local:BannerView
21 x:Uid="ContentPresenter_1"
22 DataContext="{Binding Path=TopBannerRegion}"
23 DockPanel.Dock="Top" />
Or, let Xaml create the instance for you...
20 <local:BannerView x:Uid="ContentPresenter_1">
21 <local:BannerView.DataContext>
22 <local:BannerController />
23 </local:BannerView.DataContext>
24 </local:BannerView>
Or, let Wpf choose a DataTemplate appropriate for the underlying bound property, which is an instance of a controller.
19 <ContentPresenter
20 x:Uid="ContentPresenter_4"
21 Content="{Binding Path=TopBannerRegion}" />
22 <DataTemplate
23 DataType="{x:Type local:BannerController}">
24 <local:BannerView />
25 </DataTemplate>
This approach means you can show any kind of controller in that part of the UI as long as you have taken the time to define a DataTemplate to tell Wpf how to show something of that type. This technique is great for showing any content in a "Main" panel within a Wpf Application
Generally it is acceptable to maintain a link to the controller within the view, because the views generally are not unit tested. A reference to the controller may be required if events are subscribed to and unsubscription needs to occur during the view shutdown. When a case arises to reuse the view in a completely different use case that requires a different controller, a common interface should be constructed and the view only contains an interface reference.
I personally believe the simplistic approach is more preferable.
Controlling Setting Keyboard Focus
Today I read an excellent article on Josh Smith's site describing a very tidy technique for overcoming triggering a change of focus from within a controller (remember I like to call the ViewModel a controller). Ordinarily I have solved this issue with a rather cumbersome technique of exposing an interface either specific to the view or a general interface that passes a use case token to tell the view where to set the focus. This requires an interface to be implemented by the view and this to be consumed by the controller. This is clearly polluting the Mvvm pattern intention.
Josh's legendary idea is to override/extend the binding mechanism to check for an implementation of IFocusMover on the DataContext. If it detects one, it subscribes to the MoveFocus Event. This event is then caught by the new binding subclass and is moved on request.
Another competing strategy here by Anvaka. The crux of it is that Josh's above method could be accused of being a little opaque and not clear how it works and how to debug when things don't work as they should. A similar extension would need to be written for Multi-Binding as well. Anvaka's solution requires a little more code to work, but is much more clear. The downside is that the bound bool properties that indicate focus could all be true.
I think I personally still prefer Josh's method.
Subscribe to:
Posts (Atom)











