C# 通知ViewModel集合中的对象已选定
考虑以下对象,WPF MVVM应用程序的一部分:C# 通知ViewModel集合中的对象已选定,c#,wpf,mvvm,inotifypropertychanged,C#,Wpf,Mvvm,Inotifypropertychanged,考虑以下对象,WPF MVVM应用程序的一部分: public class MyObject : INotifyPropertyChanged { // INotifyPropertyChanged gubbins private bool _isSelected; public bool IsSelected { get { return _isSelected; } se
public class MyObject : INotifyPropertyChanged
{
// INotifyPropertyChanged gubbins
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
及其在以下ViewModel中的使用:
public class MyViewModel : INotifyPropertyChanged
{
// INotifyPropertyChanged gubbins
private List<MyObject> _myObjects;
public List<MyObject> MyObjects
{
get
{
return _myObjects;
}
set
{
_myObjects = value;
OnPropertyChanged("MyObjects");
}
}
public bool CanDoSomething
{
get
{
return MyObjects.Where(d => d.IsSelected).Count() > 0;
}
}
}
公共类MyViewModel:INotifyPropertyChanged
{
//INotifyPropertyChanged gubbins
私有列表(myObjects);;
公共列表对象
{
得到
{
返回_myObjects;
}
设置
{
_myObjects=值;
关于财产变更(“MyObject”);
}
}
公共图书馆
{
得到
{
返回MyObjects.Where(d=>d.IsSelected).Count()>0;
}
}
}
在这种情况下,我可以跟踪选择了哪些对象,选择它们将激发OnPropertyChanged,从而通知父视图
但是,CandoMething将始终为false,因为我无法启动OnPropertyChanged来创建通知。如果我把它放在MyObject中,它对属性一无所知,所以什么也不做。在ViewModel中无处放置它,因为在选择列表中的对象时没有任何反应
我试着用列表代替ObservableCollection和定制的“TrulyObservableCollection”(请参阅),但两者都不起作用
我怎样才能绕过这个问题,而不诉诸点击事件?我觉得如果我对您的最终目标有了更好的了解,我可能会推荐一种更好的方法。有些事情让人觉得有点不对劲。就像“CandoMething”应该是命令对象的一部分一样。我想知道是否一次可以选择多个
MyObject
?如果不是的话,我会用完全不同的方式来处理这个问题
因此,不管怎样,只要MyObjects
中的某个项的IsSelected
属性发生更改,您就需要随时更新candomething
。听起来好像您曾经使用过一个observeableCollection
,然后放弃了它。那是个错误。您需要在两个事件中的任何一个发生时更新CandoMething
;第一个是在MyObjects
中添加或删除项目时,第二个是在MyObjects
中任何对象的IsSelected
属性发生更改时。对于第一个事件,您需要实现INotifyCollectionChanged
,即observedcollection
。您已经涵盖了第二个事件,因为对象实现了INotifyPropertyChanged
。所以你只需要把这两件事结合起来
在下面的示例中,我使用了您的代码并进行了一些更改。首先,我将MyObjects
更改为observedcollection
。它没有setter,因为我发现通常没有很好的理由更改可观察的集合;只需根据需要添加和删除对象。然后在viewmodel的构造函数中,我注册了MyObjects
的CollectionChanged
事件。在该处理程序中,我将抓取添加到集合中的项,并将其PropertyChanged
事件连接到OnSelectedChanged
事件处理程序,并将从集合中删除的任何对象的PropertyChanged
事件从OnSelectedChanged
中取消挂钩。由于项目已被添加或删除,我们不知道IsSelected
的状态可能是MyObjects
中对象的状态,因此这是更新CanDoSomething
的好机会,我在事件处理程序的底部执行此操作。最后,ONISelectedChanged的是另一半魔法发生的地方。MyObjects
中的每个对象都将其属性更改
事件连接到此事件处理程序。只要这些对象中任何一个的IsSelected
属性发生更改,事件处理程序就会更新candomething
public class MyViewModel : INotifyPropertyChanged
{
// INotifyPropertyChanged gubbins
public MyViewModel()
{
this._myObjects.CollectionChanged += (o, e) =>
{
if (e.NewItems != null)
{
foreach (var obj in e.NewItems.OfType<MyObject>())
{
obj.PropertyChanged += this.OnIsSelectedChanged;
}
}
if (e.OldItems != null)
{
foreach (var obj in e.OldItems.OfType<MyObject>())
{
obj.PropertyChanged -= this.OnIsSelectedChanged;
}
}
if (e.PropertyName == "IsSelected")
{
this.CanDoSomething = this.MyObjects.Any(x => x.IsSelected);
}
};
}
private readonly ObservableCollection<MyObject> _myObjects =
new ObservableCollection<MyObject>();
public ObservableCollection<MyObject> MyObjects
{
get
{
return _myObjects;
}
}
private void OnIsSelectedChanged(object o, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsSelected")
{
this.CanDoSomething = this.MyObjects.Any(x => x.IsSelected);
}
}
private bool _canDoSomething;
public bool CanDoSomething
{
get { return this._canDoSomething; }
private set
{
if (_canDoSomething != value)
{
_canDoSomething = value;
OnPropertyChanged("CanDoSomething");
}
}
}
}
公共类MyViewModel:INotifyPropertyChanged
{
//INotifyPropertyChanged gubbins
公共MyViewModel()
{
此._myObjects.CollectionChanged+=(o,e)=>
{
如果(如NewItems!=null)
{
foreach(e.NewItems.OfType()中的var obj)
{
obj.PropertyChanged+=此.onSelectedChanged;
}
}
如果(例如,OldItems!=null)
{
foreach(e.OldItems.OfType()中的var obj)
{
obj.PropertyChanged-=this.onSelectedChanged;
}
}
如果(e.PropertyName==“IsSelected”)
{
this.CanDoSomething=this.MyObjects.Any(x=>x.IsSelected);
}
};
}
私有只读可观察收集对象=
新的可观察集合();
公共可观测集合对象
{
得到
{
返回_myObjects;
}
}
SelectedChanged上的私有void(对象o,PropertyChangedEventArgs e)
{
如果(e.PropertyName==“IsSelected”)
{
this.CanDoSomething=this.MyObjects.Any(x=>x.IsSelected);
}
}
私人布尔(bool_)canDoSomething ;;
公共图书馆
{
获取{返回此。_canDoSomething;}
专用设备
{
if(_canDoSomething!=值)
{
_CandoMething=值;
OnPropertyChanged(“CandoMething”);
}
}
}
}
我觉得如果我对您的最终目标有了更好的了解,我可能会推荐一种更好的方法。有些事情让人觉得有点不对劲。就像“CandoMething”应该是命令对象的一部分一样。我想知道是否一次可以选择多个MyObject
?如果不是的话,我将以完全不同的方式来处理这个问题
public static class ItemClickCommand
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand),
typeof(ItemClickCommand), new PropertyMetadata(null, OnCommandPropertyChanged));
public static void SetCommand(DependencyObject d, ICommand value)
{
d.SetValue(CommandProperty, value);
}
public static ICommand GetCommand(DependencyObject d)
{
return (ICommand)d.GetValue(CommandProperty);
}
private static void OnCommandPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var control = d as ListViewBase;
if (control != null)
control.ItemClick += OnItemClick;
}
private static void OnItemClick(object sender, ItemClickEventArgs e)
{
var control = sender as ListViewBase;
var command = GetCommand(control);
if (command != null && command.CanExecute(e.ClickedItem))
command.Execute(e.ClickedItem);
}
}