設計の好みによっては、イベント サブスクリプションとそれに関連するメモリ リークを完全に回避できます。これらの方針に沿って Video クラスを作成すると...
public class Video : INotifyPropertyChanged
{
public Video(Action summationCallback)
{
_summationCallback = summationCallback;
}
private readonly Action _summationCallback;
private double _duration;
public double Duration
{
get { return _duration; }
set
{
if (value != _duration)
{
_duration = value;
OnPropertyChanged("Duration");
if (_summationCallback != null)
{
_summationCallback();
}
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
このクラスは、コンストラクターでデリゲートを受け取り、'Duration' プロパティが変更されるたびにそれを呼び出します。それを接続するには、これらの線に沿って ViewModel を実装できます...
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<Video> MyCollection { get; set; }
public MyViewModel()
{
MyCollection = new ObservableCollection<Video>();
Video v = new Video(SummationCallback);
MyCollection.Add(v);
}
private void SummationCallback()
{
SumOfAllDurations = MyCollection.Sum(q=>q.Duration)
}
private double _sumOfAllDurations;
public double SumOfAllDurations
{
get { return _sumOfAllDurations; }
set
{
if (value != _sumOfAllDurations)
{
_sumOfAllDurations = value;
OnPropertyChanged("SumOfAllDurations");
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
そして、ラベルを「SumOfAllDurations」にバインドします。この戦略は、イベント サブスクリプション (ユーザーがビデオを削除すると孤立する) に頼ることなくすべての同期を維持し、WPF 配管を使用してバインディングを処理します。