1

我正在开发一个 WPF 应用程序。我有一个绑定到数据网格的 ObservableCollection。这部分一切正常。如果集合被更新,则网格被刷新。如果手动更新网格,则集合也会更新。

现在,我有一个类本地属性,用于存储集合中 Video.Duration 属性的总和。这绑定到一个标签控件。当我向集合添加一个新条目时(当用户在网格上放置文件时实现),持续时间的总和被计算并正确显示。但是,当用户更新单元格中的值时,不会处理此事件。

我已阅读有关 INOtifyPropertyChanged 的​​信息,这似乎是我需要的。但是,我并不完全理解这个概念。

这就是我的想法: 1. 在我的视频课程中实现 INOtifyPropertyChanged。2.在duration属性的setter中引发属性改变事件

现在,sum 属性在主类中,我如何订阅 propertychanged 事件,以便在更新视频的持续时间之一时重新计算总持续时间。

4

2 回答 2

1

你的方法对我来说听起来不错。您还必须INotifyPropertyChanged在主类中实现,因为Bindingfor theLabel将在该类中侦听 Sum 属性的更改。

在 Video 和 Main 类中实现INotifyPropertyChanged后,您将拥有一个NotifyPropertyChanged事件。您可以像订阅任何事件一样订阅此事件:

private void Subscribe()
{
    foreach(var video in _videos)
    {
        video.NotifyPropertyChanged += OnVideoPropertyChanged;
    }
}

private void OnVideoPropertyChanged(object sender, NotifyPropertyChangedEventArgs e)
{
    if(e.PropertyName == "Duration")
    {
        this.RecalculateSum();
        this.RaisePropertyChanged("Sum");  //Or call this from inside RecalculateSum()
    }
}

要记住的一件事是,您需要在NotifyPropertyChanged任何时候删除视频或卸载视频时取消订阅该事件。这将有助于防止内存泄漏:

Video.NotifyPropertyChanged -= OnVideoPropertyChanged;
于 2013-07-13T23:16:12.243 回答
1

根据您的设计偏好,您可以完全避免事件订阅及其相关的内存泄漏。如果您按照这些思路构建 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
    }

此类在其构造函数中接受一个委托,并在每次“持续时间”属性更改时调用它。要将其连接起来,您可以按照这些思路实现 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 管道来处理绑定。

于 2013-07-13T23:50:32.723 回答