Несколько viewmodel, взаимодействующих друг с другом

Я работаю над проектом Surface WPF, в котором мы пытаемся реализовать шаблон MVVM. В рамках этого проекта мы создаем несколько пользовательских элементов управления, которые мы привязываем к различным моделям представления.

Например, у нас есть элемент управления настройками, в котором есть модель просмотра настроек, и у нас есть основная модель, которая является "общей" моделью представления.

На нашей странице surfacewindows.xaml мы устанавливаем текст данных для основной модели представления, используя локатор модели представления в mvvm-light. Кроме того, в нашем файле surfacewindow.xaml мы добавили наш элемент управления настройками, а в элементе управления мы установили datacontext для модели представления настроек.

Теперь нам нужно, чтобы обе модели представления взаимодействовали друг с другом. В данном случае нам нужно настроить видимость элемента управления настройками. У нас есть свойство в главной модели представления, которое является логическим (IsSettingsControlVisible), которое связано со свойством элементов управления Visibility с помощью конвертера для преобразования логического объекта в объект видимости.

Проблема возникает сейчас, когда нам нужно установить видимость невидимым, нажав на кнопку закрытия на элементе управления настройками. Поскольку мы установили текст данных в элементе управления для модели представления настроек, мы не можем получить доступ к модели основного вида.

До сих пор мы думали о том, чтобы добавить viewmodel настроек как свойство к mainviewmodel и удалить текстовый текст данных из элемента управления настройками. В контроле настроек мы будем использовать привязку в качестве SettingsProperty.Property. Чем мы можем получить доступ к mainviewmodel тоже из управления расчетами. Имеет ли это смысл? Есть ли лучшие способы сделать такого рода взаимодействия?

Мне очень нравится слышать ваши идеи о том, как сделать это взаимодействие.

3 ответа

Решение

Я склонен работать с графиками моделей представлений, которые построены с использованием Castle Windsor. Модель представления верхнего уровня использует инъекцию конструктора, чтобы получить требуемые модели представления следующего уровня. И в представлениях я привязываю предъявителей содержимого к свойствам моделей представления, чтобы создать соответствующий график представления.

Делая это, родительским дочерним моделям довольно легко общаться, но немного сложнее общаться с родными или более отдаленными моделями.

В этих случаях я склонен использовать агрегатор событий или Messenger, чтобы позволить моделям представления взаимодействовать.

Поскольку вы уже используете MVVMLight, я бы предложил использовать систему Messenger MVVM Light. Он предназначен для обмена сообщениями между ViewModels. Концепция заключается в Mediator pattern где разные объекты обмениваются информацией, не зная друг друга.

Вот пример:

В SettingsViewModel зарегистрируйтесь для события, которое говорит, чтобы показать диалог настроек

public SettingsViewModel()
{
  Messenger.Default.Register<ShowSettingsMessage>(this, ShowSettingsDialog);
}

private void ShowSettingsDialog(ShowSettingsMessage showSettingsMessage)
{
  // Set the visibility:
  this.IsVisible = showSettingsMessage.Content;
}

В вашей MainViewModel вы отправляете уведомление, завернутое в Сообщение:

// make the settings visible, e.g. the button click command:    
Messenger.Default.Send(new ShowSettingsMessage(true));

И вот сообщение:

// the message:
public class ShowSettingsMessage : GenericMessage<bool>
   {
     public ShowSettingsMessage(bool isVisible)
       : base(isVisible)
     {  }
   }

Я бы не рекомендовал делать SettingsViewModel свойство Mainviewmodel так как вы теряете возможность использовать SettingsViewModel в другом контексте или даже удалить / обменять.

Попробуйте создать свойство зависимости в элементе управления "Настройки" под названием IsSettingControlVisible и связать его с родительским viewModel.

РЕДАКТИРОВАТЬ:

public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }


        public int MyProperty
        {
            get { return (int)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("MyProperty", typeof(int), typeof(UserControl1), new UIPropertyMetadata(0));
    }

и использовать это так...

 <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <local:UserControl1 MyProperty="{Binding Path=ParentViewModelProperty, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" />
        </Grid>
    </Window>
Другие вопросы по тегам