如何将依赖项注入到 WPF 中的用户控件

问题描述 投票:0回答:6

在 WPF 中透明地将依赖项(使用 IOC 容器)注入到用户控件的最佳方法是什么?

我假设用户控件是窗口或其他用户控件的 XAML 的一部分。 我也认为父母(无论是谁)不应该为此负责。从父级手动注入依赖项的解决方案对我来说看起来不够干净。我想避免显式管理组件的依赖关系,因为它违背了 IOC 的理念。

创建逻辑树时是否会引发任何事件,以便我可以拦截它并注入我的依赖项?

编辑: 我所说的依赖关系还指 ViewModel、Controller、Presenter(无论使用什么模式)

谢谢, 安德烈

.net wpf wpf-controls
6个回答
8
投票

处理 WPF 中的依赖关系的最佳方法是遵循 MVVM 模式

简而言之,您不会将依赖项直接注入到用户控件(视图)中,而是注入到它们的DataContext(ViewModel)中。


1
投票

FrameworkElement 有一个 Initialized 事件,您可以连接该事件并注入依赖项。您应该测试它对于您的场景来说是否足够早。


1
投票

我这样做的方法是拥有一个整体应用程序类,它将依赖项注入到您的视图模型类中(假设您使用 MVVM 设计模式?) - 使用像 Unity 这样的 DI 容器。请参阅 WPF 应用程序框架 (https://github.com/jbe2277/waf),其中包含您所描述的此类场景的示例。


0
投票

如今有了内置 DI 支持,很容易实现这一点。

  1. 在您的应用程序中设置服务提供商:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public partial class App
    {
        private static readonly IHost _host = Host
            .CreateDefaultBuilder()
            .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)!); })
            .ConfigureServices((context, services) =>
            {
                // register your services
                services.AddScoped<ISomething, Something>();
                services.AddScoped<MyUserControlViewModel>();
            })
            .Build();

        /// <summary>
        /// Gets registered service.
        /// </summary>
        /// <typeparam name="T">Type of the service to get.</typeparam>
        /// <returns>Instance of the service or <see langword="null"/>.</returns>
        public static T GetService<T>()
            where T : class
        {
            var service = _host.Services.GetService(typeof(T)) as T;
            return service!;
        }

        /// <summary>
        /// Occurs when the application is loading.
        /// </summary>
        private void OnStartup(object sender, StartupEventArgs e)
        {
            _host.Start();
        }

        /// <summary>
        /// Occurs when the application is closing.
        /// </summary>
        private async void OnExit(object sender, ExitEventArgs e)
        {
            await _host.StopAsync();

            _host.Dispose();
        }
    }
  1. 在您的用户控制中

请注意,您无法将VM注入到您的用户控件中,因为当您在页面中使用用户控件时将调用无参数构造函数,因此只需从服务提供商处获取它

public partial class MyUserControl : UserControl
{
    public MyUserControlViewModel ViewModel { get; }

    public OrgSwitcherControl()
    {        
        ViewModel = App.GetService<MyUserControlViewModel>();
        DataContext = this;
        InitializeComponent();
    }
}

使用页面,您可以直接注入虚拟机(当然您也必须在服务集合中注册xaml页面)。


-1
投票

我也在与这个思维障碍作斗争:

我也认为父母(无论是谁) 不应该为此负责。

那么谁会呢? IoC 的要点是其他东西(父级、视图模型、...)定义了依赖关系。


-3
投票

解决该问题的可能方法之一是采用“ViewModel First”方法并使用约定优于配置。

© www.soinside.com 2019 - 2024. All rights reserved.