ObservableCollection<T>クラスをちょっと拡張する。

 DataGridのItemsSourceプロパティとよくバインディングされるのが、ObservableCollection<T>クラスだ。このクラスは、アイテムの増減をイベントで通知してくれる機能(INotifyCollectionChangedインターフェイスを実装している)があるので、追加されたアイテムに対する処理、削除されたアイテムに対する処理をイベントハンドラ(メソッド)内でできる。
using System.Collections.ObjectModel;
using System.Collections.Specialized;

/// <summary></summary>
private ObservableCollection<int> list;

//イベントへハンドラメソッドを登録します。
list.CollectionChanged +=
new NotifyCollectionChangedEventHandler(list_CollectionChanged);

/// <summary>
/// list コレクション アイテム数変更イベントハンドラ<br/>
/// アイテム数の増減に伴ってイベントが発生します。<br/>
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void list_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
//ここに処理を実装します。
if (e.OldItems != null) {
}

if (e.NewItems != null) {
}
}

イベント引数(NotifyCollectionChangedEventArgs)には、OldItemsとNewItemsがある。
OldItems:削除されたアイテムリスト
NewItems:追加されたアイテムリスト
となる。便利なクラスなんだけども、ちょっと困るのがClearメソッド。イベントは発生するけど、クリアされた時のアイテムがOldItemsに設定されていない。nullで飛んでくる。Clearされる時のアイテム達に対して、終了処理(Disposeやイベントハンドラの削除)を行いたい時にできない。これはちょっとまずい。処理できないと、メモリリークの原因にもなる。
そこで、その対策として、ObservableCollection<>クラスを拡張する。これって、オリジナルじゃなくて、どこかの記事を見て実装したんだけど、リンクが見つからない…Orz。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace TawamureDays.Container {

/// <summary>
/// ObservableCollection拡張クラス
/// </summary>
/// <remarks>
/// System.Collections.ObjectModel.ObservableCollection<T>クラスをちょっとだけ
/// 拡張するクラスです。<br/>
/// 元記事のリンクをロスト中…。コメントに残すべきだな。Orz<br/>
/// </remarks>
/// <typeparam name="T">コレクション要素の型宣言</typeparam>
public class ObservableCollectionEx<T> : ObservableCollection<T> {

#region コンストラクタ

/// <summary>
/// コンストラクタ
/// </summary>
public ObservableCollectionEx() : base() {
}

/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="newlist">コピー元のリストオブジェクト</param>
public ObservableCollectionEx(List<T> newlist) : base(newlist) {
}

/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="newCollection">コピー元のコレクション</param>
public ObservableCollectionEx(IEnumerable<T> newCollection) : base(newCollection) {
}

#endregion

#region ObservableCollection<T> メンバ

/// <summary>
/// コレクションから全ての項目を削除します。
/// </summary>
protected override void ClearItems() {
//クリアされるリストを確保しましょう。
var clearedList = new List<T>(this);
try {
//リストをクリアしましょう。
base.ClearItems();

//事後にしよう。
try {
//イベント励起
OnCleaning(new CleaningItemsEventArgs<T>(clearedList));
} catch (Exception) {
;//無視か、警告レベルのログを残す
}
} finally {
//後始末
clearedList.Clear();
clearedList = null;
}
return;
}

#endregion

#region イベント

/// <summary>アイテムクリアイベント</summary>
public event EventHandler<CleaningItemsEventArgs<T>> CleaningItems;

#endregion

#region 内部メソッド

/// <summary>
/// アイテムクリア前にイベントを発生させます。<br/>
/// </summary>
/// <param name="e">イベント引数</param>
protected virtual void OnCleaning(CleaningItemsEventArgs<T> e) {
if (CleaningItems != null) {
CleaningItems(this, e);
}
}

#endregion
}

/// <summary>
/// アイテムクリアイベント用引数クラス
/// </summary>
/// <remarks>
/// ObservableCollectionEx<T>クラスのClearItemsメソッド実行時に発生する
/// CleaningItemsイベント用の引数となるクラスです。<br/>
/// </remarks>
public sealed class CleaningItemsEventArgs<T> : System.EventArgs {

#region コンストラクタ

/// <summary>
/// コンストラクタ
/// </summary>
public CleaningItemsEventArgs() : base() {

}

/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="newClearedList">クリア対象だったリスト</param>
public CleaningItemsEventArgs(IList<T> newClearedList) : this() {
this.ClearedList = new ReadOnlyCollection<T>(newClearedList);
}

#endregion

#region プロパティ

/// <summary>
/// クリアされたリストを取得します。
/// </summary>
public ReadOnlyCollection<T> ClearedList {
get; internal set;
}

#endregion
}
}

・内部メソッド(ClearItems)をオーバーライドして、クリアされるリストを確保し、追加実装したイベント(CleaningItems)を発生させる。
・イベント引数に、そのクリアされたリストを設定する。
・イベント引数のリスト(ClearedList)は、ReadOnlyCollection<T>、読み取り専用としている(追加,削除不可)。
・イベント通知が終わったら、リストを削除する。
この追加したイベントに登録したハンドラ(メソッド)は、画面終了時に確実に削除しておく必要がある。
でないと、メモリリークの元となる。CollectionChangedとCleaningItemsという2つのイベントに対して処理を行う事になるが、もうこれは仕方ないかなと。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m