Внедрение зависимостей в.NET Core 3.0 для WPF
Я хорошо знаком с ASP.NET Core и поддержкой внедрения зависимостей из коробки. Контроллеры могут требовать зависимости, добавив параметр в их конструктор. Как получить зависимости в WPF UserControls? Я попытался добавить параметр в конструктор, но это не сработало. Мне нравится концепция МОК, и я бы предпочел перенести ее в WPF.
6 ответов
Недавно я столкнулся с этим требованием к своему проекту и решил его таким образом.
Для внедрения зависимостей в.NET Core 3.0 для WPF. После того, как вы создадите проект WPF core 3 в своем решении, вам необходимо установить / добавить пакеты nuget:
Microsoft.Extensions.DependencyInjection
В моем случае я создал класс, который хочу использовать для ведения журнала, назвал его LogBase, поэтому в вашем классе приложения добавьте следующее, и да, это всего лишь базовый пример:
private readonly ServiceProvider _serviceProvider;
public App()
{
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
_serviceProvider = serviceCollection.BuildServiceProvider();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ILogBase>(new LogBase(new FileInfo($@"C:\temp\log.txt")));
services.AddSingleton<MainWindow>();
}
private void OnStartup(object sender, StartupEventArgs e)
{
var mainWindow = _serviceProvider.GetService<MainWindow>();
mainWindow.Show();
}
В свой App.xaml добавьте Startup="OnStartup", чтобы он выглядел так:
<Application x:Class="VaultDataStore.Wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VaultDataStore.Wpf"
Startup="OnStartup">
<Application.Resources>
</Application.Resources>
</Application>
Итак, в вашем MainWindow.xaml.cs вы вставляете ILogBase в конструктор следующим образом:
private readonly ILogBase _log;
public MainWindow(ILogBase log)
{
_log = log;
...etc.. you can use _log over all in this class
в моем классе LogBase я использую любой регистратор, который мне нравится в моем стиле.
Я добавил все это вместе в репозиторий github.
Между тем меня спросили, как использовать инъекцию в пользовательском элементе управления, я предлагаю это решение, если кто-то извлекает из него пользу. Проверьте это здесь.
Ответ maytham-ɯɐɥʇʎɐɯ для настройки внедрения зависимостей из класса приложения и метода запуска хорош, за исключением того, что я реализую IServiceProvider как свойство
public IServiceProvider ServiceProvider { get; private set; }
Следующий шаг - «как внедрить модели просмотра»?
Мне не нравится внедрение модели представления в конструкторе окна (в коде позади). Мое более чистое решение заключалось в создании поставщика модели представления для использования в xaml. Для этого вы можете реализовать его как MarkupExtension.
public class ViewModelProvider : MarkupExtension
{
#region ctor
public ViewModelProvider()
{
}
public ViewModelProvider(Type viewModelType)
{
ViewModelType = viewModelType;
}
#endregion ctor
#region properties
public Type ViewModelType { get; set; }
#endregion properties
#region methods
public override object ProvideValue(IServiceProvider serviceProvider)
{
return ((App)Application.Current).ServiceProvider.GetService(ViewModelType);
}
#endregion methods
}
Затем в xaml вы можете спросить тип модели просмотра, который вы хотите ViewModelProvider
DataContext="{local:ViewModelProvider local:MainViewModel}"
В WPF вы используете шаблон под названием Model-View-ViewModel (MVVM для краткости). Ваши зависимости внедряются в модель представления (используя те же структуры IoC, которые вы используете в ASP.NET, например, AutoFac), а ваши представления (UserControls) регистрируются в качестве шаблонов данных для ваших моделей представления.
Таким образом, вы структурируете свое приложение вокруг моделей представлений, и представления (которые зависят от моделей представлений) разрешаются так, как если бы модель представления зависела от представления. Представления могут получить доступ к своей модели представления через свойство DataContext. Таким образом, вы можете использовать модель представления в качестве фасада, чтобы внедрить что-либо в ваши виды.
Хороший вопрос, нельзя иметь элементы управления без непараметрического конструктора в xaml. Если вы хотите, вам нужно создать его экземпляр из кода, но xaml не будет вызывать этот конструктор.
Вообще говоря, нет. Вы используете внедрение зависимостей в своих моделях представлений, а затем используете привязку данных для привязки ваших представлений к ним.
Это не значит, что это невозможно сделать. Например, MVVM Light создает класс инжектора, а затем объявляет его экземпляр в App.xaml, что почти совпадает с объявлением глобальной переменной:
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MyMvvmProject.ViewModel" />
</ResourceDictionary>
</Application.Resources>
Окна и пользовательские элементы управления, которые являются частью визуального дерева, могут связываться с ресурсами приложения, поэтому в этой структуре основное окно обычно связывается с моделью представления следующим образом:
<Window x:Class="MyMvvmProject.MainWindow"
...
DataContext="{Binding Source={StaticResource Locator}, Path=Main}">
...где Main
является свойством класса локатора:
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
Это не очень хороший IoC, потому что он помещает все ваши инъекционные препараты в один класс, на практике вы бы разбили его на специализированные фабрики и т. Д. На разных уровнях.
А если серьезно, не делай ничего из этого. Используйте DI на уровне модели представления и используйте свободную привязку данных, чтобы связать ее с вашим представлением. Это позволит вам использовать всю мощь внедрения зависимостей, частично отсоединяя его от слоя, в котором он не нужен, и частично, предоставляя гибкую возможность переконфигурировать ваши зависимости для различных сред, таких как веб, настольное, мобильное и особенно модульное тестирование. где представления не создаются вообще.
(Отказ от ответственности: я еще не использовал.NET Core для WPF, поэтому то, что я здесь представил, может быть немного специфичным для.NET, но общие принципы остаются).
Вы должны использовать код в этом случае. Но подумайте дважды, действительно ли необходимо иметь зависимость в UserControl или любом другом классе, созданном из xaml.