Friday, February 26, 2010

Wpf Single Instance Application

Sometimes it makes sense to keep the default behaviour of a .Net application that allows you to start multiple instances of the app.  For example: multiple instances of Visual Studio to house multiple solutions.  But other times it doesn't make sense to allow the user to open a second instance of the same application. Like Microsoft Word for example. It that case you want it to open the document but not open another instance of winword.exe.

Interestingly this is a simple issue to fix in VB.Net Winforms apps, but not so straight forward in WPF using C#.  Essentially there are two main strategies:
1) Use an operating system mutex to prevent a second instance from opening. (But the problem is how do you pass commandline arguments to the already open first instance).
2) Use the VisualBasic library to take advantage of some nice functionality that takes care of pretty much everything.

Option 2, still uses a normal WPF Visual Studio Template, but starts the app using a Sub Main entry as opposed to App.xml.
Here's the start up class:

    public class Startup {
        [STAThread]
        public static void Main(string[] args)
        {            
            var wrapper = new SingleInstanceApplicationWrapper();
            wrapper.Run(args);           
        }
    }
Here's the wrapper that references and uses the Visual Basic Library to perform the single instance check:

    public class SingleInstanceApplicationWrapper : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase {        
        public SingleInstanceApplicationWrapper() {
            // Enable single-instance mode.
            this.IsSingleInstance = true;
        }

        private WpfApp app;

        protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e) {            
            this.app = new WpfApp();
            this.app.Run();

            return false;
        }

        // Direct multiple instances
        protected override void OnStartupNextInstance(Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e) {
            if (e.CommandLine.Count > 0) {                
                app.ShowDocument(e.CommandLine[0]);
            }
        }
    }

And finally here's the Custom Wpf App class that loads the Wpf main window and can handle the second instance command-lines:

    public class WpfApp : System.Windows.Application {
        protected override void OnStartup(System.Windows.StartupEventArgs e) {
            base.OnStartup(e);
            
            // Load the main window.
            this.Documents = new ObservableCollection<DocumentReference>();
            this.MainWindow = list;
            list.Show();

            // Load the document that was specified as an argument.
            if (e.Args.Length > 0) ShowDocument(e.Args[0]);
        }

        public ObservableCollection<DocumentReference> Documents { get; set; }        

        public void ShowDocument(string filename) {
            try {                
                Document doc = new Document();
                DocumentReference docRef = new DocumentReference(doc, filename);
                doc.LoadFile(docRef);                
                doc.Owner = this.MainWindow;
                doc.Show();
                doc.Activate();
                Documents.Add(docRef);
            } catch {
                MessageBox.Show("Could not load document.");
            }
        }
    }   

The semantics of loading documents is not important, what is important is the user's attempt to load a second instance of the app and with a command-line (in this case to load a document) was intercepted by the already loaded first instance and displayed in that. The same behaviour as Microsoft Word.



For option 1, this is possible using the Sytem.Threading.Mutex class.
Here is a basic example:

var createdNew = true;
using (var mutex = new Mutex(true, "ApplicationNameOrSomeText", out createdNew)) {
    if (createdNew) {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

The only missing nicety would be to give focus to the already loaded app.  A good example can be found on Fredrik Kelseths blog here.

In my opinion using the Visual Basic library feature is the tidiest way to achieve a good level of functionality, at least until WPF supports this natively.  Alternatives could be hosting a WCF service in process to receive the second instance command-line, but requires a fair amount of work to get this to sing.

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.

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();

Internally the builder sets the data context on the window, and sets up a default handler for close.


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 += (se=>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}" />

Then of course you must have a resource dictionary somewhere that contains a mapping to a DataTemplate to present something of the controller's type.

   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.