[C#][WPF]IEditableCollectionViewの動きを見てみよう
前回で、IEditableCollectionViewにどんなメソッドがあるかを見ていった。
今回は、それぞれのメソッドの動きを見ていこうと思う。
とりあえずいつもどおり調査のための下準備のプロジェクトを新規作成する。作成するプロジェクトは、コンソールアプリケーションで、名前をEditableCollectionViewEduにした。
WPF関連のクラスを使うので、PresentationCore, PresentationFramework, WindowsBaseの3つを参照設定に追加する。
そして、いつものPersonクラスを追加しておく。
今回はIEditableCollectionViewの動きを見るだけなのでNameプロパティだけにした。
public class Person
{
public string Name { get; set; }
public override string ToString()
{
return "Person: Name = " + Name;
}
}
ついでに、IEditableObjectを実装させた阪のPersonクラスも定義しておく。Personを継承してさくっとね。
public class EditablePerson : Person, IEditableObject
{
private EditablePerson back;
#region IEditableObject メンバ
public void BeginEdit()
{
Console.WriteLine("# BeginEdit Called: " + this);
back = (EditablePerson)MemberwiseClone();
}
public void CancelEdit()
{
Console.WriteLine("# CancelEdit Called: " + this);
if (back == null)
{
return;
}
Name = back.Name;
}
public void EndEdit()
{
Console.WriteLine("# EndEdit Called: " + this);
back = null;
}
#endregion
}
次に、Mainメソッドにテスト用のPersonクラスのリストを作って、CollectionViewSourceのGetDefaultViewメソッドでListCollectionViewのインスタンスを取得する。
static void Main(string[] args)
{
// テスト用のListCollectionViewを作成
var people = Enumerable.Range(1, 10).Select(i =>
new Person { Name = "田中 太郎" + i }).ToList();
var view = CollectionViewSource.GetDefaultView(people);
// 型の確認
Console.WriteLine(view.GetType());
}
実行すると、「System.Windows.Data.ListCollectionView」と表示される。
このListCollectionViewがIEditableCollectionViewを実装している。こいつをIEditableCollectionViewにキャストして色々調査していこうと思う。
とりあえず、編集系のメソッドとプロパティの動きを見てみるために下のようなプログラムを書いた。
// テスト用のListCollectionViewを作成
var people = Enumerable.Range(1, 10).Select(i =>
new Person { Name = "田中 太郎" + i }).ToList();
var view = CollectionViewSource.GetDefaultView(people);
// IEditableCollectionViewにキャストするよ
var editableView = (IEditableCollectionView)view;
// 編集系
// とりあえず最初の人のインスタンスとっとく
var targetPerson = people[0];
// 編集前のIEditableCollectionViewの状態を表示
Dump("編集前", editableView);
// EditItemで編集中の状態にする
Console.WriteLine("BeginEdit 呼出し前");
editableView.EditItem(targetPerson);
Console.WriteLine("BeginEdit 呼出し後");
// 編集中のIEditableCollectionViewの状態を表示
Dump("編集中", editableView);
// 確定してみる
Console.WriteLine("CommitEdit 呼出し前");
editableView.CommitEdit();
Console.WriteLine("CommitEdit 呼出し後");
// 確定後のIEditableCollectionViewの状態を表示
Dump("確定後", editableView);
途中で使ってるDumpメソッドは、IEditableCollectionViewの編集に関係しそうなプロパティを表示する。
private static void Dump(string msg, IEditableCollectionView editableView)
{
Console.WriteLine("------------------------------");
Console.WriteLine(" " + msg);
Console.WriteLine(" IEditableCollectionView");
Console.WriteLine(" :CanCencelEdit: " + editableView.CanCancelEdit);
Console.WriteLine(" :IsEditingItem: " + editableView.IsEditingItem);
Console.WriteLine(" :CurrentEditItem: " + editableView.CurrentEditItem);
}
色々書いているけど、このプログラムの目的は、EditItemの呼出し前後のプロパティの変化と、CommitEdit呼出し後のプロパティの変化を観察するのが目的です。
予想としては、この例ではPersonオブジェクトはIEditableObjectを実装してないので、キャンセルとかは出来ないようになってるけど、編集中かどうかという状態管理だけは、してくれてるんじゃないかな?といった感じ。
実際に、実行してみると、下のような結果になりました。
------------------------------
編集前
IEditableCollectionView
:CanCencelEdit: False
:IsEditingItem: False
:CurrentEditItem:
BeginEdit 呼出し前
BeginEdit 呼出し後
------------------------------
編集中
IEditableCollectionView
:CanCencelEdit: False
:IsEditingItem: True
:CurrentEditItem: Person: Name = 田中 太郎1
CommitEdit 呼出し前
CommitEdit 呼出し後
------------------------------
確定後
IEditableCollectionView
:CanCencelEdit: False
:IsEditingItem: False
:CurrentEditItem:
編集前段階では、キャンセルできない、編集中ではない、編集中のアイテムも無いという状態です。(当然だよね)
そして、BeginEditを呼び出すと、キャンセルは出来ない、編集中の状態である、編集対象は田中 太郎1さんです、といった状態に変化している。
キャンセルが出来ないのは、PersonクラスがIEditableObjectではないからということになる。
んで、CommitEditを呼び出すと、最初の状態に戻ってる。
キャンセルが出来ないのを確認するために、プログラムにちょこっと手を入れて下のようにしてみた。
// テスト用のListCollectionViewを作成
var people = Enumerable.Range(1, 10).Select(i =>
new Person { Name = "田中 太郎" + i }).ToList();
var view = CollectionViewSource.GetDefaultView(people);
// IEditableCollectionViewにキャストするよ
var editableView = (IEditableCollectionView)view;
// 編集系
// とりあえず最初の人のインスタンスとっとく
var targetPerson = people[0];
// 編集開始
editableView.EditItem(targetPerson);
Console.WriteLine("編集対象の人のデータ: " + targetPerson);
Console.WriteLine("変更後の名前を入力してください");
Console.Write("# >");
// 名前を変更
targetPerson.Name = Console.ReadLine();
Console.WriteLine(targetPerson + "にしてよろしいですか?Y/N");
Console.Write("# >");
string answer = Console.ReadLine();
if (answer == "Y")
{
// Yなら確定!
editableView.CommitEdit();
}
else
{
// Y以外ならキャンセル
editableView.CancelEdit();
}
// 最終結果を表示
Console.WriteLine("編集後の値: " + targetPerson);
コレクションに10個もデータを突っ込みつつ、使ってるのが最初の1つだけというのが気になるけど気にしないで実行。
編集対象の人のデータ: Person: Name = 田中 太郎1
変更後の名前を入力してください
# >田中 一郎
Person: Name = 田中 一郎にしてよろしいですか?Y/N
# >Y
編集後の値: Person: Name = 田中 一郎
これは問題ない。次に編集結果をキャンセルするような操作をしてみると…
編集対象の人のデータ: Person: Name = 田中 太郎1
変更後の名前を入力してください
# >田中 麻呂
Person: Name = 田中 麻呂にしてよろしいですか?Y/N
# >N
ハンドルされていない例外: System.InvalidOperationException: CancelEdit は現在の
編集項目に対してサポートされていません。
場所 System.Windows.Data.ListCollectionView.CancelEdit()
場所 EditableCollectionViewEdu.Program.Main(String[] args) 場所 C:\Users\Kazu
ki\Documents\Visual Studio 2008\Projects\EditableCollectionViewEdu\EditableColle
ctionViewEdu\Program.cs:行 49
という例外が出てしまう。どうやら、キャンセルできないものをキャンセルしようとすると例外になるみたいです。気をつけないと。
次に、PersonをEditablePersonに差し替えてみる。
// テスト用のListCollectionViewを作成
var people = Enumerable.Range(1, 10).Select(i =>
new EditablePerson { Name = "田中 太郎" + i }).ToList();
これで、キャンセルも出来るはず!?ということで実行。とりあえず、CommitEditを通るオペレーションで試す。
# BeginEdit Called: Person: Name = 田中 太郎1
編集対象の人のデータ: Person: Name = 田中 太郎1
変更後の名前を入力してください
# >大田
Person: Name = 大田にしてよろしいですか?Y/N
# >Y
# EndEdit Called: Person: Name = 大田
編集後の値: Person: Name = 大田
問題ない。次はCancelEditの場合。
# BeginEdit Called: Person: Name = 田中 太郎1
編集対象の人のデータ: Person: Name = 田中 太郎1
変更後の名前を入力してください
# >わんくま 太郎
Person: Name = わんくま 太郎にしてよろしいですか?Y/N
# >N
# CancelEdit Called: Person: Name = わんくま 太郎
編集後の値: Person: Name = 田中 太郎1
お~ちゃんとキャンセルされてる!!