Включение частичных представлений при применении шаблона проектирования Mode-View-ViewModel - PullRequest
7 голосов
/ 08 марта 2011

Учтите, что у меня есть приложение, которое обрабатывает только Messages и Users. Я хочу, чтобы в моем окне была общая Menu и область, где отображается текущий View.

Я могу работать только с сообщениями или пользователями, поэтому я не могу работать одновременно с обоими представлениями. Поэтому у меня есть следующие Controls

  • MessageView.xaml
  • UserView.xaml

Просто чтобы сделать это немного проще, и Message Model, и User Model выглядят так:

  • Имя
  • Описание

Теперь у меня есть следующие три модели представления:

  • MainWindowViewModel
  • UsersViewModel
  • MessagesViewModel

UsersViewModel и MessagesViewModel оба просто извлекают ObserverableCollection<T> его относительно Model, который связан с соответствующим View следующим образом:

<DataGrid ItemSource="{Binding ModelCollection}" />

MainWindowViewModel подключает два разных Commands, которые реализовали ICommand, что выглядит примерно так:

public class ShowMessagesCommand : ICommand
{
    private ViewModelBase ViewModel { get; set; } 
    public ShowMessagesCommand (ViewModelBase viewModel)
    {
        ViewModel = viewModel;
    }
    public void Execute(object parameter)
    {
        var viewModel = new ProductsViewModel();
        ViewModel.PartialViewModel = new MessageView { DataContext = viewModel };
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
}

И есть еще один, похожий на него, который покажет пользователям. Теперь введено ViewModelBase, которое содержит только следующее:

    public UIElement PartialViewModel
    {
        get { return (UIElement)GetValue(PartialViewModelProperty); }
        set { SetValue(PartialViewModelProperty, value); }
    }

    public static readonly DependencyProperty PartialViewModelProperty =
        DependencyProperty.Register("PartialViewModel", typeof(UIElement), typeof(ViewModelBase), new UIPropertyMetadata(null));

Это свойство зависимости используется в MainWindow.xaml для динамического отображения User Control следующим образом:

<UserControl Content="{Binding PartialViewModel}" />

На этом Window также есть две кнопки, которые запускают команды:

  • ShowMessagesCommand
  • ShowUsersCommand

И когда они запускаются, UserControl изменяется, потому что PartialViewModel является свойством зависимости.

Я хочу знать , является ли это плохой практикой? Разве я не должен вводить пользовательский контроль таким образом? Есть ли другая «лучшая» альтернатива, которая лучше соответствует шаблону дизайна? Или это хороший способ включить частичные представления?

Ответы [ 4 ]

2 голосов
/ 08 марта 2011

почему бы не использовать ContentPresenter / ContentControl с табличкой данных в главном окне?

вместо UserControl Content = "{Binding PartialViewModel}" />, вы можете использовать:

 <ContentPresenter Content="{Binding Path=PartialViewModel}" />

все, что вам нужно сделать: установить PartialViewmodel для вашей дочерней viewmodel и создать шаблон данных, поэтому wpf будет знать, как отобразить вашу childviewmodel

<DataTemplate DataType={x:Type UserViewModel}>
    <UserView/>
</DataTemplate> 

<DataTemplate DataType={x:Type MessageViewModel}>
    <MessageView/>
</DataTemplate> 

всякий раз, когда вы устанавливаете PartialViewmodel в вашей MainViewmodel, правильный просмотр будет отображаться в вашем ContenControl.

Редактировать 1 по крайней мере, вам нужно реализовать INotifyPropertyChanged в вашей ViewModel и запускать его, когда задано свойство PartViewModel.

Редактировать 2 если вы используете команды в своих моделях представления, взгляните на некоторые реализации инфраструктуры mvvm, такие как DelegateCommand или RelayCommand. с этим работать с ICommand стало намного проще. внутри вашей модели mainview вы можете создавать такие простые команды

private DelegateCommand _showMessageCommand;
public ICommand ShowMessageCommand
{
    get
    {
         return this._showMessageCommand ?? (this._showMessageCommand = new DelegateCommand(this.ShowMessageExecute, this.CanShowMessageExecute));
        }
    }
2 голосов
/ 08 марта 2011

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

Однако есть пара вещей, которые не так хороши:

