Reputation: 6091
So I have a class MainViewModel
in which I have a button. The button navigates to a view which has its own view model, let's call in ListViewModel
. It resides inside MainViewModel. It has an ObservableCollection
called WorkOrders
.
In my main view model, I have a property, which returns the number of items, in the list in my ListViewModel. However, if I bind my button text to this property (NumberOfWorkOrders
), then nothing happens, when WorkOrders.Count()
changes. Even if I call OnPropertyChanged("NumberOfWorkOrders")
.
However, it does work, if I bind to the identical property inside the ListViewModel. How come it does not work, with the property in the MainViewModel? Is it because the notification from INotifyPropertyChanged does not work in a different view model?
Button binding which DOES NOT work (uses property from MainViewModel)
<Button
Content="{Binding NumberOfWorkOrders}"
ContentStringFormat="WorkOrders ({0})" />
Button binding which DOES work (uses property from ListViewModel)
<Button
DataContext="{Binding LVM}"
Content="{Binding NumberOfWorkOrders}"
ContentStringFormat="WorkOrders ({0})" />
MainViewModel.cs
public class MainViewModel : BindableBase
{
// INotifyPropertiesChanged is implemented in BindableBase
private ListViewModel listViewModel = new ListViewModel();
// This is where I would like to bind my button text to
public int NumberOfWorkOrders
{
get { return listViewModel.WorkOrders.Count(); }
}
// I would prefer not to have this
public ListViewModel LVM
{
get { return listViewModel; }
}
}
ListViewModel.cs
public class ListViewModel : BindableBase
{
// INotifyPropertiesChanged is implemented in BindableBase
public ObservableCollection<WorkOrder> WorkOrders
{
get; set;
}
// I would prefer to use the version of this in the MainViewModel
public int NumberOfWorkOrders
{
get { return listViewModel.WorkOrders.Count(); }
}
public void RefreshWorkOrders()
{
(...) // Load work orders and add them to collection
OnPropertyChanged("NumberOfWorkOrders");
}
}
Upvotes: 0
Views: 151
Reputation: 22008
You are running into this problem
, where you have aggregated property which required additional job: you will have to subscribe to ListViewModel.PropertyChanged
and rise notification for MainViewModel.NumberOfWorkOrders
property:
public class MainViewModel : BindableBase
{
readonly ListViewModel listViewModel = new ListViewModel();
public int NumberOfWorkOrders => listViewModel.WorkOrders.Count();
public MainViewModel()
{
// since you already rise notification in ListViewModel
// listen to it and "propagate"
listViewModel.PropertyChanged += (s, e) =>
{
if(e.PropertyName == nameof(ListViewModel.NumberOfWorkOrders))
OnPropertyChanged(nameof(NumberOfWorkOrders));
};
}
}
First button (which does NOT work) has MainViewModel
as data context, binding will only listen for notification in this class.
As a simple fix you can include LVM
in Path
of binding. Binding is smart and will start listening to both events: of main view model and of that instance given by LVM
property:
<Button Content="{Binding LVM.NumberOfWorkOrders}" ... />
you can delete NumberOfWorkOrders
from MainViewModel
then.
Upvotes: 1
Reputation: 2804
The reason your MainViewModel
binding doesn't work, because you call OnPropertyChanged("NumberOfWorkOrders")
from ListViewModel
context.
I would suggest in MainViewModel
to sign to changes in listViewModel.WorkOrders
, and fire OnPropertyChanged("NumberOfWorkOrders")
from MainViewModel
, when WorkOrders
changed. You need to look into documentation of ObservableCollection
to find how to sign for collection changed notifications.
Upvotes: 0