关于Count
,您根本不需要这样做。只需绑定到Tasks.Count
,您的绑定将通过ObservableCollection
被通知更改。
Completed
则是另一回事,因为它位于ObservableCollection
之外。但从抽象/接口层面来看,您确实希望Completed
成为Tasks
集合的属性。
为此,我认为更好的方法是为您的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");
}
这样做可以让您获得
ObservableCollection
的所有好处,并有效地使
Completed
属性成为其一部分。我们仍然没有仅捕获完成项目数量真正更改的情况,但我们已经在某种程度上减少了冗余通知的数量。
现在,视图模型只有这个属性:
public TasksViewModel Tasks { get; set; }
…你可以轻松绑定到Tasks
、Tasks.Count
和Tasks.Completed
。
作为替代方案,如果你更愿意在“主”视图模型上创建这些其他属性,你可以采用子类化的ObservableCollection<T>
概念来创建一个带有某些方法的集合,其中你可以传递一个Action<string>
委托,它将表示在主视图模型上引发属性更改通知,以及一些属性名称列表。然后,该集合就可以有效地在视图模型上引发属性更改通知:
public class ObservableCollectionWithSubscribers<T> : ObservableCollection<T>
{
Action<string> _notificationAction = s => { };
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);
}
}
您甚至可以将属性类型保留为
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));
}
}