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.




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;
}
igormoochnick said
Thanks for the comment. Don’t you feel it’s a bit too complex?
Gunter Spranz said
Correction: it is
class MyBootstrapper : TypedAutofacBootstrapper
By the way, what is the tag for the nice formatted code display ?
Gunter Spranz said
I hate it when HTML-tags get in the way when posting.
It is:
class MyBootstrapper : TypedAutofacBootstrapper<TrayIconViewModel>
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!