0

C# 4.0 で次のことを行う方法があるかどうかを調べています。

多数のカスタム クラスを含む ObservableCollection があります。それを「MainCollection」と呼びましょう。私のコードの多くは、継続的に MainCollection のこれらのクラスの値を更新しますが、すべて正常に動作します。

「コレクション」[または WPF DataGrid DataContext バインディングで使用するもの] を作成する必要があります。これは、基になるクラスの単一のパラメーターで MainCollection のクラスをグループ化するだけです。

MainCollection のアイテムが更新されるたびに、この新しい「疑似コレクション」も更新されるようにする方法はありますか。

4

6 に答える 6

1

おそらくCollectionView クラスを探しているでしょう:

データ コレクションをグループ化、並べ替え、フィルター処理、およびナビゲートするためのビューを表します。

でも、

コードでこのクラスのオブジェクトを作成しないでください。IEnumerable のみを実装するコレクションのコレクション ビューを作成するには、CollectionViewSource オブジェクトを作成し、コレクションを Source プロパティに追加して、View プロパティからコレクション ビューを取得します。

そのため、開始するのに最適な場所は、How to: Sort and Group Data Using a View in XAMLでしょう。これと他のいくつかのハウツー記事は、CollectionView ページの下部にあります。

于 2012-05-02T20:24:41.057 に答える
1

これを実現するためのオープン ソース フレームワークがいくつかあります。私はBindableLinqを使用して成功しました。ホームページに記載されているように、開発は行き詰まっており、他のフレームワークの代替手段があります。

これらのライブラリは、多数のレベルで依存関係が更新されたときに更新を提供するように設計されています (コレクション自体、またはコレクションが依存する項目のプロパティ、さらには外部依存関係など)。

于 2012-05-02T20:03:10.773 に答える
0

変更イベントをリッスンしてフィルター処理されたコレクションを更新する FilteredCollection を作成できます。これにより、ソース コレクションが変更されるたびに効率的な再フィルター処理が可能になります。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;

namespace ConsoleApplication26
{
    class FilteredObservableCollection<T> : INotifyCollectionChanged, IEnumerable<T>
    {
        List<T> _FilteredCached;
        ObservableCollection<T> Source;
        Func<T,bool> Filter;

        public FilteredObservableCollection(ObservableCollection<T> source, Func<T,bool> filter)
        {
            Source = source;
            Filter = filter;
            source.CollectionChanged += source_CollectionChanged;
        }

        void source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                var addedMatching = e.NewItems.Cast<T>().Where(Filter).ToList();
                _FilteredCached.AddRange(addedMatching);
                if (addedMatching.Count > 0)
                {
                    CollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, addedMatching));
                }
            }
            else // make life easy and refresh fully
            {
                _FilteredCached = null;
                CollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            if (_FilteredCached == null)
            {
                _FilteredCached = Source.Where(Filter).ToList(); // make it easy to get right. If someone would call e.g. First() only 
                // we would end up with an incomplete filtered collection.
            }

            foreach (var filtered in _FilteredCached)
            {
                yield return filtered;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public event NotifyCollectionChangedEventHandler CollectionChanged = (o,e) => { };
    }


    class Program
    {
        static void Main(string[] args)
        {
            ObservableCollection<int> data = new ObservableCollection<int>(new int[] { 1, 2, 3, 4, 1 });
            var filteredObservable = new FilteredObservableCollection<int>(data, x => x > 2);
            Print(filteredObservable); // show that filter works
            data.Add(1);
            Print(filteredObservable); // no change
            data.Add(10);
            Print(filteredObservable); // change
            data.Clear();
            Print(filteredObservable); // collection is empy
            data.Add(5);
            Print(filteredObservable); // add item in filter range
            data[0] = 1;
            Print(filteredObservable); // replace it
        }

        static void Print<T>(FilteredObservableCollection<T> coll)
        {
            Console.WriteLine("Filtered: {0}", String.Join(",", coll));
        }
    }

}

これは印刷されます

Filtered: 3,4
Filtered: 3,4
Filtered: 3,4,10
Filtered:
Filtered: 5
Filtered:
于 2012-05-02T21:22:55.600 に答える
0

オンデマンドで新しいコレクションを作成するプロパティを公開することは可能でしょうか? 何かのようなもの

public List<Whatever> Items
{
    get
    {
        return MainCollection.Where( x => [someCondition] ).ToList();
    }
}
于 2012-05-02T20:03:07.610 に答える
0

MainCollection を更新して、このグループ化機能を追加します

class MainCollection 
{
  public Dictionary<TGroupBySingleParameter, TValue> TheLookup{get; private set;}

  Update()
  {
        TheLookup.Add(//...
        //do work
  }
}
于 2012-05-02T20:17:15.250 に答える
0

つまり、MainCollection のビューを作成したいと考えています。それは LINQ の仕事のようですね!

   var newCollection = from item in MainCollection
        group item  by /*item condintion */ into g //use where for filtering
         select new { Prop = g.Prop, Item = g };  

オブザーバブルが必要な場合は、シーケンスを ctor に渡すだけです。

var observableColl = new ObservableCollection(newCollection);
于 2012-05-02T20:10:05.697 に答える