Reputation: 1666
I have a View which has 2 sub views on it and a ViewModel is assigned to each view:
ViewParent - ViewModelParent
{
ViewA - ViewModelA
ViewB - ViewModelB
}
The ViewParent
structure likes below.
<StackPanel Orientation="Vertical">
<local:AView DataContext="{Binding ViewModelA, Mode=TwoWay}"></localViews:AView>
</StackPanel>
<StackPanel Orientation="Vertical">
<localViews:BView DataContext="{Binding ViewModelB, Mode=TwoWay}"></localViews:BView>
</StackPanel>
Now in code behind of ViewA
, I have an event to select a row in a gridview.
private void radGridView_SelectionChanged(object sender, SelectionChangeEventArgs e)
{
try
{
RadGridView grv = sender as RadGridView;
if (e.AddedItems.Count > 0)
{
var row = grv.SelectedItem as SomeClass;
if(condition)
// Enable a button in ViewB.
What I want is to pass row
to ViewModelB
. Also, I want to enable a button in ViewB. Finally I want to pass a few integers from ViewModelA
to ViewModelB
.
How to do it? I thought about constructor injection but still without clear idea.
Upvotes: 0
Views: 1853
Reputation: 37060
There's a lot of typing here, but there's no difficult logic and there's nothing that'll turn into a bug and bite you.
Make sure ParentViewModel
has references to ViewModelA
and ViewModelB
(as I understand it you're already there).
Give ViewModelA
a SelectedRowChanged
event:
public event EventHandler SelectedRowChanged;
Give ViewModelB
an IsMyButtonEnabled
property (but name it better than that; you need the name to indicate which button its referring to)
private bool _isMyButtonEnabled;
public bool IsMyButtonEnabled {
get { return _isMyButtonEnabled; }
set {
_isMyButtonEnabled = value;
OnPropertyChanged(nameof(IsMyButtonEnabled));
}
}
In ViewB
, bind the button's IsEnabled
property to that property:
<Button
...
IsEnabled="{Binding IsMyButtonEnabled}"
...
Give both ViewModelA
and ViewModelB
a SelectedRow
property.
private SomeClass _selectedRow;
public SomeClass SelectedRow {
get { return _selectedRow; }
set {
_selectedRow = value;
OnPropertyChanged(nameof(SelectedRow));
/*
DO ADDITIONAL STUFF HERE:
VMA:
SelectedRowChanged?.Invoke(this, EventArgs.Empty);
VMB:
Set IsMyButtonEnabled to whatever is appropriate based on
the selected row.
*/
}
}
ParentViewModel
sets up a handler for ViewModelA.SelectedRowChanged
, which it can do because it has a reference to its instance of ViewModelA
. Then the handler tells ViewModelB
to do whatever needs to be done when SelectedRow changes. Another way to do this would be to give ViewModelB
a reference to ViewModelA
, and have it handle ViewModelA.SelectedRowChanged
. But as a rule, you want your child viewmodels to be more loosely coupled than that. You don't want B to depend on having a sibling of type A. But the parent already depends on having both of those children. In for a penny, in for a pound. You can't get any more wet.
...
// Constructor or someplace
this.VMA = new ViewModelA();
this.VMA.SelectedRowChanged += ViewModelA_SelectedRowChanged;
...
void ViewModelA_SelectedRowChanged(Object sender, EventArgs e)
{
// VMB.SelectedItem's setter will enable the button appropriately
VMB.SelectedItem = VMA.SelectedItem;
}
You really "should" be doing the button thing with a Command, and enabling the Command instead of having an Is*ButtonEnabled
property. That's a more versatile and powerful way to do things. But we can take things one step at a time.
Upvotes: 1