使用ObservableCollection

时间:2018-03-23 23:04:19

标签: c# wpf events data-binding observablecollection

经过大量研究,我对如何实现简单 CollectionChanged事件感到难过。我当前的设置使用INotifyPropertyChanged实现如下:

public class Invasion : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

每个Property都像这样调用NotifyPropertyChanged:

public int myProperty
    {
        get { return _backingMember; }
        set { _backingMember = value; NotifyPropertyChanged(); }
    }

一切都很好。除了: 我需要在ObservableCollection更改时引发事件,而不仅仅是属性。诀窍是,我需要这个超级简单;我不在乎所得到的东西。添加或删除。我不在乎修改了哪个元素,或者如何,如果不是一个,我就不在乎在给定的集合中发生了变化。我需要知道的是如果集合已更改。那就是它。

所以我正在寻找一种超级简单的方法来实现某种类型的CollectionChanged事件。正如我所提到的,我一直在研究" INotifyCollectionChanged",但我在网上发现的一切都非常复杂,有很多自定义处理和诸如此类的东西。我并不需要所有这些,并且如果可能的话,我不希望不必要地混乱我的代码。

截至目前,我有以下(非工作)代码:

public class Invasion : INotifyPropertyChanged, INotifyCollectionChanged
public event NotifyCollectionChangedEventHandler CollectionChanged;

private void NotifyCollectionChanged(/*Need this code*/)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(/* And this Code */));
        }
    }

集合及其属性设置如下:

private ObservableCollection<FearCard> _fearDeck = new ObservableCollection<FearCard>();
private ObservableCollection<EventCard> _eventDeck = new ObservableCollection<EventCard>();
etc...

...
public ObservableCollection<FearCard> FearDeck
    {
        get { return _fearDeck; }
        set {
                _fearDeck = value;
                NotifyPropertyChanged();
                NotifyPropertyChanged("TopFearCard");
                NotifyCollectionChanged();
            }
    }
etc...

同样,如果可能的话,我希望尽可能简单。我需要做的就是在我的集合发生变化时通知,这样xaml数据绑定就会在图像发生变化时更新。

3 个答案:

答案 0 :(得分:0)

您可能只是将CollectionChanged事件订阅传递给myApp.SendMessage('Controller','enableCamera', 'true'); 成员(如果它是唯一应该触发&#34;外部&#34; CollectionChanged事件的成员集合。)

_fearDeck

否则,请查看NotifyCollectionChangedEventArgs构造函数的重载列表,以了解如何实现它。

答案 1 :(得分:0)

通常,最简单的方法是创建一次observable然后使用它(.Clear()/ .Add(...)/ Remove(...))。 然后,您可以直接使用observable的CollectionChanged事件。

class SomeViewModel : ViewModelBase
{
    void SomeMethod ( )
    {
        Obs.Add ( "item" );

        Obs.Clear ( );
    }

    public ObservableCollection<string> Obs { get; } 
     = new ObservableCollection<string> ( );

    public ObservableCollection<string> Obs2 { get; }
     = new ObservableCollection<string> ( );
}

class SomeParentViewModel : ViewModelBase
{
    public SomeParentViewModel ( )
    {
        Child.Obs.CollectionChanged += ( sender, e ) => { /* Handles collection changed logic */ };

        Child.Obs2.CollectionChanged += ( sender, e ) => { /* Handles collection changed logic */ };
    }

    public SomeViewModel Child { get; }
     = new SomeViewModel ( );
}

然后,您可以直接在viewmodel上实现INotifyCollectionChanged并冒泡可观察集合已更改事件:

class SomeViewModel : ViewModelBase, INotifyCollectionChanged
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public SomeViewModel ( )
    {
        Obs.CollectionChanged += (sender, e) => CollectionChanged?.Invoke ( this, e ); // *edit*
    }

    public ObservableCollection<string> Obs { get; } 
     = new ObservableCollection<string> ( );
}

编辑:

由于您只需要在集合更改时显示图片,还有另一种可行的方法,即DependencyObject:

class DisplayOnNotify : DependencyObject
{
    public static INotifyCollectionChanged GetObservable ( DependencyObject obj )
    {
        return (INotifyCollectionChanged)obj.GetValue ( ObservableProperty );
    }

    public static void SetObservable ( DependencyObject obj, INotifyCollectionChanged value )
    {
        obj.SetValue ( ObservableProperty, value );
    }

    // Using a DependencyProperty as the backing store for Observable.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ObservableProperty =
                           DependencyProperty.RegisterAttached ( "Observable", 
                                                                typeof ( INotifyCollectionChanged ), 
                                                                typeof ( DisplayOnNotify ), 
                                                                new FrameworkPropertyMetadata ( propertyChangedCallback ) );

    private static void propertyChangedCallback ( DependencyObject d, DependencyPropertyChangedEventArgs e )
    {
        if ( d is UIElement uiElement && e.NewValue is INotifyCollectionChanged notify )
        {
            notify.CollectionChanged += ( sender, e_ ) => uiElement.Visibility = Visibility.Visible;
        }
    }
}

然后你可以直接在xaml中使用它:

<Image Visibility="Collapsed" local:DisplayOnNotify.Observable="{Binding FearDeck}" />

这将有效地在第一个集合更改事件

上显示您的图像

答案 2 :(得分:0)

collectionchanged事件并不仅仅是为了改变图片。 我能想到的最简单的方法是将图像绑定到从同一视图模型中公开的imagesource属性。 然后,您只需在setter中设置该属性并更改该raise属性。

set {
        _fearDeck = value;
        NotifyPropertyChanged();
        NotifyPropertyChanged("TopFearCard");
        NotifyPropertyChanged("NameofProperyExposingImageSource");
    }

看看你似乎在做什么。 我想也许这张图片是从&#34; top&#34;恐惧卡。 您似乎不太可能尝试更改套牌中的所有照片。

说出你的&#34; top&#34;汽车在集合中的索引为0。您可以将图像控件的ImageSource绑定到FearCard中索引的图片属性。 ICollectionChanged(observablecollection implements)可以通知其中一个对象已更改。强制执行此操作的方法是将observablecollection中的对象设置为自身。 因此,如果TopFearCard是指向其中一个FearCards的属性,您可以执行以下操作:

FearCard[0] = FearCard[0];