Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Command Binding

Tags:

I'm trying to learn the MVVM pattern. The main problem I'm having is learning where I should be declaring, creating and binding command objects.

2 examples:

  1. I have a main form that acts like a switch board or main menu. Selct button 1 and View 1 is displayed, Select button 2 and view 2 is displayed. Great. Now I want to go back to the main form so I need a button on View 1 (and view 2) called "Main Menu". Where should I define the command and command handlers so that I can bind to the "ShowMainMenu" command? I could create them in the View2ViewModel but then I don't have access to show the Main View? Or, I could create thim in the MainView model but then How do I bind to them in the child view model (I'm using the RelayCommand obejct as per the mvvm recommendation and they don't bubble up to the parent.)

  2. I have two user controls visible on a single Main Window view let's call them MainView, UC1 and UC2. each of these has ViewModel MainViewModel, UC1ViewModel, UC2View Model. I have a button on UC1 called "AddItem". It should add an item in a list on UC2. What is the currect way to set up an "AddItemCommand" and bind to it. Should the Command be in MainViewModel, Uc1ViewModel or UC2ViewModel? And How shoud I bind to it.

Thanks for your help.

like image 256
thrag Avatar asked Dec 05 '09 12:12

thrag


1 Answers

1) You can inherit View1Model and View2Model from one base ViewModel and define ShowMainMenu there.

or (it's my approach)

Create RootView with ContentPresenter which will show all of your views. Create RootVeiwModel with property ViewContent. Bind Content propertty of ContetnPresenter to ViewContent property of RootViewModel. You can use object as type of ViewContent, but I advise you to define the interface that is supported by MainVView1Model, View1Model and View2Model. Changing of ViewContent must raise ProprtyChangedEvent. Define ShowMainViewCommand in RootViewModel which will just change ViewContent to MainViewModel (and it will show as MainView). Then bind Command property of Button in View1 and View2 to that command, for exmple that way:

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

There is some code to explain what I'm trying to say:

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) Add reference to MainViewModel to UC1ViewModel and UC2ViewModel - thats the way to influence other controls. MainViwModel must contain properties that contains UC1ViewModel and UC2ViewModel Items of second user control must be contained in ObservableCollection.

I just show you how it works by the code:

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;
        }
    }
    ...
}
like image 123
bniwredyc Avatar answered Oct 13 '22 01:10

bniwredyc