winforms 按列宽自动伸展ListView行

carvr3hs  于 2022-11-17  发布在  其他
关注(0)|答案(2)|浏览(198)

我有一个包含一些行的列表视图,并且所有行都有一个progressBar。
调整列宽效果很好(如设计所示),但是,由于它可以轻松地移动行内的文本,因此不会移动进度条、调整其大小或甚至四处移动。

private void fileList_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            foreach (CustomProgressBar p in fileList.Controls.OfType<CustomProgressBar>().ToList())
            {
                if (e.ColumnIndex == 0)
                {
                    p.Width = fileList.Columns[3].Width;
                    p.Left = fileList.Columns[e.ColumnIndex].Width + 400;
                }
                else if (e.ColumnIndex == 1)
                {
                    p.Width = fileList.Columns[3].Width;
                    p.Left = fileList.Columns[e.ColumnIndex].Width + 227;
                }
            }
        }

我想不通,所以这是我唯一的解决办法......“部分有效”。

初始-尚未调整大小x1c 0d1x
第1列已调整大小

常规列大小调整(无特定顺序)

关于根据列位置或宽度自动正确对齐项目,我是否遗漏了什么?
我写的代码在第二列之后没有效果,因为我不能确认它是否在第一列/第二列开始时正确工作。所以我看不出实现它的其余部分有什么意义,如果它设置为失败的话。
任何帮助都是感激不尽的。
.NET框架4.8 / WinForms

**注意:**ProgressBar会回应所有一般的progressBar属性。不同之处只是覆迭的阴影和色彩。仅此而已。

laik7k3q

laik7k3q1#

您可以将ListView的OwnerDraw属性设置为true。然后自定义子项的绘制,并为特定列绘制ProgressBar。若要绘制ProgressBar,可以使用ProgressBarRenderer或您自己的自定义绘制逻辑。

示例

代码的亮点:

  • 设定OwnerDraw = true。
  • 行程DrawColumnHeaders并设定e.DrawDefault = true。
  • 处理DrawSubItems,并为进度列绘制ProgressBar。
  • 为列表视图启用DoubleBuffered(在派生类中或使用反射)。

代码如下:

using System;
using System.Drawing;
using System.Windows.Forms;
public class ListViewProgressBarExample : Form
{
    private ListView listView1;
    private void InitializeComponent()
    {
        listView1 = new ListView();
        listView1.Columns.Add("#", 70);
        listView1.Columns.Add("File name", 200);
        listView1.Columns.Add("Progress", 400);
        listView1.View = View.Details;
        listView1.OwnerDraw = true;
        listView1.Dock = DockStyle.Fill;
        listView1.FullRowSelect = true;
        listView1.DrawSubItem += listView1_DrawSubItem;
        this.Controls.Add(listView1);
        this.Text = "ListView ProgressBar Example";
        this.Size = new Size(800, 500);
        this.Load += ListViewProgressBarExample_Load;
    }
    public ListViewProgressBarExample()
    {
        InitializeComponent();
        listView1.OwnerDraw = true;
        listView1.GetType().GetProperty("DoubleBuffered",
            System.Reflection.BindingFlags.NonPublic |
            System.Reflection.BindingFlags.Instance)
            .SetValue(listView1, true);
        listView1.DrawColumnHeader += (sender, e) => e.DrawDefault = true;
    }
    private void ListViewProgressBarExample_Load(object sender,
        EventArgs e)
    {
        listView1.Items.Add(new ListViewItem(
            new[] { "1", "lorem ipsum.txt", "10" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "2", "dolor sit.txt", "0" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "3", "amet.txt", "30" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "4", "consectetur adipiscing.txt", "70" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "5", "celit.txt", "50" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "6", "adipiscing elit.txt", "100" }));
    }
    private void listView1_DrawSubItem(object sender, 
        DrawListViewSubItemEventArgs e)
    {
        if (e.ColumnIndex == 2)
        {
            var r = e.Bounds;
            r.Inflate(-1, -1);
            ProgressBarRenderer.DrawHorizontalBar(e.Graphics, r);
            r.Inflate(-1, -1);
            int w = r.Width * int.Parse(e.SubItem.Text) / 100;
            ProgressBarRenderer.DrawHorizontalChunks(e.Graphics,
                new Rectangle(r.Left, r.Top, w, r.Height));
            e.DrawText(TextFormatFlags.HorizontalCenter |
                TextFormatFlags.VerticalCenter);
        }
        else
            e.DrawDefault = true;
    }
}
42fyovps

