Несколько 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>