请考虑以下对象,它是 WPF MVVM 应用程序的一部分:
public class MyObject : INotifyPropertyChanged
{
// INotifyPropertyChanged gubbins
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
及其在以下视图模型中的使用:
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 中没有地方可以放置它,因为当选择列表中的对象时,没有任何反应。
我尝试将列表替换为可观察集合和自定义"TrulyObservableCollection"(请参阅在项目更改时通知可观察集合),但两者都不起作用。
如何在不诉诸点击事件的情况下解决这个问题?
如果我对你的最终目标有更好的了解,我可能会推荐一个更好的方法。 有些事情只是感觉有点不合适。 就像也许"CanDoSomething"应该是命令对象的一部分。 我想知道是否一次选择多个MyObject
? 如果没有,那么我会以完全不同的方式解决这个问题。
因此,无论如何,您希望随时更新CanDoSomething
MyObjects
中某个项的 IsSelected
属性更改。 听起来您曾经使用过ObservableCollection
然后放弃了它。 这是一个错误。 每当发生两个事件之一时,您需要随时更新CanDoSomething
;第一个是向MyObjects
添加项或从中删除项时,第二个是MyObjects
中任何对象的 IsSelected
属性发生更改时。 对于第一个事件,你需要实现INotifyCollectionChanged
的东西,即ObservableCollection
。 您已经覆盖了第二个事件,因为这些对象实现了INotifyPropertyChanged
。 所以你只需要把这两件事结合起来。
在下面的示例中,我采用了您的代码并进行了一些更改。 首先,我将MyObjects
改回ObservableCollection<MyObject>
。 它没有二传手,因为我发现通常没有充分的理由更改可观察的集合;只需根据需要添加和删除对象即可。 然后在视图模型的构造函数中,我注册了 MyObjects
的CollectionChanged
事件。 在该处理程序中,我正在抓取添加到集合中的项并将其PropertyChanged
事件挂接到OnIsSelectedChanged
事件处理程序,并且我正在从从集合中删除的任何对象的OnIsSelectedChanged
中取消PropertyChanged
事件。 由于已添加或删除项目,我们不知道MyObjects
中对象的IsSelected
状态可能是什么,因此这是更新CanDoSomething
的好机会,我在事件处理程序的底部这样做。 最后,OnIsSelectedChanged
是另一半魔术发生的地方。 MyObjects
中的每个对象都将将其PropertyChanged
事件挂接到此事件处理程序。 每当这些对象中的任何一个的 IsSelected
属性发生更改时,事件处理程序都会更新CanDoSomething
。
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");
}
}
}
}
首先创建一个定义此附加属性的类:
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);
}
}
然后,只需将此附加属性绑定到视图模型中的委托命令:helper:ItemClickCommand.Command="{Binding MyItemClickCommand}"
您可以在这篇博文中找到更多详细信息:https://marcominerva.wordpress.com/2013/03/07/how-to-bind-the-itemclick-event-to-a-command-and-pass-the-clicked-item-to-it/
让我知道它是否有效