C# изменение высоты элемента/строки ListView

Я хочу изменить высоту элемента / строки в listview.

Я искал повсюду и я понял, что для того, чтобы изменить высоту мне нужно использовать LBS_OWNERDRAWFIXED или MeasureItem или что-то подобное.

проблема в том, что я не знаю, что делать и как ее использовать..
Кто-нибудь может мне помочь?

Edit:
Я не могу использовать imagelist hack, потому что я использую SmallImageList для реального, и мне нужна другая высота строки из размера изображений ImageList.

спасибо!

6 ответов


это можно сделать с помощью SmallImageList фишка -- вы просто должны быть осторожны. ObjectListView -- оболочка с открытым исходным кодом вокруг стандартного .NET ListView -- использует этот трюк для успешной реализации RowHeight собственность.

если вы хотите 32 пикселя для каждой строки, выделите ImageList это 16x32 (ширина x высота), а затем расположите каждое из ваших изображений в вертикальной середине высоты 32 пикселей.

этот снимок экрана показывает 32-пиксельные строки и слово обертывание, которое возможно из-за дополнительного пространства:

enter image description here

ObjectListView делает всю эту работу для вас. На самом деле, если вы пытаетесь что-то сделать с ListView, вы должны серьезно взглянуть на использование . Это делает многие сложные вещи (например, сортировка по типу столбца, пользовательские подсказки) тривиальными, и несколько невозможных вещей (например, наложения, группы в виртуальных списках) возможно.


для людей, которые все еще борются с этим, вот код, который я использую:

private void SetHeight(ListView listView, int height)
{
    ImageList imgList = new ImageList();
    imgList.ImageSize = new Size(1, height);
    listView.SmallImageList = imgList;
}

чтобы использовать это, просто сделай:

SetHeight(lvConnections, 25);

вы должны использовать немного взломать. Хитрость заключается в использовании списка изображений в свойстве StateImageList. ListView будет регулировать высоту элемента на основе высоты свойства Imagelist's ImageSize. Вам не нужно указывать изображение для ваших элементов, но просто с помощью StateImageList заставит ListView настроить. В приведенном ниже примере я установил размер списка изображений в 32x32, что привело к 32px height ListViewItem(s).

enter image description here


высота строки по умолчанию ListView (в режиме просмотра отчета) вычисляется на основе размера шрифта элемента управления.

Итак, чтобы выбрать высоту строки, выберите шрифт с правильной высотой в свойствах ListView. Например, выберите MS без засечек 18.

затем вы можете изменить шрифт, используемый по всем пунктам: при вставке нового элемента задайте его свойство font.

чтобы оптимизировать назначение шрифта, вы должны объявить шрифт элемента как частный член форма:

Private Font stdfont = new Font( "Consolas", 9.0f, FontStyle.Regular );

затем при добавлении элементов :

ListViewItem i = new ListViewItem( "some text" );
i.Font = stdfont;
MyListView.Items.Add( i );

этот трюк является единственным простым, позволяющим иметь меньшую высоту линии ;) я.Е. установить размер шрифта для 7 и установить размер шрифта элементов до 10. (Протестировано с VS 2008)


к сожалению никто не ответил на ваш исходный вопрос, как использовать LBS_OWNERDRAWFIXED за все эти годы.

ответ, который вы приняли, - это интеграция огромного проекта (с демонстрациями и документацией 3,3 MB). Но только для установки высоты строки ListView это преувеличено.

другой обходной путь, предложенный здесь (добавление ImageList), работает только до увеличить высота строки. Но это не позволяет действительно установить RowHeight независимо от изображения высота. Дополнительно высота строки по умолчанию зависит от операционной системы. Например, в Windows 7 строки намного выше, чем в XP. Вы не можете сделать их плотнее, только выше.

но с очень немногими линиями, вы можете делать то, что вы хотите. Просто скопируйте и вставьте следующий класс:

