C# 通知WPF/C中可观察集合中的项目更改#
在我的WPF项目中,我有一个C# 通知WPF/C中可观察集合中的项目更改#,c#,wpf,mvvm,data-binding,prism,C#,Wpf,Mvvm,Data Binding,Prism,在我的WPF项目中,我有一个服务 EF模型定义为 public class Service { public int ID public string Name public decimal Price } 在我的viewmodel中,我有 public class ReceiptViewModel : BindableBase { private ObservableCollection<Service> _services; public Obser
服务
EF模型定义为
public class Service
{
public int ID
public string Name
public decimal Price
}
在我的viewmodel中,我有
public class ReceiptViewModel : BindableBase
{
private ObservableCollection<Service> _services;
public ObservableCollection<Service> Services
{
get { return _services; }
set { SetProperty(ref _services, value, () => RaisePropertyChanged(nameof(Total))); }
}
public decimal Total => Services.Sum(s => s.Price);
}
公共类ReceiptViewModel:BindableBase
{
私人可观测收集服务;
公共收集服务
{
获取{return\u services;}
set{SetProperty(ref _services,value,()=>RaisePropertyChanged(nameof(Total));}
}
公共十进制总数=>Services.Sum(s=>s.Price);
}
Total绑定到我视图中的textblock,而我的可观察集合绑定到一个itemscontrol,其中包含textbox
我希望每次用户从UI更改我收藏中的一个价格时,我的总文本块都会更改。我怎样才能做到这一点呢?这很简单,但很乏味:
ServiceViewModel
ReceiptViewModel.Services
)PropertyChanged
(并从所有删除项中分离,同时附加最初存在的所有项)ServiceViewModels
发生更改时,设置新的ReceiptViewModel.Total
(如果您将其设置为计算属性,则提升ReceiptViewModel.PropertyChanged
)ServiceViewModel
或视图模型集合更改时,也会更新数据库如果您改用
事件聚合器,第3步可能会更容易/更简单/更明显。您应该自己实现它,这是我的可观察收集示例(并且您还需要在更改收集项目时订阅并引发OnPropertyChanged(nameof(Total)),或者将collectionEx的实现更改为引发collection changed事件
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public ObservableCollectionEx(IEnumerable<T> initialData) : base(initialData)
{
Init();
}
public ObservableCollectionEx()
{
Init();
}
private void Init()
{
foreach (T item in Items)
item.PropertyChanged += ItemOnPropertyChanged;
CollectionChanged += FullObservableCollectionCollectionChanged;
}
private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (T item in e.NewItems)
{
if (item != null)
item.PropertyChanged += ItemOnPropertyChanged;
}
}
if (e.OldItems != null)
{
foreach (T item in e.OldItems)
{
if (item != null)
item.PropertyChanged -= ItemOnPropertyChanged;
}
}
}
private void ItemOnPropertyChanged(object sender, PropertyChangedEventArgs e)
=> ItemChanged?.Invoke(sender, e);
public event PropertyChangedEventHandler ItemChanged;
}
公共类ObservableCollectionEx:ObservableCollection,其中T:INotifyPropertyChanged
{
公共ObservableCollectionEx(IEnumerable initialData):基(initialData)
{
Init();
}
公共可观测集合
{
Init();
}
私有void Init()
{
foreach(项目中的T项目)
item.PropertyChanged+=ItemOnPropertyChanged;
CollectionChanged+=FullObservableCollectionCollectionChanged;
}
私有void FullObservableCollectionCollectionChanged(对象发送方,NotifyCollectionChangedEventArgs e)
{
如果(如NewItems!=null)
{
foreach(e.NewItems中的T项)
{
如果(项!=null)
item.PropertyChanged+=ItemOnPropertyChanged;
}
}
如果(例如,OldItems!=null)
{
foreach(e.OldItems中的T项)
{
如果(项!=null)
item.PropertyChanged-=ItemOnPropertyChanged;
}
}
}
私有无效项OnPropertyChanged(对象发送方,PropertyChangedEventArgs e)
=>ItemChanged?.Invoke(发送方,e);
公共事件属性ChangedEventHandler项已更改;
}
您的问题不是很清楚-您当前的实现会发生什么?有错误吗?我们应该注意的断点分析?如何在Xaml中实现绑定
在提供更多信息之前,以下是您提供的一般答案
我将充分利用Prism MVVM对您的ReceiptViewModel进行以下更改
public class ReceiptViewModel : BindableBase
{
private ObservableCollection<Service> _services;
public ObservableCollection<Service> Services
{
get { return _services; }
set { SetProperty(ref _services, value); }
}
private decimal _total;
public decimal Total
{
get { return _total; }
set { SetProperty(ref _total, Services.Sum(s => s.Price)); }
}
public DelegateCommand PriceChangedCommand {get; set;}
public ReceiptViewModel()
{
PriceChangedCommand = new DelegateCommand(OnPriceChanged);
}
private void OnPriceChanged()
{
Total = Services.Sum(s=>s.Price);
}
}
安装下面的Nuget软件包--Microsoft.Xaml.Behaviors.Wpf
我试图遵循@Haukinger和@Bandook的建议,我做到了这一点
模型
public class Service
{
public string Name { get; set; }
public decimal Price { get; set; }
}
扩展模型的视图模型
public class ServiceViewModel : Service, INotifyPropertyChanged
{
private decimal price;
public event PropertyChangedEventHandler PriceChanged;
public event PropertyChangedEventHandler PropertyChanged;
public ServiceViewModel()
{
}
public ServiceViewModel(decimal value)
{
this.price = value;
}
public new decimal Price
{
get { return price; }
set
{
price = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string price = null)
{
PriceChanged?.Invoke(this, new PropertyChangedEventArgs(price));
}
}
主视图模型
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
private string _firstName = "TABET AOUL";
public string FirstName
{
get { return _firstName; }
set { SetProperty(ref _firstName, value, ()=> RaisePropertyChanged(nameof(FullName))); }
}
private string _lastName = "Abdelkrim";
public string LastName
{
get { return _lastName; }
set { SetProperty(ref _lastName, value, () => RaisePropertyChanged(nameof(FullName))); }
}
public string FullName => $"{FirstName} {LastName}";
private ObservableCollection<ServiceViewModel> _services = new ObservableCollection<ServiceViewModel>();
public ObservableCollection<ServiceViewModel> Services
{
get { return _services; }
set { SetProperty(ref _services, value, () => RaisePropertyChanged(nameof(Total))); }
}
public decimal Total => Services.Sum(s => s.Price);
public DelegateCommand AddServiceCommand { get; set; }
public void AddService()
{
var item = new ServiceViewModel { Name = "Service", Price = 100 };
item.PriceChanged += Item_PriceChanged;
Services.Add(item);
RaisePropertyChanged(nameof(Total));
}
public MainWindowViewModel()
{
var item = new ServiceViewModel { Name = "Service", Price = 100 };
item.PriceChanged += Item_PriceChanged;
Services.Add(item);
AddServiceCommand = new DelegateCommand(new Action(AddService));
}
private void Item_PriceChanged(object sender, PropertyChangedEventArgs e)
{
RaisePropertyChanged(nameof(Total));
}
}
公共类MainWindowViewModel:BindableBase
{
私有字符串_title=“Prism应用程序”;
公共字符串标题
{
获取{return\u title;}
集合{SetProperty(ref _title,value);}
}
私有字符串_firstName=“TABET AOUL”;
公共字符串名
{
获取{return\u firstName;}
set{SetProperty(ref _firstName,value,()=>RaisePropertyChanged(nameof(FullName));}
}
私有字符串_lastName=“Abdelkrim”;
公共字符串姓氏
{
获取{return\u lastName;}
set{SetProperty(ref _lastName,value,()=>RaisePropertyChanged(nameof(FullName));}
}
公共字符串FullName=>$“{FirstName}{LastName}”;
私有ObservableCollection_服务=新ObservableCollection();
公共收集服务
{
获取{return\u services;}
set{SetProperty(ref _services,value,()=>RaisePropertyChanged(nameof(Total));}
}
公共十进制总数=>Services.Sum(s=>s.Price);
公共DelegateCommand AddServiceCommand{get;set;}
公共服务()
{
var item=newserviceviewmodel{Name=“Service”,Price=100};
item.PriceChanged+=item_PriceChanged;
服务。添加(项目);
RaisePropertyChanged(名称(总数));
}
公共主窗口视图模型()
{
var item=newserviceviewmodel{Name=“Service”,Price=100};
item.PriceChanged+=item_PriceChanged;
服务。添加(项目);
AddServiceCommand=新的DelegateCommand(新操作(AddService));
}
私有无效项\u价格已更改(对象发送方,PropertyChangedEventArgs e)
{
RaisePropertyChanged(名称(总数));
}
}
代码似乎工作得很好,当我更改一个集合项目的价格时,除了添加新项目外,UI中的总更改量,因此我在clickcommand上调用了RaisePropertyChanged手动更改
欢迎有更优雅解决方案的人希望这能有所帮助:)我更改了一个价格
此更改是来自数据库还是来自用户?数据库是否可以自行更改(即用户不做任何事情)?@Haukinger我编辑了我的问题,价格是s
public class Service
{
public string Name { get; set; }
public decimal Price { get; set; }
}
public class ServiceViewModel : Service, INotifyPropertyChanged
{
private decimal price;
public event PropertyChangedEventHandler PriceChanged;
public event PropertyChangedEventHandler PropertyChanged;
public ServiceViewModel()
{
}
public ServiceViewModel(decimal value)
{
this.price = value;
}
public new decimal Price
{
get { return price; }
set
{
price = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string price = null)
{
PriceChanged?.Invoke(this, new PropertyChangedEventArgs(price));
}
}
public class MainWindowViewModel : BindableBase
{
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
private string _firstName = "TABET AOUL";
public string FirstName
{
get { return _firstName; }
set { SetProperty(ref _firstName, value, ()=> RaisePropertyChanged(nameof(FullName))); }
}
private string _lastName = "Abdelkrim";
public string LastName
{
get { return _lastName; }
set { SetProperty(ref _lastName, value, () => RaisePropertyChanged(nameof(FullName))); }
}
public string FullName => $"{FirstName} {LastName}";
private ObservableCollection<ServiceViewModel> _services = new ObservableCollection<ServiceViewModel>();
public ObservableCollection<ServiceViewModel> Services
{
get { return _services; }
set { SetProperty(ref _services, value, () => RaisePropertyChanged(nameof(Total))); }
}
public decimal Total => Services.Sum(s => s.Price);
public DelegateCommand AddServiceCommand { get; set; }
public void AddService()
{
var item = new ServiceViewModel { Name = "Service", Price = 100 };
item.PriceChanged += Item_PriceChanged;
Services.Add(item);
RaisePropertyChanged(nameof(Total));
}
public MainWindowViewModel()
{
var item = new ServiceViewModel { Name = "Service", Price = 100 };
item.PriceChanged += Item_PriceChanged;
Services.Add(item);
AddServiceCommand = new DelegateCommand(new Action(AddService));
}
private void Item_PriceChanged(object sender, PropertyChangedEventArgs e)
{
RaisePropertyChanged(nameof(Total));
}
}