BartoszKP
BartoszKP

Reputation: 35891

How to embed ProgressBar into a ListView without WPF?

All internet sources I've found claim that in WinForms the only possibility to achieve this is to create your own UserControl (examples: here, here, here, and here).

Is it possible to achieve this using only provided WinForms controls?

Upvotes: 1

Views: 6552

Answers (1)

BartoszKP
BartoszKP

Reputation: 35891

Yes, it is possible:

  • Create an ImageList and add a Bitmap to it for each item in a list
  • Create a ListView and attach the ImageList created above as a SmallImageList
  • Set ListView style to Details
  • Add as much columns as needed - the first one must contain the picture
  • Add subsequent ListViewItems with appropriate strings for each column and appropriate ImageIndex referencing appropriate Bitmap created in first step

 

//...
{
  foreach (/*item to add to list*/)
  {
    Bitmap progressBarBitmap = new Bitmap(
        this.imageList.ImageSize.Width,
        this.imageList.ImageSize.Height);
    this.imageList.Images.Add(progressBarBitmap);
    ProgressBar progressBar = new ProgressBar();
    progressBar.MinimumSize = this.imageList.ImageSize;
    progressBar.MaximumSize = this.imageList.ImageSize;
    progressBar.Size = this.imageList.ImageSize;

    // probably create also some BackgroundWorker here with information about
    // this particular progressBar

    ListViewItem lvi = new ListViewItem(
        new[] { "column1", ... },
        this.listView.Items.Count);

    lvi.UseItemStyleForSubItems = true;
    this.listView.Items.Add(lvi);
    lvi.Tag = /* some convenient info class to refer back to related objects */
  }
//...
}
  • To refresh the ProgressBar:

 

int previousProgress = progressBar.Value;
progressBar.Value = ...
if (progressBar.Value != previousProgress)
{
  progressBar.DrawToBitmap(progressBarBitmap, bounds);
  progressBarImageList.Images[index] = progressBarBitmap;
}

where progressBarBitmap is the image for the appropriate position (index) in progressBarImageList for the appropriate progressBar (each ListViewItem has it's own ProgressBar assigned, of course).

The key thing is to assign the same image again into the same place in ImageList - this causes a repaint, and without this it doesn't work.

Pros: Quick (not having to write your own UserControl), cheap (there was much investigation to find out about this, but not much code to write eventually), and works

Cons: I've noticed some flickering when there is a large number of items. Also, there are some refreshing issues on Mono.

Example result: enter image description here

Code with an example application: https://github.com/bartoszkp/dotrl (BSD license) - in particular see the BatchExperimentWindow class: https://github.com/bartoszkp/dotrl/blob/master/Application/BatchExperimentWindow.cs

Upvotes: 6

Related Questions