考虑以下对象,它是WPF MVVM应用程序的一部分:
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;
}
}
}
在这种情况下,我可以跟踪我选择了哪些对象,选择它们将触发OnPropertyChanged,因此可以通知父视图。
然而,CanDoSomething总是假的,因为我无处可以触发OnPropertyChanged来创建通知。如果我把它放在MyObject中,它对该属性一无所知,所以什么都不做。没有地方可以将它放在ViewModel中,因为当选择列表中的对象时没有任何反应。
我尝试用List代替ObservableCollection和自定义的“TrulyObservableCollection”(参见Notify ObservableCollection when Item changes),但都不起作用。
如何在不诉诸点击事件的情况下解决这个问题?
答案 0 :(得分:1)
我觉得如果我对你的最终目标有了更好的了解,我可能会推荐一种更好的方法。有一些东西正在发生,感觉有点不合适。就像'CanDoSomething'应该是命令对象的一部分。我想知道是否一次选择多个MyObject
?如果没有,那么我会以完全不同的方式接近它。
所以,无论如何,只要CanDoSomething
中某个项目的IsSelected
属性发生变化,您就希望更新MyObjects
。听起来你曾经在某个时刻使用过ObservableCollection
然后放弃它。那是个错误。您需要在两个事件中的任何一个发生时更新CanDoSomething
;第一个是在MyObjects
中添加或删除项目时,第二个是IsSelected
中任何对象的MyObjects
属性发生更改时。对于第一个事件,您需要实现INotifyCollectionChanged
的内容,即ObservableCollection
。您已经涵盖了第二个事件,因为对象实现了INotifyPropertyChanged
。所以你只需将这两件事结合起来。
在下面的示例中,我已经使用了您的代码并进行了一些更改。首先,我将MyObjects
更改回ObservableCollection<MyObject>
。它没有setter因为我发现通常没有充分的理由改变可观察的集合;只需根据需要添加和删除对象。然后在viewmodel的构造函数中,我注册了CollectionChanged
的{{1}}事件。在该处理程序中,我抓取添加到集合中的项目并将其MyObjects
事件挂钩到PropertyChanged
事件处理程序,我正在从OnIsSelectedChanged
取消PropertyChanged
事件从集合中删除的任何对象。由于已添加或删除了项目,因此我们不知道OnIsSelectedChanged
中IsSelected
的对象的状态是什么,所以这是更新MyObjects
的好机会,而且我在事件处理程序的底部。最后,CanDoSomething
是另一半魔法发生的地方。 OnIsSelectedChanged
中的每个对象都会将其MyObjects
事件连接到此事件处理程序。每当任何这些对象上的PropertyChanged
属性发生更改时,事件处理程序都将更新IsSelected
。
CanDoSomething
答案 1 :(得分:1)
首先创建一个定义此附加属性的类:
RDS
然后将此附加属性绑定到视图模型中的委托命令: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);
}
}
您可以在此博文中找到更多详细信息:https://marcominerva.wordpress.com/2013/03/07/how-to-bind-the-itemclick-event-to-a-command-and-pass-the-clicked-item-to-it/
让我知道它是否有效