LoginSignup
0
0

【C#】 ListView に RowHeight プロパティを追加する

Posted at

今回は、継承したListViewに行の高さを取得や設定するための、RowHeightプロパティを持たせようというお話。

行の高さの設定方法は、下記事に書いてあるので今回は行の高さの取得方法を考える。

今回もテストは.Net8で行っているが、多少表記が違うだけで.Net Frameworkでも実装できると思う。

目次

ListViewItem.Boundsを利用する
ListViewItemがない場合
時間のない人はこちら

ListViewItem.Boundsを利用する

前述の記事 の追記にあるように、ListViewItem.Boundsを利用すると、項目に外接する四角形を取得できる。そこからHeightの値を取得すれば行の高さが取得できそうだ。

上記説明にもある通り、これはlistView.GetItemRect(Index)と同値であり、さらに言えばSendMessage(LVM_GETITEMRECT, index, ref rect)を実行しているに他ならない。

つまり、ListViewItem.Boundsを利用したい場合、項目のIndexが必要となる。
では、項目数が0の場合、つまりListView.Items.count0の時どうすればいいのか。

ListViewItemがない場合

恐らく最も簡単な方法は、適当な項目を追加して、測って、削除する、だと思う。

注意点は、VirtualModeを使用している場合、安易に追加するとInvalidOperationExceptionが発生することだろうか。ただ、VirtualModeの場合は項目を追加する必要は無く、VirtualListSizeを弄るだけで取得することができる。

以上を踏まえて、行の高さを取得するメソッドを作る

int getRowHeight()
{
    var height = 0;
    // 項目があるなら普通に取得
    if (listView.Items.Count > 0)
        height = listView.GetItemRect(0).Height;
    // 仮想モードの場合、VirtualListSizeを使い計測
    else if(listView.VirtualMode)
    {
        listView.VirtualListSize = 1;
        height = listView.GetItemRect(0).Height;
        listView.VirtualListSize = 0;
    }
    // 項目無しかつ仮想モードでもない場合、項目追加で計測
    else
    {
        listView.Items.Add(new ListViewItem());
        height = listView.GetItemRect(0).Height;
        listView.Items.Clear();
    }
    // 高さは外接する四角形よりも1ピクセル小さい
    return height - 1;
}

細かいことを書くと、listView.Columnsが設定されていない場合、上記メソッドは-1を返す。カラムが未設定の場合でも高さを取得したい場合は、項目と同様一度カラムを追加して計測、その後削除を行う必要がある。

今回の内容と、前述の記事の内容を合わせて、RowHeight プロパティを持った継承ListViewのコードを下記に記して、今回の話は終了、お粗末様。

ソースコード

partial class ListViewEx : ListView
{
    int rowHeight;
    public int RowHeight
    {
        get
        {
            if (Items.Count > 0)
                rowHeight = GetItemRect(0).Height;
            else if (VirtualMode)
            {
                VirtualListSize = 1;
                rowHeight = GetItemRect(0).Height;
                VirtualListSize = 0;
            }
            else
            {
                Items.Add(new ListViewItem());
                rowHeight = GetItemRect(0).Height;
                Items.Clear();
            }
            return rowHeight - 1;
        }
        set
        {
            // 0以下には設定しない
            if(value < 1) return;
            
            // WM_MEASUREITEMで使われるrowHeightはBounds.Heightと同値にする
            rowHeight = value + 1;

            var size = Size;
            var style = GetWindowLong(Handle, GWL_STYLE);
            style |= LVS_OWNERDRAWFIXED;
            SetWindowLong(Handle, GWL_STYLE, style);
            Size = new Size(size.Width, size.Height + 1);
            style ^= LVS_OWNERDRAWFIXED;
            SetWindowLong(Handle, GWL_STYLE, style);
            Size = size;
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (WM_MEASUREITEM == m.Msg)
        {
            Marshal.WriteInt32(m.LParam + (sizeof(uint) * 4), rowHeight);
            m.Result = 1;
        }
    }
    const int
        GWL_STYLE = -16,
        LVS_OWNERDRAWFIXED = 0x0400,
        WM_MEASUREITEM = 0x002C + 0x2000;

    [DllImport("user32.dll")]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
}

以下使用方法

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        var listView = new ListViewEx()
        {
            View = View.Details,
            GridLines = true,
            Location = new(12, 12),
            Size = new(350, 150)
        };
        // カラムだけ用意
        listView.Columns.Add(new ColumnHeader() { Text = "test01" });
        Controls.Add(listView);

        // サイズを取得する場合、これはデモなので値は廃棄('_')している
        _ = listView.RowHeight;
        // サイズ変更の場合、RowHeightに代入すると行の高さが変わる
        listView.RowHeight = 10;
    }
}

目次に戻る

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0