- 汎用ジェネリックコレクション ページ一覧
ObservableCollection
System.Collections.ObjectModel.ObservableCollectionクラスは、コレクションに対する挿入・削除・設定を行った際にそれらの変更をクラス外部にイベントとして通知することができるようになっているクラスです。 ObservableCollectionクラスは、ユーザーインターフェイスとコレクションの同期したい場合などに使用されます。
ObservableCollectionクラス自体はCollectionクラスを継承しているため基本的な操作はCollectionクラスと同じですが、要素の移動を行うMoveメソッドが追加されています。 クラス外からは、CollectionChangedイベント(NotifyCollectionChangedEventHandler)に適切なハンドラを設定することで、コレクションに対する変更を検出できます。
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
class Sample {
static void Main()
{
ObservableCollection<int> col = new ObservableCollection<int>();
// コレクション変更のイベントを受け取るハンドラを設定
col.CollectionChanged += PrintCollectionChanged;
// 要素の追加
col.Add(0);
col.Add(1);
col.Add(2);
col.Add(3);
col.Add(4);
Print(col);
// 要素の削除
col.Remove(1);
col.Remove(3);
Print(col);
// 特定の位置にある要素を削除
col.RemoveAt(1);
Print(col);
// 特定の位置にある要素を変更
col[0] = 5;
Print(col);
// 特定の位置に要素を挿入
col.Insert(1, 6);
Print(col);
// 特定の位置にある要素を別の位置に移動
col.Move(2, 0); // インデックス2の要素をインデックス0に移動
Print(col);
}
static void PrintCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Console.WriteLine(e.Action);
}
static void Print(ObservableCollection<int> col)
{
foreach (int e in col) {
Console.Write("{0}, ", e);
}
Console.WriteLine();
}
}
Imports System
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Class Sample
Shared Sub Main()
Dim col As New ObservableCollection(Of Integer)()
' コレクション変更のイベントを受け取るハンドラを設定
AddHandler col.CollectionChanged, AddressOf PrintCollectionChanged
' 要素の追加
col.Add(0)
col.Add(1)
col.Add(2)
col.Add(3)
col.Add(4)
Print(col)
' 要素の削除
col.Remove(1)
col.Remove(3)
Print(col)
' 特定の位置にある要素を削除
col.RemoveAt(1)
Print(col)
' 特定の位置にある要素を変更
col(0) = 5
Print(col)
' 特定の位置に要素を挿入
col.Insert(1, 6)
Print(col)
' 特定の位置にある要素を別の位置に移動
col.Move(2, 0) ' インデックス2の要素をインデックス0に移動
Print(col)
End Sub
Shared Sub PrintCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
Console.WriteLine(e.Action)
End Sub
Shared Sub Print(col As ObservableCollection(Of Integer))
For Each e As Integer In col
Console.Write("{0}, ", e)
Next
Console.WriteLine()
End Sub
End Class
Add Add Add Add Add 0, 1, 2, 3, 4, Remove Remove 0, 2, 4, Remove 0, 4, Replace 5, 4, Add 5, 6, 4, Move 4, 5, 6,
派生クラスからは、Itemsプロパティを参照することで内部コレクションにアクセスすることが出来ます。 また、SetItem, InsertItem, RemoveItem, ClearItemに加え、MoveItemの各メソッドをオーバーライドすることで要素の挿入・削除・設定・移動時の動作を拡張できます。 これらのメソッドをオーバーライドしない場合、既定の動作としてOnCollectionChangedメソッドが呼び出され、CollectionChangedイベントが発生します。
また、ObservableCollectionクラスはINotifyPropertyChangedインターフェイスも実装しています。 派生クラスでOnPropertyChangedメソッドを呼び出すようにすると、PropertyChangedイベントを発生させることが出来るようになります。
INotifyPropertyChangedインターフェイスについてはプロパティ §.プロパティ変更の通知 (INotifyPropertyChanged)を参照してください。
(未整理)
BlockReentrancyメソッドとCheckReentrancyメソッドを使うことで、コレクション変更時の再入試行を禁止できるようになります。 BlockReentrancyメソッドが返すIDisposableオブジェクトが破棄される前にCheckReentrancyを呼び出すと例外InvalidOperationExceptionをスローします。
並べ替え(ソート・リバース)
ObservableCollectionにはSortやReverseといった並べ替えのメソッドは用意されていませんが、拡張メソッドのOrderByメソッドやOrderByDescendingメソッドを使うことでコレクションをソートした結果を得ることが出来ます。
もしくは、Collectionと同様にObservableCollectionを継承して内部のコレクションをソート・リバースするメソッドを追加することが出来ます。 なお、このようにして追加したメソッドを呼び出す場合、ソート・リバースを行い要素が並べ替えられる度にCollectionChangedイベントが発生する点に注意が必要です。
次の例は、ObservableCollectionを継承してSortメソッドとReverseメソッドを実装するものです。
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
class SortableCollection : ObservableCollection<int> {
public void Sort()
{
// IListインターフェイスからArrayListのラッパーを作り、既定のIComparer<int>を使ってソートする
System.Collections.ArrayList.Adapter(this).Sort(System.Collections.Generic.Comparer<int>.Default);
}
public void Reverse()
{
// IListインターフェイスからArrayListのラッパーを作りリバースする
System.Collections.ArrayList.Adapter(this).Reverse();
}
}
class Sample {
static void Main()
{
SortableCollection col = new SortableCollection();
// コレクション変更のイベントを受け取るハンドラを設定
col.CollectionChanged += PrintCollectionChanged;
// 要素の追加
col.Add(3);
col.Add(1);
col.Add(0);
col.Add(2);
col.Add(4);
// ソート
Console.WriteLine("[Sort]");
col.Sort();
Print(col);
// リバース
Console.WriteLine("[Reverse]");
col.Reverse();
Print(col);
}
static void PrintCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Console.WriteLine(e.Action);
}
static void Print(SortableCollection col)
{
foreach (int e in col) {
Console.Write("{0}, ", e);
}
Console.WriteLine();
}
}
Imports System
Imports System.Collections.ObjectModel
Class SortableCollection
Inherits ObservableCollection(Of Integer)
Public Sub Sort()
' IListインターフェイスからArrayListのラッパーを作り、既定のIComparer<int>を使ってソートする
System.Collections.ArrayList.Adapter(Me).Sort(System.Collections.Generic.Comparer(Of Integer).Default)
End Sub
Public Sub Reverse()
' IListインターフェイスからArrayListのラッパーを作りリバースする
System.Collections.ArrayList.Adapter(Me).Reverse()
End Sub
End Class
Class Sample
Shared Sub Main()
Dim col As New SortableCollection()
' コレクション変更のイベントを受け取るハンドラを設定
AddHandler col.CollectionChanged, AddressOf PrintCollectionChanged
' 要素の追加
col.Add(3)
col.Add(1)
col.Add(0)
col.Add(2)
col.Add(4)
' ソート
Console.WriteLine("[Sort]")
col.Sort()
Print(col)
' リバース
Console.WriteLine("[Reverse]")
col.Reverse()
Print(col)
End Sub
Shared Sub PrintCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
Console.WriteLine(e.Action)
End Sub
Shared Sub Print(ByVal col As SortableCollection)
For Each e As Integer In col
Console.Write("{0}, ", e)
Next
Console.WriteLine()
End Sub
End Class
Add Add Add Add Add [Sort] Replace Replace Replace Replace Replace Replace 0, 1, 2, 3, 4, [Reverse] Replace Replace Replace Replace 4, 3, 2, 1, 0,
ReadOnlyObservableCollection
System.Collections.ObjectModel.ReadOnlyObservableCollectionクラスは名前の通り読み取り専用のObservableCollectionとして動作するコレクションクラスです。 ReadOnlyObservableCollectionクラスは、基になるObservableCollectionをコンストラクタで指定する必要があり、このObservableCollectionに対する読み取り操作のみを許可するラッパーとして動作します。 ObservableCollectionクラスがCollectionクラスを継承しているのに対し、ReadOnlyObservableCollectionクラスはReadOnlyCollectionクラスを継承しています。 そのため、基本的な操作はReadOnlyCollectionと同じです。
ReadOnlyObservableCollectionクラスではCollectionChangedイベントはprotectedなイベントとなっているため、ハンドラを設定することは出来ません。 また、ReadOnlyCollectionと同様、基になるObservableCollectionへの変更はそれをラップするReadOnlyObservableCollectionにも反映されます。
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
class Sample {
static void Main()
{
ObservableCollection<int> baseCol = new ObservableCollection<int>();
ReadOnlyObservableCollection<int> col = new ReadOnlyObservableCollection<int>(baseCol);
// コレクション変更のイベントを受け取るハンドラを設定
baseCol.CollectionChanged += PrintCollectionChanged;
baseCol.Add(0);
baseCol.Add(1);
baseCol.Add(2);
Console.WriteLine("Contains 1: {0}", col.Contains(1));
baseCol.Remove(1);
Console.WriteLine("Contains 1: {0}", col.Contains(1));
}
static void PrintCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Console.WriteLine(e.Action);
}
}
Imports System
Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Class Sample
Shared Sub Main()
Dim baseCol As New ObservableCollection(Of Integer)()
Dim col As New ReadOnlyObservableCollection(Of Integer)(baseCol)
' コレクション変更のイベントを受け取るハンドラを設定
AddHandler baseCol.CollectionChanged, AddressOf PrintCollectionChanged
baseCol.Add(0)
baseCol.Add(1)
baseCol.Add(2)
Console.WriteLine("Contains 1: {0}", col.Contains(1))
baseCol.Remove(1)
Console.WriteLine("Contains 1: {0}", col.Contains(1))
End Sub
Shared Sub PrintCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
Console.WriteLine(e.Action)
End Sub
End Class
Add Add Add Contains 1: True Remove Contains 1: False