using System;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ExtendedControls
{

public class ListViewEx : ListView
{
    #region Windows API

    /*
    struct MEASUREITEMSTRUCT 
    {
        public int    CtlType;     // Offset = 0
        public int    CtlID;       // Offset = 1
        public int    itemID;      // Offset = 2
        public int    itemWidth;   // Offset = 3
        public int    itemHeight;  // Offset = 4
        public IntPtr itemData;
    }
    */

    [StructLayout(LayoutKind.Sequential)]
    struct DRAWITEMSTRUCT
    {
        public int    ctlType;
        public int    ctlID;
        public int    itemID;
        public int    itemAction;
        public int    itemState;
        public IntPtr hWndItem;
        public IntPtr hDC;
        public int    rcLeft;
        public int    rcTop;
        public int    rcRight;
        public int    rcBottom;
        public IntPtr itemData;
    }

    // LVS_OWNERDRAWFIXED: The owner window can paint ListView items in report view. 
    // The ListView control sends a WM_DRAWITEM message to paint each item. It does not send separate messages for each subitem. 
    const int LVS_OWNERDRAWFIXED = 0x0400;
    const int WM_SHOWWINDOW      = 0x0018;
    const int WM_DRAWITEM        = 0x002B;
    const int WM_MEASUREITEM     = 0x002C;
    const int WM_REFLECT         = 0x2000;

    #endregion

    bool mb_Measured = false;
    int  ms32_RowHeight = 14;

    /// <summary>
    /// Constructor
    /// </summary>
    public ListViewEx()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
    }

    /// <summary>
    /// Sets the row height in Details view
    /// This property appears in the Visual Studio Form Designer
    /// </summary>
    [Category("Appearance")]  
    [Description("Sets the height of the ListView rows in Details view in pixels.")] 
    public int RowHeight
    {
        get { return ms32_RowHeight; }
        set 
        { 
            if (!DesignMode) Debug.Assert(mb_Measured == false, "RowHeight must be set before ListViewEx is created.");
            ms32_RowHeight = value; 
        }
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams k_Params = base.CreateParams;
            k_Params.Style |= LVS_OWNERDRAWFIXED;
            return k_Params;
        }
    }

    /// <summary>
    /// The messages WM_MEASUREITEM and WM_DRAWITEM are sent to the parent control rather than to the ListView itself.
    /// They come here as WM_REFLECT + WM_MEASUREITEM and WM_REFLECT + WM_DRAWITEM
    /// They are sent from Control.WmOwnerDraw() --> Control.ReflectMessageInternal()
    /// </summary>
    protected override void WndProc(ref Message k_Msg)
    {
        base.WndProc(ref k_Msg); // FIRST

        switch (k_Msg.Msg)
        {
            case WM_SHOWWINDOW: // called when the ListView becomes visible
            {
                Debug.Assert(View == View.Details, "ListViewEx supports only Details view");
                Debug.Assert(OwnerDraw == false,   "In ListViewEx do not set OwnerDraw = true");
                break;
            }
            case WM_REFLECT + WM_MEASUREITEM: // called once when the ListView is created, but only in Details view
            {
                mb_Measured = true;

                // Overwrite itemHeight, which is the fifth integer in MEASUREITEMSTRUCT 
                Marshal.WriteInt32(k_Msg.LParam + 4 * sizeof(int), ms32_RowHeight);
                k_Msg.Result = (IntPtr)1;
                break;
            }
            case WM_REFLECT + WM_DRAWITEM: // called for each ListViewItem to be drawn
            {
                DRAWITEMSTRUCT k_Draw = (DRAWITEMSTRUCT) k_Msg.GetLParam(typeof(DRAWITEMSTRUCT));
                using (Graphics i_Graph = Graphics.FromHdc(k_Draw.hDC))
                {
                    ListViewItem i_Item = Items[k_Draw.itemID];

                    Color c_BackColor = i_Item.BackColor;
                    if (i_Item.Selected) c_BackColor = SystemColors.Highlight;
                    if (!Enabled)        c_BackColor = SystemColors.Control;

                    using (SolidBrush i_BackBrush = new SolidBrush(c_BackColor))
                    {
                        // Erase the background of the entire row
                        i_Graph.FillRectangle(i_BackBrush, i_Item.Bounds);
                    }

                    for (int S=0; S<i_Item.SubItems.Count; S++)
                    {
                        ListViewItem.ListViewSubItem i_SubItem = i_Item.SubItems[S];

                        // i_Item.SubItems[0].Bounds contains the entire row, rather than the first column only.
                        Rectangle k_Bounds = (S>0) ? i_SubItem.Bounds : i_Item.GetBounds(ItemBoundsPortion.Label);

                        // You can use i_Item.ForeColor instead of i_SubItem.ForeColor to get the same behaviour as without OwnerDraw
                        Color c_ForeColor = i_SubItem.ForeColor;
                        if (i_Item.Selected) c_ForeColor = SystemColors.HighlightText;
                        if (!Enabled)        c_ForeColor = SystemColors.ControlText;

                        TextFormatFlags e_Flags = TextFormatFlags.NoPrefix | TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine;
                        switch (Columns[S].TextAlign)
                        {
                            case HorizontalAlignment.Center: e_Flags |= TextFormatFlags.HorizontalCenter; break;
                            case HorizontalAlignment.Right:  e_Flags |= TextFormatFlags.Right; break;
                        }

                        TextRenderer.DrawText(i_Graph, i_SubItem.Text, i_SubItem.Font, k_Bounds, c_ForeColor, e_Flags);
                    }
                }
                break;
            }
        }
    }
} // class
} // namespace

