-----------------------------------------
本投稿は下記のシリーズの一部です。
【WPF】ListBoxやDataGridをグループ化表示する。
http://pro.art55.jp/?eid=1303859
------------------------------------------ ----------------------ItemsControl.ItemsSourceプロパティにIEnumerableインターフェースを継承するオブジェクトを代入することにより、ItemsControlのコンテンツを生成することができます。ItemsControl.ItemsSourceプロパティで指定したコレクションをフィルター処理、ソート処理、グループ化処理が実施されたコレクションがItemsControl.Itemsの各アイテムとして公開さ、ListBoxの表示対象となります。
----------------------
と、以前に書きましたが、これの動きを今回は確認したいと思います。
たとえば、とある街に売り出し物件があったとします。
物件には
・東から西方向へ番号が付けれれています(Address)
・売り出し価格が付いています(Price)
・売り出し中または既に売れているフラグがあります(IsSele)
・一戸建て・アパート・ビルの3タイプがあります。(Type)
これをクラスで表すと
class House
{
public House(int address, int price, bool isSale, HouseType type)
{
Address = address;
Price = price;
IsSale = isSale;
Type = type;
}
public int Address { get; private set; }
public int Price { get; private set; }
public bool IsSale { get; private set; }
public HouseType Type { get; private set; }
}
enum HouseType
{
Single,
Apartment,
Building,
}
と書くことにしました。さらに、実際の家々を表現するために東から物件を列挙する事ができるコレクションクラス(今回のサンプルコードでは実際には入れた順になっています。)を作成します。今回はZ地区に関する情報を取得するGetAreaZメソッドを用意しています。MyList<T>クラスはIEnumerableインターフェイスを継承するジェネリッククラスです。MyList<T>クラスの詳細に関してはSource and Projectをご覧ください。
class HouseCollection : MyList<House>
{
public static HouseCollection GetAreaZ()
{
return new HouseCollection
{
new House(1, 100, true, HouseType.Single),
new House(2, 150, true, HouseType.Single),
new House(3, 90, true, HouseType.Single),
new House(4, 3000, true, HouseType.Building),
new House(5, 2000, false, HouseType.Apartment),
new House(6, 100, true, HouseType.Single),
new House(5, 2000, true, HouseType.Apartment),
new House(6, 170, false, HouseType.Single),
new House(7, 3000, false, HouseType.Apartment),
new House(8, 2500, false, HouseType.Apartment),
new House(9, 20000, true, HouseType.Building),
new House(10, 200000, false, HouseType.Apartment),
new House(11, 10000, true, HouseType.Single),
new House(12, 1000, true, HouseType.Single),
};
}
}
さて、このZ地区の物件の一覧を見たいユーザがいました。彼の要求は以下の通りです。
・一覧表示であること。
・各物件の「タイプ」「住所」「値段」が表示されていること。
・一戸建て・アパート・ビルのそれぞれのタイプ別に分かれていること。
・各タイプで価格の安い順にならんでいること。
・売り出し中のものだけがみたい。
これを満たすようにItemsControlを設定したのが下記のコードです。
class Program
{
[STAThread]
static void Main()
{
var itemsControl = new ItemsControl();
itemsControl.Items.SortDescriptions.Add(new SortDescription("Price", new ListSortDirection()));
if (itemsControl.Items.GroupDescriptions != null)
itemsControl.Items.GroupDescriptions.Add(new PropertyGroupDescription("Type"));
itemsControl.Items.Filter += Filter;
itemsControl.ItemsSource = HouseCollection.GetAreaZ();
foreach (House house in itemsControl.Items)
{
Console.WriteLine("Type:" + house.Type + " Address:" + house.Address + " Price:" + house.Price);
}
}
static bool Filter(object item)
{
var house = item as House;
if (house == null)
return false;
return house.IsSale;
}
}
実際に、実行してみると
Type:Single Address:3 Price:90
Type:Single Address:6 Price:100
Type:Single Address:1 Price:100
Type:Single Address:2 Price:150
Type:Single Address:12 Price:1000
Type:Single Address:11 Price:10000
Type:Apartment Address:5 Price:2000
Type:Building Address:4 Price:3000
Type:Building Address:9 Price:20000
今回は目的は
ItemsControl.ItemsSourceにコレクションを代入したら、そのコレクションがソート処理、フィルター処理、グループ化処理が実施されたあと要素が、ItemsControl.Itemsのコレクションの各要素にオブジェクトが設定されることを確認することが目的でしたが、実際に確認できました。
考察を深めていくと、ItemsSourceに設定したIEnumerableインターフェイスを継承するオブジェクトとItemsControl.Itemsで公開されているItemsCollectionの関係は下記の用になっていますことに気づきます。
GoFのデザインパターンで言うところのProxyパターンになっています。つまり、「ItemsCollectionは、Watcherの知りたいことを、HouseCollectionに代行して答えている。」と解釈できます。また、HouseCollectionにたいしてのソート・フィルタ・グループ化の機能拡張として見ればDecoratorパターンに当たると思います。
少し余談がながくなりましたが、とりあえずItemsControl.Itemsの確認がとれたので今回はここでいったん止めます。