WPF, MVVM IoC: альтернатива шаблону локатора службы.Нужна зависимость в Просмотреть код позади - PullRequest
0 голосов
/ 25 апреля 2018

Следуя нескольким руководствам, у меня есть макет приложения, как показано ниже, с использованием WPF .NET 4.7.1 и MVVM-Light.Кстати, я новичок в WPF.

App.xaml:

<Application x:Class="My.App" 
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
         xmlns:viewmodel="clr-namespace:My.ViewModel" 
         StartupUri="View\MainView.xaml">
<Application.Resources>
    <ResourceDictionary>
        <viewmodel:ViewModelLocator x:Key="Locator" />
    </ResourceDictionary>
</Application.Resources>

, который регистрирует класс ViewModelLocator в качестве ресурсов и устанавливает для запуска WPF значение"View / MainView.xaml".

MainView.xaml:

<Window x:Class="My.View.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Window.DataContext>
    <Binding  Path="Main" Source="{StaticResource Locator}"/>
</Window.DataContext>

Где ViewModelLocator используется как шаблон локатора службы.Здесь установка DataContext для моего "MainViewModel" (не показано).Как бы мне это не нравилось, я могу жить с этим в контексте WPF XAML.Однако теперь выясняется, что мне нужна зависимость в программном обеспечении представления (а не в ViewModel).

MainView.cs:

public partial class MainView : INotifyPropertyChanged
{
   public MainView()
   {
       // Need to access dependency here.          
   }
}

Теперь я могу просто вызвать ViewModelLocatorнепосредственно в этом конструкторе и получить это разрешение из моего контейнера IoC - но тогда я полностью согласился и принял этот шаблон.

Я бы предпочел, чтобы зависимость вставлялась в ctor, конечно, и если это таквозможно, я бы также полностью оставил ViewModelLocator и вставил бы здесь ViewModel.

Итак, вопрос в том, существует ли какой-нибудь стандартный способ указания приложению WPF использовать мой контейнер?И если да, то целесообразно ли идти по этому пути и не использовать функцию ViewModelLocator?

1 Ответ

0 голосов
/ 25 апреля 2018

Вам абсолютно не нужно использовать ViewModelLocator (примечание: в последнее время шаблон локатора служб получил свою долю критики как анти-шаблон, но я позволю вам составить собственное мнение).MVVM Light и другие библиотеки в основном предоставляют вам доступ к набору инструментов.Вам не нужно использовать все инструменты, и вы должны использовать только то, что необходимо для вашего конкретного домена.

За пределами ViewModelLocator есть два шаблона, известные как ViewModel First и * 1006.* у обоих есть свои плюсы и минусы.Тем не менее, оба предоставляют средство для разделения вашего кода, что означает, что переключение не составит труда.

Что касается создания приложения с использованием MVVM Light без локатора служб, моя реализация метода View First выглядит примерно так.

Я слышал мнение, что ViewModel First предпочтительнее, однако я считаю, что View First более упрощен для разработки через тестирование (TDD)

App.xaml.cs (код приложения ниже))

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        var bootStrapper = new BootStrapper();
        //Container Builder
        var container = bootStrapper.BootStrap();
        var mainWindow = container.Resolve<MainWindow>();
        mainWindow.Show();
    }
}

BootStrapper.cs (в данном случае я использую AutoFac, но вы можете легко заменить.)

public class BootStrapper
{
    public IContainer BootStrap()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<MainWindow>().AsSelf();
        builder.RegisterType<MainWindowViewModel>().AsSelf();
        return builder.Build();
    }
}

MainWindowViewModel.cs

//I rolled my own ViewModelBase, but you can use MVVM Light's ViewModelBase
public class MainWindowViewModel : ViewModelBase
{
    public string DisplayProgram
    {
        get { return _displayProgram; }
        //MVVM Light's ViewModelBase uses RaisePropertyChanged();
        set { _displayProgram = value; OnPropertyChanged(); }
    }

    public void Initialize()
    {
        //Called from view code behind.
    }
}

MainWindow.xaml.cs (код основного окна)

//When MainWindow.Show()..
public partial class MainWindow : Window
{
    private readonly MainWindowViewModel _viewModel;
    //Container resolves dependencies
    public MainWindow(MainWindowViewModel viewModel)
    {
        //Let base Window class do its thing.
        InitializeComponent();

        //Handle loaded event
        Loaded += MainWindowLoaded;

        //Hold on to the MainWindowViewModel, and set it as the windows DataContext            
        _viewModel = viewModel;
        DataContext = _viewModel;
    }

    private void MainWindowLoaded(object sender, RoutedEventArgs e)
    {
        _viewModel.Initialize();
    }
}
...