C# Изменить ListView Высота элемента / строки
Я хочу изменить высоту элемента / строки в списке.
Я искал везде, и я решил, что для изменения высоты мне нужно использовать LBS_OWNERDRAWFIXED
или же MeasureItem
или что-то типа того.
Проблема в том, что я не знаю точно, что делать и как это использовать..
Кто-нибудь может мне помочь с этим?
Редактировать:
Я не могу использовать взлом ImageList, потому что я использую SmallImageList на самом деле, и мне нужна высота линии, отличная от размера изображений ImageList.
Спасибо!
7 ответов
Это можно сделать с помощью SmallImageList
уловка - вы просто должны быть осторожны. ObjectListView - обертка с открытым исходным кодом вокруг стандартного.NET ListView
- использует этот трюк, чтобы успешно реализовать RowHeight
имущество.
Если вы хотите 32 пикселя для каждой строки, выделите ImageList
это 16x32 (ширина x высота), а затем поместите каждое из ваших изображений в вертикальную середину 32-пиксельной высоты.
Этот снимок экрана показывает 32-пиксельные строки и перенос слов, которые возможны из-за дополнительного пространства:
ObjectListView
делает все это для вас. На самом деле, если вы пытаетесь что-то сделать с помощью ListView, вы должны серьезно взглянуть на использование ObjectListView
вместо. Это делает много сложных вещей (например, сортировку по типу столбца, настраиваемые всплывающие подсказки) тривиальными, а также несколько невозможных вещей (например, наложения, группы в виртуальных списках) возможными.
Для людей, которые все еще борются с этим, вот код, который я использую:
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 отрегулирует высоту своего элемента на основе высоты свойства ImageSist ImageList. Вам не нужно указывать изображение для ваших элементов, но просто с помощью StateImageList заставит ListView настроить. В приведенном ниже примере я установил размер списка изображений равным 32x32, что позволило получить ListViewItem (s) высотой 32 пикселя.
К сожалению, никто не ответил на ваш оригинальный вопрос, как использовать 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 Forms Designer, которое позволяет устанавливать высоту строки в пикселях:
Введенное вами значение будет высотой строки в пикселях и будет строго соблюдаться во всех операционных системах. Я проверил это на Windows XP, 7 и 10:
Кроме того, у моего класса есть еще два преимущества по сравнению с оригинальным ListView: он рисует без мерцания и учитывает ForeColor и Font, установленные в ListViewSubItem
который игнорируется оригинальным Microsoft ListView. Таким образом, вы можете нарисовать каждую ячейку с другим цветом и шрифтом.
ВАЖНО: как говорится в MSDN LBS_OWNERDRAWFIXED
был разработан только для просмотра сведений (представление отчета). Мой код работает только для этого режима, и это потому, что Microsoft разработала его таким образом.
Дополнительно обратите внимание, что настройка ListView.OwnerDraw = true
это совершенно другая вещь, чем использование LVS_OWNERDRAWFIXED
,
Я не реализовывал рисование иконок, потому что мне это не нужно. Но вы можете легко добавить это.
Высота строки по умолчанию для 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 );
Этот трюк является единственным простым, позволяющим иметь меньшую высоту строки;) iE установить размер шрифта элемента управления на 7 и установить размер шрифта элементов на 10. (протестировано с VS 2008)
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>
}
Прочитав ответы за столько лет, один из них должен использовать элементы управления расширениями на основе ListView, а другой - использовать шрифты или значки для расширений. Если в вашем проекте уже используется ListView - как в моем случае, когда вам нужно увеличить высоту столбца, сохранив при этом исходный значок и размер шрифта, - я предлагаю вам приблизительно рассчитать высоту столбца, которая вам нужна, и соотношение нормального размер значка и, таким образом, используйте прозрачную рамку для увеличения размера значка, например, если значок 24x24 на самом деле имеет высоту 35, вы можете использовать Windows Paint 3D, чтобы увеличить значок до 35x35, используя холст, чтобы сохранить исходное соотношение значка, Я думаю, что это, вероятно, самый эффективный и экономичный способ.