после добавления ListViewEx в форму вы увидите новое свойство в конструкторе форм Visual Studio, которое позволяет задать высоту строки в пиксели:

Setting RowHeight in a C# ListView

значение, которое вы вводите там будет высота строки в пикселях, и это будет уважаться exatctly на всех операционных системах. Я тестировал его на Windows XP, 7 и 10:

ListViewEx.RowHeight sample

кроме того, мой класс имеет еще два преимущества перед исходным ListView: он рисует фликер-свободный и он уважает ForeColor и шрифт установить в ListViewSubItem что игнорируется исходным Microsoft ListView. Таким образом, вы можете нарисовать каждую ячейку с другим цветом и шрифтом.

важно: как говорит MSDN LBS_OWNERDRAWFIXED была разработана только для просмотра подробностей (представление отчета). Мой код работает только для этого режима, и это потому, что Microsoft разработала его таким образом.

дополнительно обратите внимание, что настройка ListView.OwnerDraw = true - это совершенно другая вещь, чем через LVS_OWNERDRAWFIXED.

Я не реализовал рисование иконы, потому что мне это не нужно. Но вы можете легко добавить это.


Plasmabubble имеет правильную идею. Это расширяет это и то, что я использую для использования узкой ширины линии для элементов.

пространство строк в ListView зависит от шрифта ListView и не может быть изменено. Однако вы можете установить шрифт для элементов в ListView на что-то большее, чем шрифт ListView.

Если вы хотите, чтобы он был пропорциональным, создайте шрифт на основе шрифта элемента. Я хочу, чтобы высота элемента была 90% от нормальной, независимо от шрифта выбранный.

когда я заполняю список, я использовал шрифт, хранящийся в настройках, но вы также можете использовать буквальный шрифт, такой как"Consolas".

lvResults.Font = 
   new Font(Properties.Settings.Default.usrHookFont.FontFamily, 
      (float)(Properties.Settings.Default.usrHookFont.Size * .9));

foreach (HookSet item in resultSet)
   {
      ListViewItem lvi = new ListViewItem();
      lvi.Font = Properties.Settings.Default.usrHookFont;
      <dot><dot><dot>
}