Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通知ViewModel集合中的对象已选定_C#_Wpf_Mvvm_Inotifypropertychanged - Fatal编程技术网

C# 通知ViewModel集合中的对象已选定

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

考虑以下对象,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;
        }
    }
}
公共类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); 
    } 
}