  1. ViewModelBase должен быть DependencyObject, чтобы иметь DependencyProperty. В реальном мире я обнаружил, что очень неприятно обрабатывать ViewModel однопоточным способом (существует множество асинхронных операций, которые можно выполнять).
  2. Не масштабируется; изменение макета потребует значительных усилий.

Любая приличная инфраструктура MVVM упрощает составление пользовательского интерфейса, предоставляя инфраструктуру для создания подвидов в вашем основном представлении. В Призме (которая является моим личным предпочтением) это происходит с Regions.

1 голос
/ 08 марта 2011

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

. Я бы также не стал использовать свойства зависимостей в ваших моделях представления и вместо этого реализовал INotifyPropertyChanged .Caliburn.Micro поставляется с типом PropertyChangedBase, который реализует этот интерфейс, а также предоставляет вспомогательный метод для вызова события PropertyChanged с использованием лямбда-выражений, а не магических строк (что гораздо лучше для рефакторинга позже).

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

http://msdn.microsoft.com/en-us/library/ms743695.aspx показывает пример реализации INotifyPropertyChanged.

Чтобы достичь того, что вы хотите сделать в Caliburn.Micro, вы должны сделать что-то вродениже (грубый пример, но он показывает вам, как легко сделать композицию представления с использованием инфраструктуры MVVM):

public class MainViewModel : Conductor<IScreen>.Collection.OneActive
{
  private UsersViewModel usersViewModel;

  private MessagesViewModel messagesViewModel;

  public UsersViewModel UsersViewModel
  {
    get { return this.usersViewModel; }
    set { this.usersViewModel = value; this.NotifyOfPropertyChanged(() => this.UsersViewModel);
  }

  public MessagesViewModel MessagesViewModel
  {
    get { return this.messagesViewModel; }
    set { this.messagesViewModel = value; this.NotifyOfPropertyChanged(() => this.MessagesViewModel);
  }

  public MainViewModel()
  {
    this.UsersViewModel = new UsersViewModel();
    this.MessagesViewModel = new MessagesViewModel();

    this.Items.Add(this.UsersViewModel);
    this.Items.Add(this.MessagesViewModel);

    // set default view
    this.ActivateItem(this.UsersViewModel);
  }

  public ShowUsers()
  {
    this.ActivateItem(this.UsersViewModel);
  }

  public ShowMessages()
  {
    this.ActivateItem(this.MessagesViewModel);    
  }
}

Обратите внимание, что UsersViewModel и MessagesViewModel будут производными от Screen.

Чтобы вызвать глаголы ShowUsers или ShowMessages с Caliburn.Micro, вам просто нужно создать элементы управления представлением с тем же именем.Тип проводника имеет свойство ActiveItem, которое является текущим проводимым элементом, поэтому вы можете добавить ContentControl в свой файл MainView.xaml с именем ActiveItem, и Caliburn.Micro позаботится о введении правильного представления.

Так что ваш MainView.xaml может выглядеть так:

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="200" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinition>

  <!-- Menu in left hand column -->
  <StackPanel Grid.Column="0">
   <Button x:Name="ShowUsers">Show Users</Button>
   <Button x:Name="ShowMessages">Show Messages</Button>
  </StackPanel>

  <!-- Currently active item -->
  <ContentControl x:Name="ActiveItem" Grid.Column="1" />
</Grid>
0 голосов
/ 08 марта 2011

Вы должны взглянуть на призму . Это дает вам управление регионом. Я также хотел бы взглянуть на MEF для экспорта представлений и на этом пути поддерживать расширяемость для вашего проекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...