C# 更改 ListView 项目/行的高度

发布于 2024-11-18 09:59:25 字数 262 浏览 3 评论 0原文

我想更改列表视图中项目/行的高度。

我搜索了所有地方,我发现为了改变高度,我需要使用 LBS_OWNERDRAWFIXED 或 MeasureItem 或类似的东西。

问题是我不知道到底要做什么以及如何使用它..
有人可以帮我吗?

编辑:
我无法使用 ImageList hack,因为我实际使用的是 SmallImageList,并且我需要与 ImageList 图像大小不同的行高。

谢谢!

I want to change the Item's/Row's height in listview.

I searched every where and I figured that in order to change the height I need to use LBS_OWNERDRAWFIXED or MeasureItem or something like that.

The problem is that I dont know exactly what to do and how to use it..
Can anyone help me with it?

Edit:
I cant use the ImageList hack because I am using the SmallImageList for real and I need different line height from the ImageList images size.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

埋葬我深情 2024-11-25 09:59:25

对于仍在为此苦苦挣扎的人,这是我使用的代码:

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

要使用它,只需执行以下操作:

SetHeight(lvConnections, 25);

For the people that are still struggling with this, here is the code I use:

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

To use this, just do:

SetHeight(lvConnections, 25);
世界等同你 2024-11-25 09:59:25

你必须使用一些技巧。诀窍是在 StateImageList 属性中使用图像列表。 ListView 将根据 ImageList 的 ImageSize 属性的高度调整其项目高度。您不必为项目指定图像,但仅使用 StateImageList 将强制 ListView 进行调整。在下面的示例中,我将图像列表大小设置为 32x32,从而生成 32px 高度的 ListViewItem。

在此处输入图像描述

You have to use a bit of a hack. The trick is to use an image list in the StateImageList property. The ListView will adjust its item height, based on the height of the ImageList's ImageSize property. You do not have to specify an image for your items, but just using the StateImageList will force the ListView to adjust. In the example below, I had set the image list size to 32x32, thus resulting in a 32px height ListViewItem(s).

enter image description here

情感失落者 2024-11-25 09:59:25

这可以使用 SmallImageList 技巧来完成 - 您只需小心即可。 ObjectListView——一个围绕标准 .NET ListView 的开源包装器——使用了这个技巧成功实现 RowHeight 属性。

如果您希望每行 32 像素,请分配一个 16x32(宽 x 高)的 ImageList,然后将每个图像放置在 32 像素高度的垂直中间。

此屏幕截图显示 32 像素行以及由于额外空间而可能的自动换行:

在此处输入图像描述

< code>ObjectListView 为您完成所有这些工作。事实上,如果您尝试使用 ListView 执行任何操作,则应该认真考虑使用 ObjectListView。它使许多困难的事情(例如按列类型排序、自定义工具提示)变得微不足道,并使一些不可能的事情(例如覆盖、虚拟列表上的组)成为可能。

It can be done using the SmallImageList trick -- you just have to be careful. ObjectListView -- an open source wrapper around a standard .NET ListView -- uses that trick to successfully implement a RowHeight property.

If you want 32 pixels for each row, allocate an ImageList that is 16x32 (width x height), and then position each of your images in the vertical middle of the 32-pixel height.

This screen shot shows 32-pixel rows and the word wrapping that is possible because of the extra space:

enter image description here

ObjectListView does all this work for you. In fact, if you are trying to do anything with a ListView, you should seriously looked at using an ObjectListView instead. It makes many difficult things (e.g. sorting by column type, custom tooltips) trivial, and several impossible things (e.g. overlays, groups on virtual lists) possible.

余厌 2024-11-25 09:59:25

遗憾的是,这些年来没有人回答您最初的问题如何使用LBS_OWNERDRAWFIXED

您接受的答案是集成一个巨大的项目(带有演示和文档 3.3MB)。但仅仅为了设置 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 表单设计器中看到一个新属性,该属性允许以像素为单位设置行高:

在 C# ListView 中设置 RowHeight

您输入的值将会有行高以像素为单位,并且在所有操作系统上都将严格遵守。我在 Windows XP、7 和 10 上测试了它:

ListViewEx.RowHeight example

