MVVM Light,Ninject 主要用于通知区域应用程序 [英] MVVM Light, Ninject in a mostly notification area application

查看:18
本文介绍了MVVM Light,Ninject 主要用于通知区域应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要应用架构建议.

我正在构建一个支持通知区域图标的 .Net 4 WPF 桌面应用程序.

I am building a .Net 4 WPF desktop application with notification area icon support.

应用程序有几个窗口,在启动时显示,然后关闭,只剩下通知区域图标.

Application has a few windows, that show up on startup, then get closed, and only the Notification Area icon remains.

通知区域图标纯粹是我从 this codeproject 获得的 WPF 控件示例.

The notification area icon is purely WPF control that I got from this codeproject example.

由于即使关闭所有窗口,我的应用程序仍应保持运行状态,因此我设置了一个

Since my app should remain running even when all the windows are closed, I have set a

ShutdownMode="OnExplicitShutdown"

在 App.xaml 中.

in App.xaml.

我将描述我对架构和启动机制的想法,你告诉我哪里出错了,并在可能的情况下纠正我.

I will describe my idea of an architecture and startup mechanism, and you tell me where I am going wrong and correct me if possible.

在 App.xaml.cs 中,我创建了一个 Ninject StandardKernel,我们称之为 appKernel 并将 Ninject 模块加载到其中.起初,Ninject 只需要解析一个接口——一个 heartbeatManager 实例.HeartbeatManager 是我打算用于的类:

In App.xaml.cs I create a Ninject StandardKernel, let's call it appKernel and load Ninject modules into it. At first only one interface is to be resolved by Ninject - a heartbeatManager instance. A HeartbeatManager is a class I am planing to use for:

a) 将我的 NotifyIcon 实例托管为一个字段变量,这样只要类实例在内存中,它就会重新可见.

a) Hosting my NotifyIcon instance as a field variable, so that it reamins visible as long as the class instance is in memory.

b) 关闭事件的实现,当心跳类请求它时,我将在 app.xaml.cs 中订阅并明确关闭应用程序.

b) Implementation of shutdown event, that I will subscribe for in app.xaml.cs and shutdown the application explicitly, when the heartbeat class requests it.

此时创建了一个 heartbeatManager 实例,并挂在内存中.

At this point a heartbeatManager instance is created just left to hang in the memory.

在 App.xaml 中,我设置了 StartupUri="MainWindow.xaml" 以便创建并显示 MainWindow.遵循 MVVM Light ViewModelLocator 模式,MainWindow 尝试从 App.xaml 中定义的静态 ViewModelLocator 实例解析它的数据上下文:

In App.xaml I set the StartupUri="MainWindow.xaml" so the MainWindow is created and shown. Following the MVVM Light ViewModelLocator pattern the MainWindow tries to resolve it's data context from the static ViewModelLocator instance defined in App.xaml:

<Application.Resources>
    <ViewModels:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</Application.Resources>

ViewModelLocator 实例被创建,并在构造函数中初始化另一个 StandardKernel(现在还有其他类型的内核吗?)将用于解析视图模型绑定.提供了一个 MainWindow 的视图模型来满足窗口的请求,整个应用程序继续运行.

ViewModelLocator instance is created and in the constructor it initializes another StandardKernel (is there any other type of kernel I shout use at this point?) that will be used to resolve the view model bindings. A MainWindow's view model is provided to satisfy the windows's request and the whole application continues to operate.

一个非常重要的含义是,heartbeatManger 实例绑定到单调作用域中的接口定义,因此需要它作为构造函数参数的视图模型可以解析并获取已创建的实例.如果视图模型和 heartbeatManager 加载到不同的内核中,这种依赖解析是否有效?如果没有,我该如何解决这个问题?

A very important implication, is that the hearbeatManger instance is bound to an interface definition in a singletone scope, so that view models that require it as a constructor parameter can resolve and get the already created instance. Will such dependency resolution work, if the view model and the heartbeatManager are loaded in a different kernels? If not, how can I solve this problem?

上述计划的场景在架构方面是否有任何好的表现,是否可以在代码中实现,或者我在思考架构时是否犯了错误?

Is the above planned scenario any good architecture-wise, is it implementable in code, or have I made a mistake when I was thinking through the architecture?

推荐答案

...此时会创建一个 heartbeatManager 实例,只留下挂在内存中...

...At this point a heartbeatManager instance is created just left to hang in the memory...

