通知ViewModel已选择集合中的对象

时间:2016-02-29 15:43:21

标签: c# wpf mvvm inotifypropertychanged

考虑以下对象,它是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),但都不起作用。

如何在不诉诸点击事件的情况下解决这个问题?

2 个答案:

答案 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事件从集合中删除的任何对象。由于已添加或删除了项目,因此我们不知道OnIsSelectedChangedIsSelected的对象的状态是什么,所以这是更新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/

让我知道它是否有效