Silverlight for Windows Phone Toolkit に入っている LongListSelector はお手軽にグループ化したリストが作れて便利ですが、ちょっとはまったので記録として。
もっとも単純な形だと、
public class Book { public string Category { get; set; } public string Name { get; set; } }
こんなクラスがあったとすると、
var books = new Book[] { new Book() { Category = "Cat1", Name = "Book1" }, new Book() { Category = "Cat1", Name = "Book2" }, new Book() { Category = "Cat2", Name = "Book3" }, }; this.LongListSelector1.ItemsSource = from book in books group book by book.Category into c select c;
こんな風にすればグループ化して表示できます。
と思ってたんですが、これじゃダメなんですね。これだとグループヘッダーのところに何も表示されません。
この場合、ItemsSource には System.Linq.IGouping<TKey, TElement> のコレクションを渡していて、Key がグループヘッダー、グループの中身は GetEnumerator() で取得することになります。実際に group by で返ってくるのは IGrouping を実装した System.Linq.Lookup.Grouping クラス(リファレンスには載ってない)なんですが、どうやらこれの Key プロパティとうまくデータバインドできない様子。
Toolkit のサンプルを見ると
public class PublicGrouping<TKey, TElement> : IGrouping<TKey, TElement> { private readonly IGrouping<TKey, TElement> _internalGrouping; public PublicGrouping(IGrouping<TKey, TElement> internalGrouping) { _internalGrouping = internalGrouping; } public override bool Equals(object obj) { PublicGrouping<TKey, TElement> that = obj as PublicGrouping<TKey, TElement>; return (that != null) && (this.Key.Equals(that.Key)); } public override int GetHashCode() { return Key.GetHashCode(); } #region IGrouping<TKey,TElement> Members public TKey Key { get { return _internalGrouping.Key; } } #endregion #region IEnumerable<TElement> Members public IEnumerator<TElement> GetEnumerator() { return _internalGrouping.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _internalGrouping.GetEnumerator(); } #endregion }
こんなクラスを自前で用意して
this.LongListSelector1.ItemsSource = from book in books group book by book.Category into c select new PublicGrouping<string, Book>(c);
と言う風に包んであげています。
なぜそんな事に?
var q = from book in books group book by book.Category into c select c; var group = q.First(); var key = group.Key; // ちゃんと Key の内容を取り出せる var propertyInfo = group.GetType().GetProperty("Key"); // null が返る!
こんな風に試してみました。
System.Linq.Lookup.Grouping クラスは DependectyObject ではありませんから、LongListSelector は内部でリフレクションを使ってデータバインドしてると思います。なので、GetProperty(“Key”) で PropertyInfo が取れないとバインドしようが無いと思いますが、実際に試してみると null が返ってきちゃいます。どうやら Grouping クラスは internal なのでリフレクションでアクセスできない様子。
ちなみに、まったく同じコードを .NET Framework 4 のコンソールアプリケーションと Silverlight 4 で試すとまったく問題なく PropertyInfo が取得できます。Silverlight と WP7 は null になるのかと思ったら、WP7 だけが動作が違うんですね。
分かってしまえばどうということは無いんですけど、ちょっとはまりました。
(というか、最初から public に Grouping クラスを用意しておいてくれたらよかったのに)
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。