Basic MVVM Template (with Ninject) ================================== `Program` Class --------------- Your program entry point should be changed to the following code snippet. This is more complex than the default one for .NET Windows Forms projects, but you'll have a fully usable Ninject kernel, emergency error handling on missing dependencies and cleanup of any services that implement `IDisposable`. ```csharp /// Setup code and main entry point for the application internal static class Program { /// The application's main entry point [STAThread] static void Main() { try { // Wrapping the application code in a method lets .NET's "fusion" linker to compile // and run the Main() method, even when there are missing dependencies. This enables // us to at least display some kind of error message rather than just fizzling out. runApplication(); } catch(Exception error) { MessageBox.Show( "Application failed to launch: " + error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error ); } } /// /// Initializes services, creates the main window and keeps the application running /// until the main window closes. /// private static void runApplication() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); // Set up our dependency injector and all its bindings using(var kernel = new StandardKernel()) { setupBindings(kernel); // Then let the window manager create the view model and show the window var windowManager = kernel.Get(); Application.Run(windowManager.OpenRoot()); } } /// Setups up dependency bindings for the application /// Dependency injector the bindings will be set up in private static void setupBindings(IKernel kernel) { kernel.Load(); kernel.Bind().ToConstant(kernel); } } ``` MainForm -------- The main window should inherit from `ViewForm`. It won't change anything regarding how you use Windows Forms designer and such, but it gives your main window a new property: `DataContext`. The name `DataContext` comes from WPF and UWP and is used for data binding. For example, a list control would have a `DataContext` property to which you can assign any kind of list object to make the list control display its contents. Similarly, the `DataContext` of your main window will be its view model. The `WindowManager` of `Nuclex.Windows.Forms` checks if your Form inherits from `ViewModel` and automatically assigns the view model to the `DataContext` if it can. ```csharp /// Main window for the application public partial class MainForm : ViewForm { /// Initializes a new main window public MainForm() { InitializeComponent(); } /// The view model for the main window under its proper type private MainViewModel ViewModel { get { return DataContext as MainViewModel; } } // ... } ``` MainViewModel ------------- As you could already see in the `Program` class at the top, rather than create and display a form itself, the new `Program` class just asks the `WindowManager` to "open" the `MainViewModel` and create its default view, which is discovered by name. Names it will try are: `MainView`, `MainPage`, `MainForm`, `MainWindow`, `MainDialog` and `MainControl`. ```csharp var windowManager = kernel.Get(); Application.Run(windowManager.OpenRoot()); ``` Thanks to Ninject, our `MainViewModel` can have constructor parameters and Ninject will try to satisfy them by looking in its bound services: ```csharp /// View model for the application's main window public class MainViewModel : ViewModel { /// Initializes a new view model for the main view /// Window manager used to display child windows /// Service to display messages to the user public MainViewModel( IWindowManager windowManager, IMessageService messageService, ) : base(windowManager) { this.messageService = messageService; } /// Displays an example message to the user public void ShowExampleMessage() { this.messageService.Inform( new MessageText() { Caption = "Example", Message = "This is an example message." } ); } /// Reports an error to the user /// Error that will be reported protected override void ReportError(Exception exception) { this.messageService.ReportError( new MessageText() { Caption = "Error", Message = "An error has occurred: " + exception.Message } ); } /// Displays messages to the user private IMessageService messageService; } ```