C # Изменить ListView Высота элемента / строки - PullRequest
18 голосов
/ 03 июля 2011

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

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

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

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

Спасибо!

Ответы [ 6 ]

24 голосов
/ 06 февраля 2015

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

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

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

SetHeight(lvConnections, 25);
15 голосов
/ 03 июля 2011

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

enter image description here

14 голосов
/ 04 июля 2011

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

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

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

enter image description here

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

4 голосов
/ 06 ноября 2017

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

Ответ, который вы приняли, - это интеграция огромного проекта (с демонстрациями и документацией 3,3 МБ).Но только для установки высоты строки 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

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

ListViewEx.RowHeight sample

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

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

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

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

3 голосов
/ 13 октября 2014

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

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

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

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

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)

1 голос
/ 17 марта 2017

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

Межстрочный интервал в 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>
}
...