42fyovps2#

依赖于所有者描述的ListView(我在另一个答案中分享过)是一个更好的主意;但是,对于出于任何原因而无法更改其解决方案的用户,这里提供了一个解决方案,该解决方案基于将ProgressBar控件添加到Listview并根据子项位置和大小调整控件位置。

示例

代码亮点:

  • 至少在下列事件中,您需要调整控件大小:可能还有更多
  • 您还需要创建ListView的子类,并处理MouseWheel、VerticalScroll和HorizontalScroll事件(通过处理WM_VSCROLLWM_HSCROLLWM_MOUSEWHEEL消息)。
  • 在子类中,需要隐藏标头后面的控件。(通过发送LVM_GETHEADER消息并使用GetWindowRect获取标头矩形。)
  • 调整控件位置和大小时,还需要考虑AutoScrollPosition

代码如下:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ListViewProgressBarExample : Form
{
    private MyListView listView1;
    private void InitializeComponent()
    {
        listView1 = new MyListView();
        listView1.Columns.Add("#", 50);
        listView1.Columns.Add("File name", 150);
        listView1.Columns.Add("Progress", 200);
        listView1.View = View.Details;
        listView1.Dock = DockStyle.Fill;
        listView1.FullRowSelect = true;
        Controls.Add(listView1);
        Text = "ListView ProgressBar Example";
        Size = new Size(500, 300);
    }
    public ListViewProgressBarExample()
    {
        InitializeComponent();
        listView1.Items.Add(new ListViewItem(
            new[] { "1", "lorem ipsum.txt", "10" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "2", "dolor sit.txt", "0" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "3", "amet.txt", "30" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "4", "consectetur adipiscing.txt", "70" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "5", "celit.txt", "50" }));
        listView1.Items.Add(new ListViewItem(
            new[] { "6", "adipiscing elit.txt", "100" }));
        foreach (ListViewItem item in listView1.Items)
        {
            var p = new ProgressBar();
            p.Value = int.Parse(item.SubItems[2].Text);
            item.SubItems[2].Tag = p;
            if (p != null)
            {
                p.Bounds = item.SubItems[2].Bounds;
                listView1.Controls.Add(p);
                p.SendToBack();
            }
        }
        listView1.ColumnWidthChanged += (sender, args) => AdjustControls();
        listView1.ColumnReordered += (sender, args) => AdjustControls();
        listView1.ColumnWidthChanging += (sender, args) => AdjustControls();
        listView1.Scrolled += (sender, args) => AdjustControls();
        listView1.SizeChanged += (sender, args) => AdjustControls();
    }
    private void AdjustControls()
    {
        foreach (ListViewItem item in listView1.Items)
        {
            foreach (ListViewItem.ListViewSubItem subItem in item.SubItems)
            {
                if (subItem.Tag is Control)
                {
                    var bound = subItem.Bounds;
                    bound.Offset(listView1.AutoScrollOffset);
                    var c = (Control)subItem.Tag;
                    c.Bounds = subItem.Bounds;
                    c.Visible = bound.Top >= listView1.GetHeaderHeight();
                }
            }
        }
    }
}
public class MyListView : ListView
{
    private const int WM_HSCROLL = 0x114;
    private const int WM_VSCROLL = 0x115;
    private const int WM_MOUSEWHEEL = 0x020A;
    public event EventHandler Scrolled;
    private const int LVM_GETHEADER = 0x1000 + 31;
    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(
        IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(
        IntPtr hwnd, out RECT lpRect);
    public int GetHeaderHeight()
    {
        var r = new RECT();
        var hwnd = SendMessage(Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
        if (GetWindowRect(hwnd, out r))
            return r.Bottom - r.Top;
        return -1;
    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
            Scrolled?.Invoke(this, EventArgs.Empty);
    }
}

相关问题