C# 将类属性绑定到集合的和
我正在开发一个WPF应用程序。我有一个绑定到datagrid的ObservableCollection。这部分一切正常。如果集合已更新,则网格将刷新。如果手动更新网格,则集合也会更新 现在,我有一个类本地属性,它存储集合中Video.Duration属性的总和。这是绑定到标签控件的。当我向集合添加一个新条目时(当用户将文件放到网格上时实现),将计算并正确显示持续时间之和。但是,当用户更新单元格中的值时,不会处理此事件 我读过关于INOtifyPropertyChanged的文章,这似乎是我需要的。然而,我并不完全理解这个概念 以下是我的想法: 1.在我的视频类中实现INOtifyPropertyChanged。 2.在duration属性的setter中引发属性更改事件C# 将类属性绑定到集合的和,c#,wpf,events,delegates,inotifypropertychanged,C#,Wpf,Events,Delegates,Inotifypropertychanged,我正在开发一个WPF应用程序。我有一个绑定到datagrid的ObservableCollection。这部分一切正常。如果集合已更新,则网格将刷新。如果手动更新网格,则集合也会更新 现在,我有一个类本地属性,它存储集合中Video.Duration属性的总和。这是绑定到标签控件的。当我向集合添加一个新条目时(当用户将文件放到网格上时实现),将计算并正确显示持续时间之和。但是,当用户更新单元格中的值时,不会处理此事件 我读过关于INOtifyPropertyChanged的文章,这似乎是我需要的
现在,sum属性在主类中,如何订阅propertychanged事件,以便在更新视频的某个持续时间时重新计算总持续时间。您的方法听起来不错。您还必须在主类中实现
INotifyPropertyChanged
,因为标签的绑定将侦听Sum属性的更改
一旦在视频和主类中实现了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;
根据您的设计偏好,您可以完全避免事件订阅及其关联的内存泄漏。如果你按照这些思路构建视频课程
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
}
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
}
此类在其构造函数中接受一个委托,并在每次“Duration”属性更改时调用该委托。要将其连接起来,可以沿以下直线实现ViewModel
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
}
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
}
公共类MyViewModel:INotifyPropertyChanged
{
公共ObservableCollection MyCollection{get;set;}
公共MyViewModel()
{
MyCollection=新的ObservableCollection();
视频v=新视频(总和回调);
MyCollection.Add(v);
}
私有void SummationCallback()
{
SumOfAllDurations=MyCollection.Sum(q=>q.Duration)
}
私人双保险期;
公共双保险期
{
获取{return\u sumOfAllDurations;}
设置
{
如果(值!=\u总持续时间)
{
_sumOfAllDurations=值;
房地产变更(“SumOfAllDurations”);
}
}
}
#区域INotifyPropertyChanged实现
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged(字符串名称)
{
var handler=System.Threading.Interlocked.compareeexchange(ref-PropertyChanged,null,null);
if(处理程序!=null)
{
处理程序(此,新PropertyChangedEventArgs(名称));
}
}
#端区
}
并将标签绑定到“SumOfAllDurations”。此策略将使所有内容保持同步,而无需求助于事件订阅(如果用户删除视频,将导致孤立事件),并使用WPF管道处理绑定 谢谢!我采用了这个解决方案,这样我就不必担心订阅/取消订阅活动。但是,我没有创建模型类,而是为total duration实现了DependencyProperty,这样每当total duration的值更新时,标签都会更新。对我来说,通过总结回调是你回答中最重要的方面。