简体   繁体   中英

Loading a Taskbar Icon from resources and using Prism to inject view model

Background

I am trying to write an application which primarily lives on the system tray, it will in the future have a window so on right clicking the icon it opens the window.

The Code

I currently have no shell being defined on Prism startup ie:

protected override Window CreateShell()
{
    return null;
}

The notify icon (using Hardcodet.NotifyIcon if that makes any difference?) is defined in a resources dictionary, as i don't have a startup View xaml to add the icon to:

<!-- the application's NotifyIcon - started from App.xaml.cs. Declares its own view model. -->
    <tb:TaskbarIcon x:Key="NotifyIcon"
                    IconSource="{Binding UserStatus, Converter={StaticResource UserStatusToImageSourceConverter}}"
                    ToolTipText="Double-click for window, right-click for menu"
                    DoubleClickCommand="{Binding ShowWindowCommand}"
                    ContextMenu="{StaticResource SysTrayMenu}">

         <!--self-assign a data context (could also be done programmatically)--> 
        <tb:TaskbarIcon.DataContext>
            <viewModels:NotifyIconViewModel />
        </tb:TaskbarIcon.DataContext>
    </tb:TaskbarIcon>

The view model, as you can see on the later part of that snippet, takes the NotifyIconViewModel , which has a constructor argument so I can use the IEventAggregator to communicate between the different parts of views (like a view in the context menu shown when you just plain click on the tray icon).

The signature of the view model looks like so:

public NotifyIconViewModel(IEventAggregator eventAggregator)
{
    _eventAggregator = eventAggregator;
    ...
}

The services are registered:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    ...
    containerRegistry.Register<NotifyIconViewModel>();
}

And the Notify Icon itself is instantiated in the OnInitialized Method:

protected override void OnInitialized()
{
    base.OnInitialized();
    notifyIcon = (TaskbarIcon)FindResource("NotifyIcon");
}

The Issue

However, the exception being thrown on startup is that no default constructor could be found for the view model (correct, there isnt one). But my reading is that the prism architecture should be able to inject the view model (and its deps) when required?

XamlParseException

I can only assume I am initializing the notify icon incorrectly and that FindResource does not cause the prism library constructor injection/DI parts to be triggered, but what would the correct way for this behaviour to be carried out be?

Dependencies are injected if you use the container to construct (aka. resolve) the object.

This happens when a normal Prism application resolves the shell, which (by using the ViewModelLocator ) resolves the shell's view model which resolves alle the dependencies of the shell's view model and the dependencies of those dependencies and so on.

If you do not use the container (ie by constructing objects directly in xaml), it won't resolve any dependencies for you.

You could create the icon and use the container to resolve the NotifyIconViewModel and set it as DataContext :

protected override void OnInitialized()
{
    base.OnInitialized();
    notifyIcon = (TaskbarIcon)FindResource("NotifyIcon");
    notifyIcon.DataContext = Container.Resolve<NotifyIconViewModel>();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM