Как использовать ViewModelLocator в пользовательском элементе управления? - PullRequest
0 голосов
/ 10 января 2019

Меня попросили преобразовать отдельное приложение WPF, использующее шаблон MVVM, в пользовательский элемент управления. Это приложение состоит из главного окна и нескольких других окон. Однако при попытке сделать это я получаю несколько ошибок, указывающих на мой класс App.xaml и другие ресурсы, объявленные как конвертеры:

Library project file cannot specify ApplicationDefintion element. The project file contains a property value that is not valid. The name "ViewModelLocator" does not exist in the namespace "clr-namespace:MapperX.ViewModels".

Похоже, что ошибки вращаются вокруг моего ViewModelLocator.

В настоящее время структура каталогов проекта настроена так:

Верхний уровень -> папка ViewModels -> ViewModelLocator

App.xaml настроен так:

<Application x:Class="MapperX.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MapperX"
             xmlns:vm="clr-namespace:MapperX.ViewModels"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <vm:ViewModelLocator x:Key="ViewModelLocator" />
    </Application.Resources>
</Application>

А вот фрагмент класса ViewModelLocator:

namespace MapperX.ViewModels
{
    /// <summary>
    /// This class instantiates all the viewmodels
    /// </summary>
    public class ViewModelLocator
    {
        WpfMap map = new WpfMap();

        private MainViewModel _mainViewModel;
        public MainViewModel MainViewModel
        {
            get
            {
                if (_mainViewModel == null)
                {
                    _mainViewModel = new MainViewModel(map)
                }
                return _mainViewModel;
            }
        }

        private LayersViewModel _layersViewModel;
        public LayersViewModel LayersViewModel
        {
            get
            {
                if (_layersViewModel == null)
                {
                    _layersViewModel = new LayersViewModel(map)
                }
                return _layersViewModel;
            }
        }
    }
}

И затем я установил DataContext для представлений .xaml следующим образом: DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}"

Как правильно по-прежнему иметь возможность использовать ViewModelLocator без App.xaml ??

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Вместо того, чтобы полагаться на ресурс, вы можете создать вложенное свойство для установки DataContext представлений в вашей управляющей библиотеке:

namespace ControlsAndResources
{
    public class View
    {
        private static readonly ViewModelLocator s_viewModelLocator = new ViewModelLocator();

        public static readonly DependencyProperty ViewModelProperty = DependencyProperty.RegisterAttached("ViewModel", typeof(string), 
            typeof(ViewModelLocator), new PropertyMetadata(new PropertyChangedCallback(OnChanged)));

        public static void SetViewModel(UserControl view, string value) => view.SetValue(ViewModelProperty, value);

        public static string GetViewModel(UserControl view) => (string)view.GetValue(ViewModelProperty);

        private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UserControl view = (UserControl)d;
            string viewModel = e.NewValue as string;
            switch (viewModel)
            {
                case "MainViewModel":
                    view.DataContext = s_viewModelLocator.MainViewModel;
                    break;
                case "LayersViewModel":
                    view.DataContext = s_viewModelLocator.LayersViewModel;
                    break;
                default:
                    view.DataContext = null;
                    break;
            }
        }
    }
}

Использование:

<UserControl xmlns:local="clr-namespace:ControlsAndResources" ... 
             local:View.ViewModel="MainViewModel">
0 голосов
/ 10 января 2019

Почему бы не поставить ViewModelLocator на верхний уровень UserControl?

<UserControl.Resources>
   <vm:ViewModelLocator x:Key="ViewModelLocator" />
</UserControl.Resources>
...