IgorShare Thoughts and Ideas

Consulting and Training

Tip: Showing a Main view as a tray app with Caliburn.Micro

Posted by Igor Moochnick on 03/31/2011

The trick here is to make sure that the main view doesn’t pop-up right away in a visible form. After creation and resolving all the binding rules – the main view should be in a Hidden form.

This can easily be achieved with customizing the WindowManager by sub-classing it and adding one extra method:

[Export]
public class CustomWindowManager : WindowManager
{
    public Window MainWindow(object rootModel, object context = null)
    {
        return CreateWindow(rootModel, false, context);
    }
}

As soon as you’ll have the new WindowManager – the logic for the root view creation in the Boostrapper should be adjusted accordingly:

protected override void DisplayRootView()
{
    var viewModel = IoC.Get<IShell>();

    var windowManager = IoC.Get<CustomWindowManager>();

    _mainWindow = windowManager.MainWindow(viewModel);
    _mainWindow.Hide();
}

Here is a simple ShellView that uses a WPF TrayIcon implementation from CodeProject:

<UserControl ...
             xmlns:tb="clr-namespace:Hardcodet.Wpf.TaskbarNotification;assembly=Hardcodet.Wpf.TaskbarNotification"
             xmlns:cal="http://www.caliburnproject.org"
             Visibility="Hidden">
    <Grid>
        <tb:TaskbarIcon
            Visibility="Visible"
            x:Name="MyNotifyIcon"
            IconSource="/Resources/Images/Bulb.ico"
            MenuActivation="LeftOrRightClick" PopupActivation="DoubleClick">
            <!-- Set a simple context menu  -->
            <tb:TaskbarIcon.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Exit" cal:Message.Attach="AppExit" />
                </ContextMenu>
            </tb:TaskbarIcon.ContextMenu>
        </tb:TaskbarIcon>
    </Grid>
</UserControl>

The View Model for this view is very straight forward:

[Export(typeof(IShell))]
public class ShellTrayViewModel : Screen, IShell
{
    public void AppExit()
    {
        Application.Current.Shutdown();
    }
}

That’s it.

Advertisements

5 Responses to “Tip: Showing a Main view as a tray app with Caliburn.Micro”

  1. Gunter Spranz said

    I am also using the NotifyIcon WPF project and have a found a different approach to this problem.

    In my project the root view model is a view model for the tray icon:


    class MyBootstrapper : TypedAutofacBootstrapper

    In my custom bootstrapper i register a custom WindowManager:


    protected override void ConfigureContainer(ContainerBuilder builder)
    {
    builder.Register(c => new MyWindowManager()).InstancePerLifetimeScope();
    }

    In TrayIconViewModel i just use windowManager.ShowWindow(mainViewModel) to show the window of the main application.

    Im my i override ShowWindow to special case the tray icon view model window activation. I also have code here to show always the same single window for a view model.


    class MyWindowManager : WindowManager
    {
    public override void ShowWindow(object rootModel, object context = null)
    {
    if (!HandleSpecialCaseTrayIconViewModel(rootModel, context))
    {
    ShowSingletonWindowForView(rootModel, context);
    }
    }

    static bool HandleSpecialCaseTrayIconViewModel(object rootModel, object context)
    {
    if (rootModel is TrayIconViewModel)
    {
    UIElement view = ViewLocator.LocateForModel(rootModel, null, context);
    ViewModelBinder.Bind(rootModel, view, null);
    var activatable = rootModel as IActivate;
    {
    activatable.Activate();
    }
    return true;
    }
    return false;
    }

    void ShowSingletonWindowForView(object rootModel, object context)
    {
    Window window = FindExistingWindowForViewModel(rootModel);
    if (window != null)
    {
    window.Activate();
    return;
    }
    base.ShowWindow(rootModel, context);
    }

    static Window FindExistingWindowForViewModel(object rootModel)
    {
    var viewAware = rootModel as IViewAware;
    if (viewAware != null)
    {
    object view = viewAware.GetView();
    return Application.Current.Windows.Cast().FirstOrDefault(window => window == view);
    }
    return null;
    }

  2. Gunter Spranz said

    Correction: it is


    class MyBootstrapper : TypedAutofacBootstrapper

    By the way, what is the tag for the nice formatted code display ?

  3. Gunter Spranz said

    I hate it when HTML-tags get in the way when posting.

    It is:

    class MyBootstrapper : TypedAutofacBootstrapper<TrayIconViewModel>

  4. Mikel said

    I’m coming here from http://caliburnmicro.codeplex.com/discussions/245755

    Your question is about showing a window based on a double-click. This code here seems to handle showing the tray icon and a context menu but I still don’t see how to show a window when they double-click on the icon. Did you get this to work?

    Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: