Возникают проблемы с решением, как подключить UserControl с MVVM - PullRequest
1 голос
/ 13 июля 2010

Я старался изо всех сил стараться оставаться верным разделению, рекомендованному паттерном MVVM.Одна вещь, которую я не могу понять, как правильно делать, связана с инициализацией моих UserControls.

Мой самый последний пример этого связан с библиотекой, которую я написал для общения с некоторыми низкоуровневыми аппаратными средствами.Эта сборка имеет UserControl, который я могу просто вставить в любой графический интерфейс, который использует это оборудование.Все, что необходимо для его работы, - это установить ссылку на объект, который имеет доступ к низкоуровневым методам.

Однако в этом и заключается моя проблема - в настоящее время UserControl добавляется в GUI черезXAML, где я определяю пространство имен, а затем добавляю UserControl в мое окно.Конечно, на данный момент я не контролирую его создание, поэтому вызывается конструктор по умолчанию.Единственный способ установить необходимую ссылку для управления оборудованием - это вызвать метод в UC.ViewModel может вызвать метод в модели, например, GetController(), а затем вызвать метод в UserControl, чтобы установить ссылку соответственно.GUI может передавать ссылку на UserControl в ViewModel, когда указанный GUI создает ViewModel, но это нарушает MVVM, потому что ViewModel не должен ничего знать об этом элементе управления.

Другой способ, которым я мог бы иметь дело с этим, состоит в том, чтобы не создайте UserControl в XAML, но вместо этого сделайте все это из-за кода.После того, как ViewModel инициализируется и получает инициализированный UserControl (то есть тот, который имеет низкоуровневую ссылку на объект), он может установить Content of Window в UserControl.Однако это также нарушает MVVM - есть ли способ привязать содержимое окна, TabControl или любого другого элемента к UserControl?

Я хотел бы услышать, сталкивался ли кто-нибудь с этимдо того, и если они подошли к нему первым или вторым способом, который я изложил здесь, или если они выбрали совершенно другой подход.Если то, что я спросил здесь, неясно, пожалуйста, дайте мне знать, и я сделаю все возможное, чтобы обновить его с помощью дополнительной информации, диаграмм и т. Д.

ОБНОВЛЕНИЕ

Спасибо за ответы, ребята, но я не очень хорошо объяснил проблему.Я уже использую RelayCommands в ViewModel UserControl для обработки всех вызовов аппаратного уровня (Model), когда пользователь щелкает элемент управления в самом UserControl.Моя проблема связана с первоначальной передачей ссылки на UserControl, чтобы он мог общаться с аппаратным уровнем.

Если я создаю UserControl непосредственно в XAML, я не могу передать ему эту ссылку через конструктор, потому что я могу использовать только конструктор по умолчанию.Решение, которое у меня сейчас есть, не выглядит MVVM-совместимым - мне пришлось назвать UserControl в XAML, а затем в коде (т. Е. Для View) я должен вызвать метод, который я добавил вбыть в состоянии установить эту ссылку.Например, у меня есть GUI UserControl, который содержит диагностический UserControl для моего оборудования:

partial class GUI : UserControl
{
    private MainViewModel ViewModel { get; set; }

    public GUI( Model.MainModel model)
    {
        InitializeComponent();
        ViewModel = new MainViewModel( model, this.Dispatcher);
        ViewModel.Initialize();
        this.DataContext = ViewModel;
        diagnostics_toolbar.SetViewModel( ViewModel);
        user_control_in_xaml.SetHardwareConnection( model.Connection);
    }
}

, где внешний класс является основным GUI UserControl, а user_control_in_xaml - это UserControl, который я должен был назвать в GUI.XAML.

Глядя на это снова, я понимаю, что, вероятно, можно использовать подход именования, потому что все это используется в самом представлении.Я не уверен в передаче информации о модели в user_control_in_xaml, потому что это означает, что дизайнер должен знать, чтобы вызвать этот метод, если он хочет переделать графический интерфейс - я думал, что идея заключалась в том, чтобы скрыть детали модели из видаслой, но я не уверен, как еще это сделать.

