Con respecto a Count
, no tiene que hacer esto en absoluto. Simplemente enlace a Tasks.Count
y sus enlaces serán notificados del cambio por el ObservableCollection
.
Completed
es una historia diferente, porque está fuera de ObservableCollection
. Sin embargo, desde el nivel de la abstracción/interfaz, realmente desea que Completed
sea propiedad de esa colección Tasks
.
Por ello, creo que un mejor enfoque sería crear "sub" vista-modelo para su propiedad Tasks
:
public class TasksViewModel : ObservableCollection<Task>
{
public int Completed
{
get { return this.Count(t => t.IsComplete); }
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if(e.PropertyName == "Count") NotifyCompletedChanged();
}
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
NotifyCompletedChanged();
}
void NotifyCompletedChanged()
{
OnPropertyChanged(_completedChangedArgs);
}
readonly PropertyChangedEventArgs _completedChangedArgs = new PropertyChangedEventArgs("Completed");
}
Esto le da todas las ventajas de la ObservableCollection
, y hace efectiva la Completed
parte de la propiedad. Todavía no hemos capturado solo los casos en los que la cantidad de elementos completados realmente cambia, pero hemos reducido algo el número de notificaciones redundantes.
Ahora el modelo de vista sólo tiene la propiedad:
public TasksViewModel Tasks { get; set; }
... y usted puede unirse a Tasks
, Tasks.Count
y Tasks.Completed
con facilidad.
Como alternativa, si prefiere crear estas otras propiedades en la vista-modelo "principal", puede aprovechar esta noción de una subclase ObservableCollection<T>
para crear uno con algún método en el que se puede pasar en una Action<string>
delegar, que representaría elevar una notificación de cambio de propiedad en el modelo de vista principal y una lista de nombres de propiedad. Esta colección podría entonces aumentar de manera efectiva las notificaciones de cambio de propiedad de la vista-modelo:
public class ObservableCollectionWithSubscribers<T> : ObservableCollection<T>
{
Action<string> _notificationAction = s => { }; // do nothing, by default
readonly IList<string> _subscribedProperties = new List<string>();
public void SubscribeToChanges(Action<string> notificationAction, params string[] properties)
{
_notificationAction = notificationAction;
foreach (var property in properties)
_subscribedProperties.Add(property);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
NotifySubscribers();
}
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
NotifySubscribers();
}
void NotifySubscribers()
{
foreach (var property in _subscribedProperties)
_notificationAction(property);
}
}
Incluso se puede dejar el tipo de propiedad como ObservableCollection<Task>
.
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
var tasks = new ObservableCollectionWithSubscribers<Task>();
tasks.SubscribeToChanges(Notify, "Completed");
Tasks = tasks;
}
public ObservableCollection<Task> Tasks { get; private set; }
public int Completed
{
get { return Tasks.Count(t => t.IsComplete); }
}
public event PropertyChangedEventHandler PropertyChanged;
void Notify(string property)
{
var handler = PropertyChanged;
if(handler != null) handler(this, new PropertyChangedEventArgs(property));
}
}
Ese es sin duda un mejor diseño. –