应用Mode-View-ViewModel设计模式时包括部分视图

Fil*_*erg 7 c# wpf design-patterns mvvm

想想看,我只是处理的应用程序MessagesUsers我希望我的窗口有一个共同的Menu,并在当前的区域View显示.

我只能使用消息或用户,所以我不能同时使用两个视图.因此,我有以下控件

  • MessageView.xaml
  • UserView.xaml

这只是为了更容易一点,无论是Message ModelUser Model看起来像这样:

  • 名称
  • 描述

现在,我有以下三个ViewModel:

  • MainWindowViewModel
  • UsersViewModel
  • MessagesViewModel

UsersViewModelMessagesViewModel两个刚取的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;
}
Run Code Online (Sandbox Code Playgroud)

还有另外一个会向用户展示的.现在介绍的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));
Run Code Online (Sandbox Code Playgroud)

这个依赖属性用于动态MainWindow.xaml显示User Control如下:

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

此处还有两个按钮Window可以触发命令:

  • ShowMessagesCommand
  • ShowUsersCommand

当这些被触发时,UserControl会发生变化,因为它PartialViewModel是一个依赖属性.

我想知道这是不是很糟糕的做法?我不应该像这样注入用户控件吗?是否有另一种"更好"的替代方案更符合设计模式?或者这是包含部分视图的好方法吗?

bli*_*eis 2

为什么不在主窗口中使用带有数据模板的 ContentPresenter/ContentControl ?

您可以使用以下内容代替 UserControl Content="{Binding PartialViewModel}" />:

 <ContentPresenter Content="{Binding Path=PartialViewModel}" />
Run Code Online (Sandbox Code Playgroud)

你所要做的就是:将你的 PartialViewmodel 设置为你的子视图模型并创建一个数据模板,这样 wpf 就会知道如何渲染你的子视图模型

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

<DataTemplate DataType={x:Type MessageViewModel}>
    <MessageView/>
</DataTemplate> 
Run Code Online (Sandbox Code Playgroud)

当您在 MainViewmodel 中设置 PartialViewmodel 时,正确的 View 将在您的 ContenControl 中呈现。

编辑 1 至少您必须在 ViewModel 中实现 INotifyPropertyChanged 并在设置 PartViewModel 属性时触发它。

编辑 2 如果您在视图模型中使用命令,请查看一些 mvvm 框架实现,例如 DelegateCommand 或 RelayCommand。这样处理 ICommand 就变得容易多了。在你的主视图模型中,你可以创建像这样简单的命令

private DelegateCommand _showMessageCommand;
public ICommand ShowMessageCommand
{
    get
    {
         return this._showMessageCommand ?? (this._showMessageCommand = new DelegateCommand(this.ShowMessageExecute, this.CanShowMessageExecute));
        }
    }
Run Code Online (Sandbox Code Playgroud)