Reputation: 83
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".
General column resizing (no particular order)
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.
Upvotes: 2
Views: 416
Reputation: 125197
Relying on an owner-drawn ListView which I shared in my other answer is a better idea; however, just for the users who for any reason cannot change their solution, here is a solution based on adding ProgressBar controls to the Listview and adjusting control position based on sub-item position and size.
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);
}
}
Upvotes: 1
Reputation: 125197
You can set the OwnerDraw property of the ListView to true. Then customize drawing of the sub items and for your specific column, draw a ProgressBar. To draw a ProgressBar, you can use ProgressBarRenderer or your own custom paint logic.
Example
The highlights of the code:
Here is the code:
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;
}
}
Upvotes: 2