实现自己的ObservableCollection

时间:2016-10-13 11:11:08

标签: c# wpf observablecollection

对于我的WPF项目,我需要一个始终保持正确顺序的可观察集合。我的想法是使用SortedSet<T>并实施我自己的AddAndNotifyRemoveAndNotify方法。在其中,我会打电话给NotifyPropertyChanged,就像这样:

public class ObservableSortedSet<T> : SortedSet<T>, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }

    public void AddAndNotify(T element)
    {
        Add(element);
        NotifyPropertyChanged(...);
    }

    public void RemoveAndNotify(T element)
    {
        Remove(element);
        NotifyPropertyChanged(...);
    }
}

但是那个属性(或属性)会是什么?

如何在集合内容发生变化时实现一个告诉UI更新的集合?

或者在ViewModel中直接使用SortedSet是否有更简单的方法?

编辑:

我不想将预定义的ObservableCollection与排序视图一起使用。我知道这可以使用CollectionViewSource或转换器,但这些解决方案对我没有吸引力。我有CollectionViewSource不起作用的层次结构数据,我认为转换器版本是CollectionViewSource限制的可怕解决方法。我想使用一个干净的解决方案。

所以这个问题不是how to sort ObservableCollection的重复。我不想对ObservableCollection进行排序,我想使用可以告知用户界面更改的SortedSet

3 个答案:

答案 0 :(得分:5)

您应该实现INotifyCollectionChanged Interface

About

答案 1 :(得分:3)

我设法这样做了:

public class ObservableSortedSet<T> : SortedSet<T>, INotifyCollectionChanged where T : IComparable<T>
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public new void Add(T element)
    {
        base.Add(element);
        CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public override void Clear()
    {
        base.Clear();
        CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    public new void Remove(T element)
    {
        base.Remove(element);
        CollectionChanged?.Invoke(this,
            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

为什么我总是将Reset操作作为EventArg?

  • Remove的原因:如果集合没有索引(请参阅Implementing INotifyCollectionChanged on a collection without indexesObservable Stack and Queue - 似乎无法使用 - 在这两种情况下,归结为无法指定正确的索引,导致运行时错误。请查看答案下方的所有评论“索引xyz对我不起作用!”。)

  • Add的原因:在内部,集合IS已排序,但UI未正确反映此情况。我的猜测是,通过提供EventArg new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, element);,GUI只会被告知新元素应该添加到结尾。

根据https://msdn.microsoft.com/en-us/library/system.collections.specialized.notifycollectionchangedaction(v=vs.100).aspxReset代表“收藏内容发生了巨大变化”。这对SortedSet来说是正确的,因为如果只添加或删除一个元素,其内部结构可能会发生很大变化。所以也许我的解决方案甚至不是一种解决方法(即使它感觉就像一个)!

答案 2 :(得分:0)

您可以使用CollectionViewSource:

<td class="text-center">
<?php

$url=get_curl_content_tx("http://example.com/". $order->order_id);          
$arr = json_decode($url, true);     
if (is_array($arr['data']) || is_object($arr['data'])) {
        foreach($arr['data'] as $data ) {                   
            $match = false;
            if ($data['amount'] == $order->amount) {                    
                    $match = $data;
                    break;
            }
        }
        if($match !== false ) {

            if( .. ) {
                 // do something
            }
            else {      
                // do something else
            }                 
        }
        else { }    
}    
?>
</td>

然后,按照您需要的属性对其进行排序:

<Window.Resources>
    <CollectionViewSource x:Key="yourViewSource" source="{Binding YourCollection}"/>
</Window.Resources>

将其绑定为ItemSource:

CollectionViewSource yourViewSource=
            ((CollectionViewSource)(this.FindResource("yourViewSource")));
yourViewSource.SortDescriptions.Add(new SortDescription("SortByProperty", ListSortDirection.Descending));