在MVVM WPF应用程序中实现模态对话框时,将ServiceLocator替换为DependencyInjection

本文关键字:ServiceLocator 替换 DependencyInjection 对话框 WPF MVVM 应用程序 模态 实现 | 更新日期: 2023-09-27 18:18:18

我正在编写我的第一个WPF应用程序,我想请您帮助解决我遇到的一个问题。

我试图遵循MVVM模式,我来到一个点,我需要实现模态对话框。我在谷歌上搜索了一段时间,然后找到了一个解决方案。然而,在重构时,我遇到了一个难题,即使用DI(构造函数注入)来替代服务定位器。

我将引用这些:http://pastebin.com/S6xNjtWW.

我真的很喜欢Roboblob的方法:

首先:他创建了一个模态对话框(界面)的抽象。我将接口命名为IModalDialog,它看起来是这样的:

public interface IModalDialog
{
    bool? DialogResult { get; set; }
    object DataContext { get; set; }
    void Show();
    bool? ShowDialog();
    void Close();        
    event EventHandler Closed;
}

Second:模态对话框服务的抽象:

public interface IModalDialogService
{       
    void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel, Action<TDialogViewModel> onDialogClose) where TDialogViewModel : class;        
    void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel) where TDialogViewModel : class;        
}

第三: IModalDialogService的具体实现:

    public class ModalDialogService : IModalDialogService
    {
    public void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel, Action<TDialogViewModel> onDialogClose) where TDialogViewModel : class
    {
        // set datacontext
        if (viewModel != null)
        {
            view.DataContext = viewModel;
        }
        ((System.Windows.Window)view).Owner = System.Windows.Application.Current.MainWindow;
        // register 
        if (onDialogClose != null)
        {
            view.Closed += (sender, e) => onDialogClose(viewModel);
        }
        view.ShowDialog();
    }

    public void ShowDialog<TDialogViewModel>(IModalDialog view, TDialogViewModel viewModel) where TDialogViewModel : class
    {
        this.ShowDialog(view, viewModel, null);
    }

第四个:有更多的IModalDialog实现。每个都是实现IModalDialog的窗口派生类。


在我提出问题(描述问题)之前,我需要先解释一下:

假设我有更多的服务,比如IMessageBoxService。然后我需要在MainWindowViewModel的构造函数中声明这些依赖关系:

public MainWindowViewModel(IModalDialogService a,                               
                           IMessageBoxService b,
                           ...)

,这样我就可以注入它们(通过手动或使用IOC容器,如Unity等)。

为了能够使用模态对话框服务,还缺少一个难题——基于某个键解析IModalDialog的具体实现的能力。

Roboblob在他的文章中使用ServiceLocator模式解决了这最后一块难题:

public class Bootstrapper
{
public static void InitializeIoc()
  {
    SimpleServiceLocator.SetServiceLocatorProvider(new UnityServiceLocator());
    SimpleServiceLocator.Instance.Register<IModalDialogService, ModalDialogService>();
    SimpleServiceLocator.Instance.Register<IMessageBoxService, MessageBoxService>();
  ...    
    SimpleServiceLocator.Instance.Register<IModalWindow, EditUserModalDialogView>(Constants.EditUserModalDialog);
  }

}

所以他在MainWindowViewModel中简单地调用静态类Get并解析基于键的IModalDialog窗口的具体实现。

甚至Josh Smith在他的文章中也使用了类似的方法,但在评论中他说(DI -构造函数注入)是一个有效的选项。

引用的StackOverflow答案也描述了一个类似的可以修改和使用的WindowViewLoaderService。


所以问题是——用依赖注入取代ServiceLocator(它解决了IModalDialog的具体实现)的最好方法是什么?

我的思路是:

  1. 一种可能性是(由于项目不是很大/只由我开发)只是创建一个新的服务(例如称为IModalDialogResolver),它将创建并返回IModalDialog的具体实现的新实例。

  2. 然后我想到了IOC容器(Unity)。我没有这方面的经验。我想也许我不必写IModalDialogResolver,因为我可以用Unity容器注册IModalDialog的不同实现=>但是我如何使用MainWindowViewModel中的容器?我不能将引用传递给构造函数,因为那将是退回到ServiceLocation。
    然后我想也许我可以在bootstrapper中使用一个统一容器来解析所有的服务,并在IModalDialogResolver内部使用另一个。但是我不知道对于Unity的推荐使用来说这是否是一个好主意。我知道的太少了,无法对此作出判断。但是有些东西告诉我,这不是一个好主意,因为它创建了一个隐藏的依赖于容器+,如果容器是一个单例,这将相当于只是传递引用到构造函数。

为了更好地解释我的心理障碍:我想使用IOC容器(例如Unity)来构造和注入接口。但是我不能把IModalDialog作为参数放在构造函数中。所以我可能真的需要把它包装在一个服务中,然后自己实现——但是(假设Unity可以开箱就能做到这一点),如果我不能使用它,那么把Unity放在那里就没有意义了。

我知道一种替代方法是将这个服务放入基类中,但是为了讨论的缘故,我们不考虑这个。我真的很想学习使用依赖注入来解决这个问题的正确方法。

在MVVM WPF应用程序中实现模态对话框时,将ServiceLocator替换为DependencyInjection

在您的组合根目录中访问IoC容器是完全有效的。

实际上,这应该是唯一访问您的容器的位置。

在你给出的例子中,这就是所有正在发生的事情——具体的实现被注册在组合根目录下的容器中。

因此,要回答您的问题,您不需要在这里替换使用服务定位器模式,因为它只是在组合根中注册类型的一种机制,这是完全有效的。

如果你希望基于一些运行时条件实例化模态对话框服务,那么你应该注入一个模型对话框服务工厂(同样是一个在容器中注册实现的抽象),然后工厂将有一个方法来创建模型对话框服务,这个工厂方法将接受所需的运行时参数。

然后,您的工厂可以根据运行时参数适当地新建适当的模型对话框服务。或者,它也可以从容器中解析适当的模型对话框服务,这显然需要工厂具有对容器的引用。

大多数容器支持自动工厂类型,因此您只需要为工厂定义接口,容器将使用约定自动实现工厂。城堡。以Windsor为例,它拥有类型化工厂设施,Unity也有一些类似的设施。