Compact FrameworkでListViewのオーナードロー
みたいなものを今日は作っていました(・∀・)
フルスクラッチのカレンダーコントロールも使うけど、オーナードローしたListViewも使うのよ〜。
っで、Compact FrameworkではListViewのオーナードローはサポートされないので、サブクラス化して、WM_NOTIFYメッセージのNM_CUSTOMDRAWを自前で処理するようなかんじで。
昔、Full Frameworkの1.1時代にも同じような事をしていたけれど(・ω・)
ちなみに、下記のListViewDemo.zipなんかにもオーナードローの例があるので、オーナードローしたい人はそれを参考にどうぞ(・∀・)
http://code.msdn.microsoft.com/uiframework/Release/ProjectReleases.aspx?ReleaseId=2315
自分が作っていたListView拡張は、上記の機能に加えてヘッダの色変更とヘッダクリック時のソート機能とかと、後はLVM_***で提供される機能を追加したようなもの。
ヘッダの色変更もオーナードローで処理するのだけど、WM_NOTIFYの処理なので、ListViewに対するオーナードローはParent.Handleへのフック、ヘッダに対するオーナードローはListView自信のHandleに対するフックと2つのフックを設定。
描画自体は色を変えられだけで良かったので、SetTextColor()、SetBkColor()するだけの処理で(´д`)
っで、クリック時のソートは下記の様なコードで対応。
private void OnColumnClick(object sender, ColumnClickEventArgs e) { this.extenders[ e.Column ].Ascending = !this.extenders[ e.Column ].Ascending; IComparer<ListViewItem> comparer = this.extenders[ e.Column ].GetComparer(); int count = Items.Count; BeginUpdate(); List<ListViewItem> list = new List<ListViewItem>(); for( int i = 0; i < count; i++ ) { list.Add( Items[ i ] ); } list.Sort( 0, count, comparer ); Items.Clear(); for( int i = 0; i < count; i++ ) { Items.Add( list[ i ] ); } EndUpdate(); }
一度ListViewItemをListにぶち込んで、Sort()した後に再設定というやりかた。
そんなに大量のデータを扱うつもりは無いのでこれでよし(´д`;)
っで、使い方としては下記の様な感じで。
// データクラス class Data { public int Id { get; set; } public string Text { get; set; } public static int SortById(Data x, Data y, bool ascending) { return x.Id.CompareTo( y.Id ) * ( ascending ? 1 : -1 ); } public static int SortByText(Data x, Data y, bool ascending) { return x.Text.CompareTo( y.Text ) * ( ascending ? 1 : -1 ); } } // 初期化 private void Form1_Load(object sender, EventArgs e) { // ダミーデータ for( int i = 0; i < 100; i++ ) { Data data = new Data() { Id = i, Text = "Data-" + i }; ListViewItem item = new ListViewItem(); item.Text = data.Id.ToString(); item.SubItems.Add( new ListViewItem.ListViewSubItem() { Text = data.Text } ); item.Tag = data; this.listView1.Items.Add( item ); } // ソート関数設定 this.listView1.Extenders[ 0 ].SortFunction = (x, y, a) => Data.SortById( (Data)x.Tag, (Data)y.Tag, a ); this.listView1.Extenders[ 1 ].SortFunction = (x, y, a) => Data.SortByText( (Data)x.Tag, (Data)y.Tag, a ); }
Extendersプロパティは列毎に拡張情報を保持するコレクションで、ヘッダの色やソートファンクションとかを保持。
それらの情報をどう保持しようかと考えたんだけど、お手軽にデザイナ対応するために、Cloumnsとは別のコレクションとして保持する形で作成(´ω`)
っで、これでテクニカルな要素の準備はほぼ終わったので、後は画面制御と業務ロジックをチマチマ書いていきます(・ω・)