Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Pattern, ViewModel DataContext question

I need to figure out how to communicate between ViewModels. I'm new to MVVM so please be kind.

Here's a dumbed down example

class definitions(assume that I have hooked the Child.PropertyChanged event in the ParentViewModel):

public class ParentViewModel : ViewModelBase
{
    public ChildViewModel Child { get; set; }
}

public class ChildViewModel : ViewModelBase
{
    String _FirstName;
    public String FirstName 
    {
        get { return _FirstName; }
        set
        {
            _FirstName = value;
            OnPropertyChanged("FirstName");
        }
    }
}

Here's what you see in the resource dictionary

<DataTemplate DataType="{x:Type vm:ParentViewModel}">
    <vw:ParentView/>
</DataTemplate>

<DataTemplate DataType="{x:Type vm:ChildViewModel}">
    <vw:ChildView/>
</DataTemplate>

and the code-behind of the ChildView:

public partial class ChildView : UserControl
{
    public QueueView()
    {
        InitializeComponent();
        DataContext = new ChildViewModel();
    }
}

The obvious problem is that when the ChildView gets instantiated (via selection from the DataTemplate) it creates a new ChildViewModel class and the ParentViewModel doesn't have access to it.

So how can I instantiate the DataContext of the View to be the original ViewModel that caused the DataTemplate to be selected?

An obvious fix is to mmerge the properties in the ChildViewModel into the ParentViewModel, but I would rather separate it because for reuse.

I'm sure the answer is trivial, I just would like to know what it is. :)

Thanks in advance.

like image 375
Jose Avatar asked May 05 '09 16:05

Jose


People also ask

What is the use of ViewModel in MVVM?

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.

How do I create a ViewModel in MVVM?

1 - Create all the properties in the customer again on the view model. Inject the customer instance into view model and each properties will retrun the value from this customer object. Advantage of this method is that I can create a common base class for all view models and have common functionality dumped there.

Should a ViewModel have a constructor?

At present, this means that every ViewModel must have a public constructor which has either no parameters or which has only string parameters. So the reason your ViewModel isn't loading is because the MvxDefaultViewModelLocator can't find a suitable constructor for your ViewModel.


2 Answers

You should simply remove the line:

DataContext = new ChildViewModel();

The DataContext of the view will be set automatically by WPF. DataTemplates always have their data context set to the data for the template (in this case the ViewModel):

<DataTemplate DataType="{x:Type vm:ChildViewModel}">
    <vw:ChildView/>
</DataTemplate>

The end result is that you can build your view model objects separately (both parent and child classes) and then display them later by simply plugging them into content controls.

like image 132
Josh G Avatar answered Oct 19 '22 01:10

Josh G


Let's say you have a QueueView that uses a QueueViewModel.

public class QueueViewModel : INotifyPropertyChanged
{
    public ParentType Parent { get; set; }

    public QueueViewModel(ParentType parent)
    {
        this.Parent = parent;
        foreach (ChildType child in Parent)
        {
            child.PropertyChanged += delegate(object sender,
                PropertyChangedEventArgs e)
            {
                if (e.PropertyName != "IsSelected")
                    return;

                //do something like this:
                Parent.IsSelected = AllChildrenAreSelected();
            };
        }
    }

}

public class ParentType : INotifyPropertyChanged
{
    private bool _isSelected;

    public IList<ChildType> Children { get; set; }
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }
}

public class ChildType : INotifyPropertyChanged
{
    private string _name;
    private bool _isSelected;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }
}

-- QueueView part

<StackPanel>
<CheckBlock Text="{Binding Path=Parent.Name}" 
            IsChecked="{Binding Parent.IsSelected}"/>
<ItemsControl ItemsSource="{Binding Path=Parent.Children}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>                                    
            <CheckBox Content="{Binding Path=Name}"
                      IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>
        </DataTemplate>
    <ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
like image 26
Soni Ali Avatar answered Oct 19 '22 00:10

Soni Ali