スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: スポンサー広告

DataGrid用ViewModelクラスを実装した(弐)。

DataGrid用ViewModelクラスを実装した(壱)。から更に進めていく。
アイテムソースをObservableCollectionEx<T>型にすることで、アイテムの増減を知ることができる。でも、各アイテムのプロパティ値の変更までは検知できない。これを可能にしようと思えば、各アイテムに変更通知機能があるとき(INotifyPropertyChangedインターフェイスを実装している)に限り、ProprtyuChangedイベントにハンドラを登録する必要がある。もちろん、リストから削除されるアイテムに対しては、登録したハンドラを削除する必要がある。削除しないと、当然の様にリークの因子となって残り続ける。

/// <summary>
/// コンストラクタ
/// </summary>
public DataGridVM() {
this.ItemsSource = new ObservableCollectionEx<TItem>();
this.ListViewSource = CollectionViewSource.
GetDefaultView(this.ItemsSource) as ListCollectionView;
//コレクションの変更イベント用ハンドラ
this.ItemsSource.CollectionChanged +=
new NotifyCollectionChangedEventHandler(
ItemsSource_CollectionChanged);
//コレクションクリアイベント用ハンドラ
this.ItemsSource.CleaningItems +=
new EventHandler<CleaningItemsEventArgs<TItem>>(
ItemsSource_CleaningItems);
//Itemの変更通知イベント用ハンドラ(自分用)
this.internalItemPropertyChangedHandler_ =
new PropertyChangedEventHandler(GridItem_PropertyChanged);

return;
}

#region privateメンバ

/// <summary>(内部用)Itemプロパティ変更イベント用ハンドラ</summary>
private PropertyChangedEventHandler internalItemPropertyChangedHandler_;

#endregion

コレクション変更イベントハンドラ

/// <summary>
/// アイテムソースコレクション変更イベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void ItemsSource_CollectionChanged(object sender,
NotifyCollectionChangedEventArgs e) {
//INotifyPropertyChangedインターフェイス実装型のオブジェクト
//が追加や削除された時のみ、プロパティ値変更イベントを登録したり、
//削除したりします。
if (e.OldItems != null && e.OldItems.Count > 0) {
foreach (var oldItem in e.OldItems.OfType<INotifyPropertyChanged>()) {
oldItem.PropertyChanged -= this.itemPropertyChangedHandler_;
}
}

if (e.NewItems != null && e.NewItems.Count > 0) {
foreach (var newItem in e.NewItems.OfType<INotifyPropertyChanged>()) {
newItem.PropertyChanged += this.itemPropertyChangedHandler_;
}
}

return;
}
追加されるアイテムの変更通知イベントにハンドラを登録し、削除されるアイテムの変更通知イベントからハンドラを削除する。クリア(Clear)でもこのイベントは発生するけど、e.OldItemsは空なので、クリア用イベントハンドラが必要になる。

/// <summary>
/// アイテムクリアイベントハンドラ
/// </summary>
/// <param name="sender">イベント発生元</param>
/// <param name="e">イベント引数</param>
private void ItemsSource_CleaningItems(object sender,
CleaningItemsEventArgs<TItem> e) {
//クリアされた時も、イベントハンドラの削除は怠れません。
if (e.ClearedList != null && e.ClearedList.Count > 0) {
foreach (var oldItem in e.ClearedList.OfType<INotifyPropertyChanged>()) {
oldItem.PropertyChanged -= this.itemPropertyChangedHandler_;
}
}
return;
}
こうすることで、リスト内のアイテムのプロパティ値が変更されたら、必ずGridItem_PropertyChangedメソッドが呼び出される事になる。

/// <summary>
/// DataGrid アイテム プロパティ変更イベントハンドラ(内部用)
/// </summary>
/// <param name="sender">変更発生元</param>
/// <param name="e">イベント引数</param>
private void GridItem_PropertyChanged(object sender,
PropertyChangedEventArgs e) {
if (this.IsDisposed) {
return;
}

//アイテムのプロパティ変更を外部(から登録さたリスナ)へ通知します。
if (this.itemPropertyChangedHandler_ != null) {
foreach (PropertyChangedEventHandler handler in
this.itemPropertyChangedHandler_.GetInvocationList()) {
handler(sender, e);
}
}
}

/// <summary>アイテムプロパティ変更イベント用ハンドラ</summary>
protected PropertyChangedEventHandler itemPropertyChangedHandler_;

/// <summary>
/// アイテムプロパティ変更イベント<br/>
/// DataGridのItemのプロパティ値変更を通知するイベントです。<br/>
/// </summary>
public event PropertyChangedEventHandler ItemPropertyChanged {
add {3itemPropertyChangedHandler_ += value;}
remove {itemPropertyChangedHandler_ -= value;}
}
当クラスを使い、アイテムのプロパティ値変更を検知したい時は、ItemPropertyChangedイベントにハンドラを登録するだけとなる。終了時の処理も忘れずに実装する。

/// <summary>
/// 内部リソースを破棄します。
/// </summary>
/// <param name="disposing">false:アンマネージドのみ破棄します。</param>
protected override void OnDispose(bool disposing) {
if (this.IsDisposed) {
return;
}

base.OnDispose(disposing);

if (disposing) {
if (this.ItemsSource != null) {
this.ItemsSource.CollectionChanged -=
new NotifyCollectionChangedEventHandler(
ItemsSource_CollectionChanged);
if (this.ItemsSource.Count > 0) {
this.ItemsSource.Clear();
}

this.ItemsSource.CleaningItems -=
new EventHandler<CleaningItemsEventArgs<TItem>>(
ItemsSource_CleaningItems);
this.ItemsSource = null;
}

if (this.itemPropertyChangedHandler_ != null) {
foreach (PropertyChangedEventHandler handler in
this.itemPropertyChangedHandler_.GetInvocationList()) {
this.itemPropertyChangedHandler_ -= handler;
}
}

this.ListViewSource = null;
this.internalItemPropertyChangedHandler_ = null;
}
return;
}
WPFにしても、Windows.Formsにしても、徹底的にやってはじめてメモリリークを抑制できると思う。
続く。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


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

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

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

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

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。