如果它已在您的内核中注册,则不会导致它挂在内存中的任何魔法 - 只要内核/容器存在,它就会一直存在.该容器可能应该是您的 App 类的成员,因为只要(编译器生成的)Main 方法存在,您的应用类就会一直存在,并且无论如何您都应该在应用关闭时处理它.

If it is registered with your kernel, it isn't any magic that causes it to hang in memory - it will stick around as long as the kernel/container does. That container should probably be a member of your App class, since your app class sticks around as long as the (compiler generated) Main method does, and you should dispose it on app shutdown anyhow.

...遵循 MVVM Light ViewModelLocator 模式,MainWindow 尝试从 App.xaml 中定义的静态 ViewModelLocator 实例解析其数据上下文...

...Following the MVVM Light ViewModelLocator pattern the MainWindow tries to resolve it's data context from the static ViewModelLocator instance defined in App.xaml...

我不确定这会与 NInject 很好地混合.它是一个依赖注入容器,而不是一个服务定位器容器(即使它在幕后使用了一个).NInject(和类似框架)的主要目的是避免要求您使用服务定位器模式,而是注入您的所有依赖项.

I'm not sure this will mix well with NInject. It is a Dependency Injection container, not a Service Locator container (even though it uses one under the hood). The main purpose of NInject (and similar frameworks) is to avoid requiring you to use the Service Locator pattern, and instead to inject all your dependencies.

...ViewModelLocator 实例被创建并在构造函数中初始化另一个 StandardKernel...

...ViewModelLocator instance is created and in the constructor it initializes another StandardKernel...

除非您的场景非常复杂(它确实不适合此应用),否则我建议坚持使用单个 NInject 内核.

Unless your scenario is quite complicated (which it really isn't for this app), then I suggest sticking to a single NInject kernel.

建议的解决方案

视图模型定位器类本身除了让您拆分初始化逻辑并根据您是处于设计模式还是运行时模式进行选择性初始化之外,并没有为您做太多事情.您可以使用 NInject 模块(其中 您在评论中链接的视图模型定位器文章已经使用).

The view model locator class itself doesn't do much for you other than let you split up your initialization logic, and do selective initialization depending on whether you're in design mode or runtime mode. You could achieve the same with NInject modules (which the view model locator article you linked in comments already uses).

我建议您不要使用视图模型定位器,而是在模块类中指定所有组件,并在 Load<中执行 IsInDesignMode 逻辑/code> 方法.

I suggest that instead of using a view model locator, you specify all your components in your module class, and do the IsInDesignMode logic in the Load method.

这对于 MVVM 来说可能有点棘手,因为视图模型需要绑定到一个您没有创建的 object 属性,并且不能注释.

This might be a bit tricky with MVVM though, since the view model needs to bind to an object property you didn't create, and can't annotate.

有几种方法可以直接在 NInject 中解决这个问题,而不是求助于服务定位器:

There are a few ways to solve this directly in NInject, instead of resorting to a service locator:

  • 在您的视图上使用依赖注入,使其需要一个视图模型.
    如果使用构造函数注入不起作用(如您在评论中提到的),请改用属性注入,并使用将其 setter 转发到 DataContext 的自定义属性.
  • 使用 NInject 工厂方法 (ToMethod) 来创建您的视图,并将视图模型绑定到每个工厂方法中的视图.
    例如.Bind().ToMethod(context => new MainView() { DataContext = new MainViewModel() });
  • Use Dependency Injection on your view, making it require a view model.
    If this doesn't work using constructor injection (as you mentioned in your comments), use property injection instead, with a custom property that forwards its setter to DataContext.
  • Use NInject factory methods (ToMethod) to create your view, and bind the view model to the view in each factory method.
    E.g. Bind<MainView>().ToMethod(context => new MainView() { DataContext = new MainViewModel() });

如果可以,我会选择第二种方法.这样您的视图就不必处理数据绑定,也不必背后有任何代码.它也很容易理解,可以让您避免在内核中同时注册视图和视图模型,并且可以避免为您的视图模型制作任何类型的众所周知的接口.

If you can, I'd go for the second method. This way your view doesn't have to handle data binding, and doesn't have to have any code behind. It is also simple to understand, would let you avoid having to register both views and view models in the kernel, and would let you avoid making any sort of well known interface for your view model.

这篇关于MVVM Light,Ninject 主要用于通知区域应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