是否可以实现不是 WPF 模块的模块(标准 class 库,无屏幕)?

Is it possible to implement a module that is not a WPF module (a standard class library, no screens)?

我正在 .Net Core 5.0 中使用 Prism 开发模块化 WPF 应用程序(使用 MVVM、DryIoc),我想要一个 不是 WPF 模块的模块,即,具有可被任何其他模块使用的功能的模块。 我不想要任何项目参考,因为我想保持模块的松耦合思想。 我的第一个问题是:它在概念上是否正确?还是模块必须有屏幕?我想应该没问题吧。

第二个(对我而言)更重要的是,创建实例的最佳方式是什么?

这是项目(我知道我应该查看这个项目中的名称):

HotfixSearcher 是主要的 class,我需要对其进行实例化。例如在这个class中,我订阅了一些事件。 这是实现 IModule 接口的 class(模块 class):

namespace SearchHotfix.Library
{
    public class HotfixSearcherModule : IModule
    {
        public HotfixSearcherModule()
        {
        }

        public void OnInitialized(IContainerProvider containerProvider)
        {
            //Create Searcher instance
            var searcher = containerProvider.Resolve<IHotfixSearcher>();
        }

        public void RegisterTypes(IContainerRegistry containerRegistry)
        {

            containerRegistry.RegisterSingleton<IHotfixSearcher, HotfixSearcher>();
            
        }
    }
}

这是我发现 class 实例化的唯一方法,但我对创建未使用的实例不是百分百满意,我认为它没有多大意义。 对于有屏幕的模块,实例是在使用 RequestNavigate 方法导航到它们时创建的:

_regionManager.RequestNavigate(RegionNames.ContentRegion, "ContentView");

但是因为这只是一个没有屏幕的库,我找不到任何其他方法来实例化它。

根据 Prism 文档,订阅一个事件应该足够了,但我尝试在我的主 class HotfixSearcher 中这样做,但它不起作用(构造函数或事件处理程序上的断点我订阅的事件从未被击中)。

当我这样做时,相反,创建了实例,我遇到了构造函数断点,显然实例订阅了事件,因为它是在构造函数中完成的。

总而言之,有没有办法摆脱这种情况var searcher = containerProvider.Resolve<IHotfixSearcher>();以及实现这一目标的更好方法?

提前致谢!

Or is it mandatory that a module has a screen?

不,当然不是,模块与视图或视图模型无关。它们只是容器的一组注册。

what would be the best way to create the instance?

让容器来完成工作。通常,您(至少)有一个程序集只包含 public interfaces(和关联的 enums),但没有模块。您从模块中引用它,并使用模块的 Initialize 方法注册模块对相关接口的实现。然后一些其他模块(或主应用程序)可以有 类 获取接口作为构造函数参数,并且容器将解析(即创建)在模块中注册的具体类型,尽管它们是 internal甚至 private 并且在模块外完全未知。

如果您不想牺牲强类型,这就是松耦合。

is there a way to get rid of that var searcher = containerProvider.Resolve<IHotfixSearcher>(); and a better way to achieve this?

你可以跳过 var searcher = 部分 :-) 但是如果 HotfixSearcher 从来没有被注入到任何地方,除非你自己做,否则它不会被创建。 OnInitialized 是一个完美的地方,因为它在所有模块都有机会 RegisterTypes 之后运行,所以应该注册所有依赖项。

如果HotfixSearcher不是要注入的,也可以丢IHotfixSearcher直接解析HotfixSearcher

public void OnInitialized(IContainerProvider containerProvider)
{
    containerProvider.Resolve<HotfixSearcher>();
}

I am not a hundred per cent comfortable with creating an instance that is not used, I think it does not make much sense.

它被使用了,我想,虽然不是通过调用它的方法之一。通过向它发送一个事件来使用它。那很好。可以把它想象成 Task.Run - 任务看似孤立存在也很好。