MVVM命令绑定

5

我正在尝试学习MVVM模式。 我遇到的主要问题是学习在哪里声明、创建和绑定命令对象。

以下是两个例子:

  1. 我有一个主窗体,它像一个交换板或主菜单。选择按钮1,显示视图1;选择按钮2,显示视图2。很好。现在我想回到主窗体,所以我需要在View 1(和View 2)上放置一个名为“Main Menu”的按钮。我应该在哪里定义命令和命令处理程序,以便我可以绑定到“ShowMainMenu”命令?我可以在View2ViewModel中创建它们,但这样我就无法访问显示主视图了。或者,我可以在MainViewModel中创建它们,但是如何在子视图模型中绑定它们(我按照mvvm推荐使用RelayCommand对象,它们不会冒泡到父级)。

  2. 我在单个主窗口视图上看到了两个用户控件,我们称它们为MainView、UC1和UC2。每个控件都有ViewModel MainViewModel、UC1ViewModel、UC2ViewModel。我在UC1上放置了一个名为“AddItem”的按钮。它应该在UC2上的列表中添加一个项目。设置“AddItemCommand”的正确方法是什么,如何绑定它?命令应该在MainViewModel、UC1ViewModel还是UC2ViewModel中?我该如何绑定它。

感谢您的帮助。

2个回答

3

1)您可以从一个基本的ViewModel中继承View1Model和View2Model,并在其中定义ShowMainMenu。

或者(这是我的方法)

创建RootView,其中包含ContentPresenter来显示所有视图。创建RootViewModel并使用属性ViewContent。将ContentPresenter的Content属性绑定到RootViewModel的ViewContent属性。您可以使用“object”作为ViewContent的类型,但我建议您定义界面,该界面由MainVView1Model、View1Model和View2Model支持。更改ViewContent必须引发PropertyChangedEvent。 在RootViewModel中定义ShowMainViewCommand,它将只是将ViewContent更改为MainViewModel(它将显示为主视图)。然后将View1和View2中的Button的Command属性绑定到该命令,例如:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type RootView}}, 
                         Path=DataContext.ShowMainViwe}

这里有一些代码来解释我的意思:

RootView.xaml

...
<ContentPresenter Content={Binding ViewContent} />
...

RootViewModel.ca

class RootViewModel : INotifyPropertyCahnged
{
    ...
    private object _ViewContent;
    public object ViewContent
    {
        get {return _ViewContent;}
        set
        {
            _ViewContent = value;
            if (PropertyChanged != null)
            {
                PropertyChanged ("ViewContent");
            }

        }
    }

    private RelayCommand _ShowMainView;
    public ICommand ShowMainView
    {
        get 
        {
            if (_ShowMainView == null)
            {
                _ShowMainView = new RelayCommand(x => ViewContent = new MainViewModel());
            }
            return _ShowMainView;
        }
    }
    ...
}

2) 将MainViewModel引用添加到UC1ViewModel和UC2ViewModel中 - 这是影响其他控件的方法。 MainViewModel必须包含包含UC1ViewModel和UC2ViewModel的属性,第二个用户控件中的项必须包含在ObservableCollection中。

我通过代码向您展示了它的工作方式:

class UC1ViewModel : INotifyPropertyChanged
{
    ...
    private MainViewModel _Parent;
    public UC1ViewModel(MainViewModel parent)
    {
        _Panert = parent;
    }

    private RelayCommand _AddItemToUC2;
    public ICommand AddItemToUC2
    {
        get
        {
            if (_AddItemToUC2 = null)
            {
                // UC2Content is UC2ViewModel
                // Items is ObservableCollection
               _AddItemToUC2 = new RelayCommand(x => _Parent.UC2Content.Items.Add(...));
            }
            return AddItemToUC2;
        }
    }
    ...
}

在第一个示例中,您设置了ViewContent = new MainViewModel());这应该是一个Window / Usercontrol吗?还是您真的将当前内容设置为视图模型? - thrag
这是视图模型。如果您在视图中放置ContentPresenter并将Content属性绑定到ViewModel,则它将显示为关联视图。您是否像这样使用视图-视图模型关联: <DataTemplate DataType="{x:Type ViewModel:MainViewModel}"> <View:MainView /> </DataTemplate> - bniwredyc

2
MainModel可以为每个UCxViewModel设置一个属性或更简单的方式是使用一个ViewModel列表。 “Show”命令将创建相应的UVxViewModel,订阅由UVxViewModel发布的“OnClose”事件,并将其添加到列表中。 MainView有一个控件(例如Tab Control)绑定到此列表和DataTemplates定义要用于每个UCxViewModel的Views。 当UVxViewModel触发其OnClose事件时,MainModel将其从列表中删除,导致相应的视图“关闭”。
对于“添加项目”部分,ViewModels应共享项目列表(即Model)。然后,UC2ViewModel可以添加项目,并且UC1View将得到更新(前提是列表实现了INotifyCollectionChanged)。
我在理解MVVM方面发现这篇解释非常有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接