С# Изменить ListView Элемент/Высота строки
Я хочу изменить высоту элемента/строки в списке.
Я искал все, где бы я ни находился, и я решил, что для изменения высоты мне нужно использовать LBS_OWNERDRAWFIXED
или MeasureItem
или что-то в этом роде.
Проблема в том, что я точно не знаю, что делать и как ее использовать.
Может ли кто-нибудь помочь мне с этим?
Edit:
Я не могу использовать прошивку ImageList, потому что я использую SmallImageList для реального, и мне нужна другая высота строки из размера изображений ImageList.
Спасибо!
Ответы
Ответ 1
Это можно сделать с помощью трюка SmallImageList
- вам просто нужно быть осторожным. ObjectListView - оболочка с открытым исходным кодом вокруг стандартного .NET ListView
- использует этот трюк для успешной реализации свойства RowHeight
.
Если вам нужно 32 пикселя для каждой строки, выделите ImageList
, который равен 16x32 (ширина x высота), а затем поместите каждое из ваших изображений в вертикальную середину высоты в 32 пикселя.
Этот снимок экрана показывает 32-пиксельные строки и перенос слов, которые возможны из-за дополнительного пространства:
![enter image description here]()
ObjectListView
все это работает для вас. На самом деле, если вы пытаетесь что-либо сделать с помощью ListView, вам следует серьезно подумать об использовании ObjectListView
. Это делает множество трудных вещей (например, сортировка по типу столбцов, настраиваемые подсказки) тривиальным и возможно несколько невозможных вещей (например, наложения, группы в виртуальных списках).
Ответ 2
Вам нужно немного взломать. Хитрость заключается в использовании списка изображений в свойстве StateImageList. ListView будет регулировать высоту своего элемента в зависимости от высоты свойства ImageList ImageSize. Вам не нужно указывать изображение для ваших элементов, но просто использование StateImageList заставит ListView настроить. В приведенном ниже примере я установил размер списка изображений в 32x32, что привело к отображению ListViewItem (s) высотой 32px.
![enter image description here]()
Ответ 3
Для людей, которые все еще борются с этим, вот код, который я использую:
private void SetHeight(ListView listView, int height)
{
ImageList imgList = new ImageList();
imgList.ImageSize = new Size(1, height);
listView.SmallImageList = imgList;
}
Для этого просто выполните:
SetHeight(lvConnections, 25);
Ответ 4
Высота строки по умолчанию 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 );
Этот трюк является единственным легким, позволяющим иметь высоту линии SMALLER;)
то есть установите размер шрифта управления до 7 и установите размер шрифта на 10.
(Протестировано с VS 2008)
Ответ 5
Plasmabubble имеет правильную идею. Это расширяется, и это то, что я использую для использования узкой ширины линии для элементов.
Перемещение строк в ListView зависит от шрифта ListView и не может быть изменено. Однако вы можете установить шрифт для элементов в ListView на нечто большее, чем шрифт ListView.
Если вы хотите, чтобы он был пропорционален, создайте шрифт на основе шрифта элемента.
Я хочу, чтобы высота элемента составляла 90% от нормального, независимо от выбранного шрифта.
Когда я заполняю список, я использовал шрифт, хранящийся в настройках, но вы также можете использовать буквенный шрифт, например "Консола".
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>
}
Ответ 6
К сожалению, никто не ответил на ваш оригинальный вопрос, как использовать 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, которое позволяет установить высоту строки в пикселях:
![Установка RowHeight в С# ListView]()
Значение, которое вы вводите там, будет иметь высоту строки в пикселях, и это будет востребовано во всех операционных системах. Я тестировал его в Windows XP, 7 и 10:
![ListViewEx.RowHeight sample]()
Кроме того, мой класс имеет еще два преимущества перед исходным списком ListView: он рисует без мерцания, и он соответствует ForeColor и Шрифту, установленному в ListViewSubItem
, который игнорируется исходным Microsoft ListView. Таким образом, вы можете рисовать каждую ячейку с другим цветом и шрифтом.
ВАЖНО:. Как сообщает MSDN, LBS_OWNERDRAWFIXED
был разработан только для просмотра сведений (представление отчета). Мой код работает только для этого режима, и это связано с тем, что Microsoft разработала его так.
Кроме того, обратите внимание, что установка ListView.OwnerDraw = true
- это совсем другая вещь, чем использование LVS_OWNERDRAWFIXED
.
Я не реализовал рисование значков, потому что мне это не нужно. Но вы можете легко добавить это.