Вы также заметите, что основной GUI передается Model в конструкторе, что я считаю, также плохо.Возможно, мне нужно пересмотреть дизайн, чтобы увидеть, возможно ли, чтобы ViewModel создал Модель, что я обычно и делаю, но в этом случае я не могу вспомнить, почему мне пришлось создавать ее вне GUI.

Ответы [ 4 ]

0 голосов
/ 15 июля 2010

Если вы установите DataContext для Window или UserControl, содержащего это UserControl, для модели основного вида , пользовательский элемент управления может вызвать SetHardwareConnection() для себя в его Loaded событие (или DataContextChanged обработчик события).

Если это невозможно, потому что вы говорите, что UserControl является «фиксированным», вы должны получить его или свернуть в другой UserControl, который будет служить «адаптером» MVVM.


(Для того чтобы связать окно: вы можете сделать MainViewModel синглтоном со свойством static Instance и использовать DataContext="{x:Static MyClass.Instance}". Хороший способ ускорить процесс)


Примечание; это основано на моем понимании того, что MVVM работает из-за привязок. Я всегда связываю элемент управления с ViewModel, а не передаю ViewModel в качестве параметра.

Надеюсь, это поможет!

0 голосов
/ 15 июля 2010

, если ваш вопрос: Как мне показать мою viewmodel в представлении? тогда мое решение всегда использует подход viewmodelfirst и шаблоны данных.

так что все, что вам нужно сделать, это подключить вашу модель представления через привязку к contentcontrol.content в xaml. wpf + datatemplates выполнят эту работу и создадут пользовательский контроль для вашей модели представления.

0 голосов
/ 15 июля 2010

Вы правы, ViewModel не должна знать о чем-либо в View - или даже о том, что существует такая вещь, как View, поэтому MVVM ищет и модульное тестирование, так как виртуальной машине может быть все равно, если это так. подвергая себя представлению или тестовой среде.

Насколько я понимаю, вам, возможно, придется немного поменяться местами. Чтобы придерживаться шаблона MVVM, вы можете представить ICommand, ICommand вызывает внутренний метод VM, который отправляет и получает данные (или что-то еще) из модели, этот метод затем обновляет свойство ObservableCollection объектов данных, чтобы View связывался с , Так, например, в вашей виртуальной машине вы можете иметь

private ICommand _getDataCommand;
public ICommand GetDataCommand
    {
        get
        {
            if (this._getDataCommand == null)
            {
                this._getDataCommand = new RelayCommand(param => this.GetMyData(), param => true);
            }

            return this._getDataCommand;
        }
    }


private void GetMyData{
//go and get data from Model and add to the MyControls collection
}

 private ObservableCollection<MyUserControls> _uc; 
 public ObservableCollection<MyUserControls> MyControls
            {
                get
                {
                    if (this._uc == null)
                    {
                        this._uc = new ObservableCollection<MyUserControls>();
                    }
                    return this._uc;
                }
            }

Ознакомиться с RelayCommand Статья Джоша Смита по MSDN .

В представлении вы можете либо вызвать ICommand в статическом конструкторе вашего UC - я полагаю, вам нужно добавить событие в вашем классе для этого - либо вызвать ICommand из какого-либо события click на вашем UC - возможно, просто есть кнопка «загрузить» в окне WPF. И установите привязку данных вашего UC в качестве видимой наблюдаемой коллекции виртуальной машины.

Если вы вообще не можете изменить свой UC, вы можете извлечь из него новый класс и переопределить определенное поведение.

Надеюсь, что это хоть немного поможет, как я уже сказал, взгляните на статью Джоша Смита, посвященную MVVM, так как он блестяще освещает в ней вопросы связывания и ICommand.

0 голосов
/ 14 июля 2010

Я новичок в MVVM, но вот возможное решение:

Создайте свойство в вашей виртуальной машине, относящееся к типу объекта (которое управляет оборудованием), и привяжите его к присоединенному свойству в UserControl. Затем вы можете установить свойство в вашей виртуальной машине, используя внедрение зависимостей, так что оно будет установлено при создании виртуальной машины. На мой взгляд, класс, взаимодействующий с аппаратным обеспечением (контроллером оборудования), является сервисом. Сервис может быть внедрен в вашу модель представления и привязан к вашему UserControl. Я не уверен, что это лучший способ сделать это и достаточно ли он строг ко всем принципам MVVM, но кажется возможным решением.

...