Home > Net >  Auto-Stretch ListView rows By Column Width
Auto-Stretch ListView rows By Column Width

Time:09-21

I have a listview with some rows, and all have a progressBar.

Adjusting column width works fine (as by design), however as it easily moves text within rows, it does NOT move the progressbar, resize it or even move it around.. without writing this:

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

I couldn't figure it out, so that was my only solution.. which "partially works".

Initial - no resize yet enter image description here

Column 1 resized enter image description here

General column resizing (no particular order) enter image description here

Is there something I am missing about automatically aligning items correctly according to the column position or width?

The code I wrote has zero effect after the 2nd column, as I can not confirm if it is working correctly for column1/column2 to begin with. So I dont see a point implementing the rest of it, if its set to fail anyway.

Any help is appreciated.

.NET Framework 4.8 / WinForms

--

NOTE: ProgressBar responds to all typical properties as would a regular progressBar. The difference is just the overlay shade and color. Nothing more.

CodePudding user response:

You can set the enter image description here

Example

The highlights of the code:

  • Set the OwnerDraw = true.
  • Handle DrawColumnHeaders and set e.DrawDefault = true.
  • Handle DrawSubItems and for the progress column, draw a ProgressBar.
  • Enable enter image description here

    Example

    Highlights of the code:

    Here is the code:

    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);
        }
    }
    
  • Related