Caliburn Micro Part 5: The Window Manager

来源:互联网 发布:origin作图软件官网 编辑:程序博客网 时间:2024/06/07 03:28

Hello again and welcome to the next post in our Caliburn Micro tutorial series. A relatively simple tutorial this time where we will be looking at the Window Manager. Before we begin, here are the links to the previous tutorials in this series:

Part 1: Getting Started
Part 2: Data Binding and Events
Part 3: More About Events and Parameters
Part 4: The Event Aggregator

Many of you who have played around with Caliburn Micro will know there is not much mentioned about the Window Manager. Due to this, I won’t be covering everything about the Window Manager, I’ll simply explain what I know about it. To demonstrate how to use the Window Manager, we will be extending the application we made in the first blog post of this series.

Using a Window Manager

You may remember from the getting started blog post that one of the first things we did was delete MainWindow.xaml from the project. Caliburn Micro takes care of initializing the window, setting its data context and displaying the appropriate view for us. The Window Manager is one of the mechanisms responsible for getting this done. When you run an application built with Caliburn Micro, the Window Manager is automatically used to create the startup window. For small applications, this is all you really need to know about the Window Manager. When you are building larger applications that need to display other windows or dialogs, it’s time to learn how to use the Window Manager. To demonstrate this we will add a button to the application which will open a new window when clicked. Start by adding a button to AppView.xaml and hooking the click event to a method in AppViewModel.cs. You can do this using Caliburn Micro conventions as explained in the previous tutorials. I have called this method “OpenWindow”. In the OpenWindow method we are going to need access to an instance of a Window Manager. Although we could simply create a new instance of WindowManager and use that, it is best practice to get a hold of the global Window Manager instance that Caliburn Micro makes available to the application. We can do this by making a constructor on AppViewModel.cs that takes in an IWindowManager and store it in a field. You may remember from part 4 of this blog series of what needs to be done when you create a constructor on a view model that has at least 1 parameter. Here is a recap in 3 easy step:

1. Update the bootstrapper as follows. Remember to add System.ComponentModel.Composition.dll as a reference in your project.

using Caliburn.Micro;using System.ComponentModel.Composition;using System.ComponentModel.Composition.Hosting;using System.ComponentModel.Composition.Primitives; public class AppBootstrapper : Bootstrapper<AppViewModel>{  private CompositionContainer container;   protected override void Configure()  {    container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));     CompositionBatch batch = new CompositionBatch();     batch.AddExportedValue<IWindowManager>(new WindowManager());    batch.AddExportedValue<IEventAggregator>(new EventAggregator());    batch.AddExportedValue(container);     container.Compose(batch);  }   protected override object GetInstance(Type serviceType, string key)  {    string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;    var exports = container.GetExportedValues<object>(contract);     if (exports.Count() > 0)    {      return exports.First();    }     throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));  }}

2. Use the Export attribute on the AppViewModel class:

[Export(typeof(AppViewModel))]public class AppViewModel : PropertyChangedBase{  ...}

3. Use the ImportingConstructor attribute on the AppViewModel constructor:

private readonly IWindowManager _windowManager; [ImportingConstructor]public AppViewModel(IWindowManager windowManager){  _windowManager = windowManager;}

Now we can use the Window Manager instance in our OpenWindow method to open a new window. To keep this tutorial simple, we will simply create a new window that also uses the AppViewModel as the data context. This is done using the following code:

public void OpenWindow(){  _windowManager.ShowWindow(new AppViewModel(_windowManager));}

Run this up and press the button to see another window appear. All we needed to do was pass in an instance of a view model, then everything else from creating the window instance and displaying the appropriate view for our view model is done for us. Once again Caliburn Micro makes our life easier!

Using the Window Manager in Caliburn Micro

The Window Manager has all sorts of methods and method overloads for opening windows, dialogs and popups. All these methods are fairly straight forward and easy to use. You can see more usage of the Window Manager in the HelloWindowManager sample that comes with Caliburn Micro. One more thing I wanted to look at is the ‘settings’ parameter. Here you can pass in a dynamic object used to set properties on the new window. This gives you fine-grained control on the appearance of your application if you need it. Here is an example where I am setting the WindowStartupLocation to be manual rather than center-owner.

public void OpenWindow(){  dynamic settings = new ExpandoObject();  settings.WindowStartupLocation = WindowStartupLocation.Manual;   _windowManager.ShowWindow(new AppViewModel(_windowManager), null, settings);}

Custom Window Managers

There are scenarios where it is useful to implement a custom Window Manager. This is good if you need to set properties on all Window instances to be common values. For example, properties could include the icon, the window state, window size and applying custom chrome. The most useful property that I have found to set on windows is the SizeToContent property. By default, Caliburn Micro sets this to be SizeToContent.WidthAndHeight. This means that the window automatically sizes itself based on its content. Although this can be convenient at times, I have found this to cause some issues with certain application layouts and seems to be buggy when setting the window to be maximized by default. Creating a custom Window Manager is very simple. Start by adding a class that extends WindowManager. Next, you can override the EnsureWindow method and do something like the following:

protected override Window EnsureWindow(object model, object view, bool isDialog){  Window window = base.EnsureWindow(model, view, isDialog);   window.SizeToContent = SizeToContent.Manual;   return window;}

In this method, we start by calling base.EnsureWindow() to create the window instance. Next you can set any properties on the window that you want, and then simply return the window instance. The last step is to set an instance of your custom Window Manager to be globally used by the application. In the first code snippet in this blog post we make modifications to the bootstrapper. Here you can see we are adding a WindowManager instance to the CompositionBatch. You can replace this to use an instance of your custom window manager instead which would look like this:

batch.AddExportedValue<IWindowManager>(new AppWindowManager());

That’s everything I wanted to cover with the Window Manager, I hope you found it useful in building great WPF applications powered by Caliburn Micro! I appreciate your comments and feedback on the series!

Download the full Visual Studio 2010 project for this tutorial.

Next time I’ll give you an introduction to screens and conductors.

Happy coding :)

0 0
原创粉丝点击