architecture - MVVM Light,Ninject 在大多数通知区域应用程序中

标签 architecture mvvm ninject mvvm-light

我需要应用程序架构建议。

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

应用程序有几个窗口,在启动时显示,然后关闭,仅保留通知区域图标。

通知区域图标纯粹是我从this获得的WPF控件代码项目示例。

由于即使所有窗口都关闭,我的应用程序也应保持运行,因此我设置了

ShutdownMode="OnExplicitShutdown"

在 App.xaml 中。

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

在 App.xaml.cs 中,我创建一个 Ninject StandardKernel,我们将其命名为 appKernel 并将 Ninject 模块加载到其中。首先,Ninject 只解析一个接口(interface) - 一个 heartbeatManager 实例。 HeartbeatManager 是我计划用于以下用途的类:

a) 将我的 NotifyIcon 实例托管为字段变量,以便只要类实例在内存中,它就保持可见。

b) 关闭事件的实现,我将在 app.xaml.cs 中订阅该事件,并在心跳类请求时显式关闭应用程序。

此时,一个 heartbeatManager 实例已创建,并卡在内存中。

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

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

ViewModelLocator 实例已创建,并在构造函数中初始化另一个 StandardKernel(此时我是否需要使用任何其他类型的内核?),该实例将用于解析 View 模型绑定(bind)。提供MainWindow的 View 模型来满足窗口的请求,并且整个应用程序继续运行。

一个非常重要的含义是,hearbeatManger 实例绑定(bind)到单调范围中的接口(interface)定义,以便需要它作为构造函数参数的 View 模型可以解析并获取已创建的实例。如果 View 模型和 heartbeatManager 加载到不同的内核中,这种依赖关系解析是否有效?如果没有,我该如何解决这个问题?

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

最佳答案

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

如果它已在您的内核中注册,则不会有任何魔法导致它挂起在内存中 - 只要内核/容器存在,它就会保留在内存中。该容器可能应该是您的 App 类的成员,因为只要(编译器生成) Main ,您的应用程序类就会一直存在。方法确实如此,无论如何您都应该在应用程序关闭时将其处置。

...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 很好地混合。它是一个依赖注入(inject)容器,而不是服务定位器容器(尽管它在底层使用了一个容器)。 NInject(和类似框架)的主要目的是避免要求您使用服务定位器模式,而是注入(inject)所有依赖项。

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

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

建议的解决方案

View 模型定位器类本身并没有为您做太多事情,只是让您分割初始化逻辑,并根据您处于设计模式还是运行时模式进行选择性初始化。您可以使用 NInject 模块( the view model locator article you linked in comments already uses )实现相同的目的。

我建议您不要使用 View 模型定位器,而是在模块类中指定所有组件,然后执行 IsInDesignMode Load中的逻辑方法。

这对于 MVVM 来说可能有点棘手,因为 View 模型需要绑定(bind)到 object属性不是您创建的,并且无法注释。

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

  • 在 View 上使用依赖注入(inject),使其需要 View 模型。
    如果使用构造函数注入(inject)不起作用(正如您在评论中提到的),请改用属性注入(inject),并使用将其 setter 转发到 DataContext 的自定义属性。 .
  • 使用NInject factory methods ( ToMethod ) 创建 View ,并将 View 模型绑定(bind)到每个工厂方法中的 View 。
    例如。 Bind<MainView>().ToMethod(context => new MainView() { DataContext = new MainViewModel() });

如果可以的话,我会选择第二种方法。这样您的 View 就不必处理数据绑定(bind),也不必有任何后面的代码。它也很容易理解,可以让您避免在内核中注册 View 和 View 模型,并且可以让您避免为 View 模型创建任何类型的众所周知的接口(interface)。

关于architecture - MVVM Light,Ninject 在大多数通知区域应用程序中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7781170/

相关文章:

architecture - 谁应该学习 "old"系统?

wpf - ViewModel 每个 View 还是每个模型?

c# - ViewModel 与 Model 有不同的字段吗?

c# - 如何使用 lambda 指定构造函数参数?

c# - MVC/n注入(inject) : Implementing My Own ApplicationUserManager

c# - 在 COM 中使用托管 (.NET) 组件是否有成本?

design-patterns - 需要帮助建模图像和一些使用它们的类之间的关系

linux - MMU 实现

wpf - 是否保证在调用 OnStartup() 时所有 WPF 绑定(bind)都将起作用?

dependency-injection - 如何使用 Ninject 实例化 MEF 导出的对象?