2006年03月14日

ListView にカラム

引き続きシリーズの外。今回は完全に外。@IT の ネイティブアプリとCLRアプリの違い スレッドより。

スレ主さん曰く、Becky! のリストビューは第一カラムが幅固定であると。.NET のプロパティにはそう設定できるプロパティがないと。まあそういうことらしいです。しかし考えてみれば生 API 使うのならもともとプロパティだのなんて存在しませんし、MFC の CListView クラスなどにもそんなのありません。あるのはただ WM_NOTIFY と いくつかのメッセージのみ。別にこの辺がアンマネージドというわけでは、まあありますが、幸いメモリのことは一切勘案することなく、unsafe にもしないで、Marshal クラスも使わず書ける部分です。

WndProc のオーバーライドだって普通に存在しているんだから使わなければ損損。と言う比較的現実主義な私としては早速実装してみるのでした。

///<summary>
///カラム幅の変更を制限できる ListView です。
///</summary>
public class ColumnWidthFixableListView : ListView {
    ///<summary>
    ///サイズの変更を禁止するカラムのインデックスの配列です。
    ///指定したインデックスのカラム右側の仕切りがドラッグできなくなり、
    ///またダブルクリックによる自動調整も不可能になります。
    ///存在しないインデックスが含まれていても問題ありません。
    ///</summary>
    public int[] FixedColumns {
        get { return this.fixedColumns; }
        set { this.fixedColumns = (value == null) ? new int[0] : value; }
    }
    private int[] fixedColumns = new int[0];
    private struct NotifyMessageHeader {
        public IntPtr Window;
        public int Id;
        public int NotifyCode;
        public int ItemIndex;
        public MouseButton MouseButton;
        public IntPtr ItemInfo;
        // 単に警告を黙らせるためだけなので無くて良いコンストラクタ
        public NotifyMessageHeader(int dummy) {
            this.Window = this.ItemInfo = IntPtr.Zero;
            this.Id = this.NotifyCode = this.ItemIndex = 0;
            this.MouseButton = MouseButton.Left;
        }
    }
    private enum MouseButton {
        Left = 0,
        Right = 1,
        Middle = 2,
    }
    protected virtual bool ProcessNotifyMessage(ref Message m) {
        object lParam = m.GetLParam(typeof(NotifyMessageHeader));
        NotifyMessageHeader header = (NotifyMessageHeader)lParam;
        const int BeginTrackW = -326; //HDN_BEGINTRACKW
        const int BeginTrackA = -306; //HDN_BEGINTRACKA
        const int DividerDoubleClickW = -325; //HDCN_DIVIDERDBLCLICKW
        const int DividerDoubleClickA = -305; //HDCN_DIVIDERDBLCLICKA
        switch (header.NotifyCode) {
            //A が来るはずなのに W が来たりなどあるようなのでいっそ全部
            case BeginTrackW : case DividerDoubleClickW :
            case BeginTrackA : case DividerDoubleClickA :
                if (this.fixedColumns == null)
                    break;
                if (Array.IndexOf(this.fixedColumns, header.ItemIndex) != -1) {
                    m.Result = new IntPtr(1);
                    return true;
                }
                break;
        }
        return false;
    }
    protected override void WndProc(ref Message m) {
        if (m.Msg == 0x4E) { //WM_NOTIFY
            if (ProcessNotifyMessage(ref m))
                return;
        }
        base.WndProc(ref m);
    }
}
posted by Hongliang at 05:56| Comment(0) | TrackBack(0) | C# | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/14788140

この記事へのトラックバック

ここ(hongliang.seesaa.net)で公開しているものについて、利用は自由に行って頂いて構いません。改変、再頒布もお好きになさって下さい。利用に対しこちらが何かを要求することはありません。

ただし、公開するものを使用、または参考したことによって何らかの損害等が生じた場合でも、私はいかなる責任も負いません。

あ、こんなのに使ったってコメントを頂ければ嬉しいです。

×

この広告は1年以上新しい記事の投稿がないブログに表示されております。