此外,我的类比原始 ListView 还有两个优点:它绘制无闪烁并且尊重ForeColorFontListViewSubItem 中设置,原始 Microsoft ListView 会忽略它们。所以你可以用不同的颜色和字体绘制每个单元格。

重要:正如 MSDN 所说,LBS_OWNERDRAWFIXED设计用于详细信息视图(报告视图)的。我的代码仅适用于这种模式,这是因为微软就是这样设计的。

另外请注意,设置 ListView.OwnerDraw = true 与使用 LVS_OWNERDRAWFIXED 完全不同。

我没有实现绘制图标,因为我不需要它。但您可以轻松添加它。

Sadly nobody answered your original question how to use LBS_OWNERDRAWFIXED in all these years.

The answer that you have accepted is integrating a huge project (with demos and documentation 3,3MB). But just for setting the line height of a ListView this is overbloated.

The other workaround suggested here (adding an ImageList) works only to increase the row height. But it does not allow to really set the RowHeight independent of the image height. Additionally the default row height depends on the operating system. For example on Windows 7 the rows are much higher than on XP. You cannot chose to make them tighter, only higher.

But with very few lines you can do what you want.
Just copy and paste the following class:

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

After adding a ListViewEx to your Form you will see a new property in the Visual Studio Forms Designer which allows to set the row height in pixels:

Setting RowHeight in a C# ListView

The value you enter there will be the row height in pixels and it will be respected exatctly on all operating systems. I tested it on Windows XP, 7 and 10:

ListViewEx.RowHeight sample

Additionally my class has two more advantages over the original ListView: It draws flicker-free and it respects the ForeColor and Font set in ListViewSubItem which is ignored by the original Microsoft ListView. So you can draw each cell with a different color and font.

IMPORTANT: As the MSDN says LBS_OWNERDRAWFIXED has been designed only for Details view (Report view). My code works only for this mode and this is because Microsoft has designed it like that.

Additionally please note that setting ListView.OwnerDraw = true is a completely different thing than using LVS_OWNERDRAWFIXED.

I did not implement drawing icons, because I don't need that. But you can easily add this.

醉生梦死 2024-11-25 09:59:25

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测试)

The default line height of a ListView (in report view mode) is computed based on the control's font size.

So to select the line height, choose a font with the right height in the ListView properties.
For example, select MS Sans Serif 18.

Then you can change the font used by all items:
when you insert a new item, set its font property.

To optimize font assignment you should declare the item font as a private member of the form:

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

Then when adding items :

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

This trick is the only easy one allowing to have SMALLER line height ;)
i.E. set control's font size to 7 and set items' font size to 10.
(Tested with VS 2008 )

当梦初醒 2024-11-25 09:59:25

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>
}

Plasmabubble has the right idea. This expands on that and is what I use to use a narrow line-width for the items.

The linespacing in a ListView is dependent on the ListView's font and can't be changed. However, you can set the font for the items in the ListView to something larger than the ListView's font.

If you want it to be proportional, create a font based on the item's font.
I want the item height to be 90% of normal, whatever the font chosen.

When I populate the list I used a font stored in settings but you could also use a literal font like "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>
}
站稳脚跟 2024-11-25 09:59:25

看了这么多年的答案,一是使用基于ListView的扩展控件,二是使用字体或者图标进行扩展。
如果您的项目已经使用 ListView - 就像我的情况一样,您需要在保持原始图标和字体大小的同时扩展列高 - 我建议
你可以粗略计算出你需要的列高,以及正常图标大小的比例,从而使用透明边框来扩展图标大小,例如如果24x24图标实际上是35高,你可以使用windows Paint 3D来扩展使用画布将图标调整为35x35以保持图标的原始比例,我认为这可能是最节省时间和成本的方法。

After reading the answers for so many years, one is to use ListView based extension controls and the other is to use fonts or icons for extensions.
If your project already uses a ListView -- as in my case, where you need to extend the column height while keeping the original icon and font size -- I suggest
You can roughly calculate the column height you need, and the ratio of the normal icon size, and thus use the transparent border to extend the icon size, e.g. if the 24x24 icon is actually 35 in height, you can use windows paint 3D to extend the icon to 35x35 using the canvas to keep the original ratio of the icon, I think this is probably the most time and cost effective way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文