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とは別のコレクションとして保持する形で作成(´ω`)


っで、これでテクニカルな要素の準備はほぼ終わったので、後は画面制御と業務ロジックをチマチマ書いていきます(・ω・)