I have used ProgressBar Control in my c# desktop application.I have used it in a thread other then the thread in which control has been declared.Its working Fine. Now I am w
I have used this simple code, and it works!
for (int i = 0; i < N * N; i++)
{
Thread.Sleep(50);
progressBar1.BeginInvoke(new Action(() => progressBar1.Value = i));
progressBar1.CreateGraphics().DrawString(i.ToString() + "%", new Font("Arial",
(float)10.25, FontStyle.Bold),
Brushes.Red, new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7));
}
It just has one simple problem and this is it: when progress bar start to rising, percentage some times hide, and then appear again. I did't write it myself.I found it here: text on progressbar in c#
I used this code, and it does work.
I tried placing a label with transparent background over a progress bar but never got it to work properly. So I found Barry's solution here very useful, although I missed the beautiful Vista style progress bar. So I merged Barry's solution with http://www.dreamincode.net/forums/topic/243621-percent-into-progress-bar/ and managed to keep the native progress bar, while displaying text percentage or custom text over it. I don't see any flickering in this solution either. Sorry to dig up and old thread but I needed this today and so others may need it too.
public enum ProgressBarDisplayText
{
Percentage,
CustomText
}
class ProgressBarWithCaption : ProgressBar
{
//Property to set to decide whether to print a % or Text
private ProgressBarDisplayText m_DisplayStyle;
public ProgressBarDisplayText DisplayStyle {
get { return m_DisplayStyle; }
set { m_DisplayStyle = value; }
}
//Property to hold the custom text
private string m_CustomText;
public string CustomText {
get { return m_CustomText; }
set {
m_CustomText = value;
this.Invalidate();
}
}
private const int WM_PAINT = 0x000F;
protected override void WndProc(ref Message m)
{
base.WndProc(m);
switch (m.Msg) {
case WM_PAINT:
int m_Percent = Convert.ToInt32((Convert.ToDouble(Value) / Convert.ToDouble(Maximum)) * 100);
dynamic flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis;
using (Graphics g = Graphics.FromHwnd(Handle)) {
using (Brush textBrush = new SolidBrush(ForeColor)) {
switch (DisplayStyle) {
case ProgressBarDisplayText.CustomText:
TextRenderer.DrawText(g, CustomText, new Font("Arial", Convert.ToSingle(8.25), FontStyle.Regular), new Rectangle(0, 0, this.Width, this.Height), Color.Black, flags);
break;
case ProgressBarDisplayText.Percentage:
TextRenderer.DrawText(g, string.Format("{0}%", m_Percent), new Font("Arial", Convert.ToSingle(8.25), FontStyle.Regular), new Rectangle(0, 0, this.Width, this.Height), Color.Black, flags);
break;
}
}
}
break;
}
}
}
I have written a no blinking/flickering TextProgressBar
You can find the source code here: https://github.com/ukushu/TextProgressBar
Samples:
Just want to point out something on @codingbadger answer. When using "ProgressBarRenderer" you should always check for "ProgressBarRenderer.IsSupported" before using the class. For me, this has been a nightmare with Visual Styles errors in Win7 that I couldn't fix. So, a better approach and workaround for the solution would be:
Rectangle clip = new Rectangle(rect.X, rect.Y, (int)Math.Round(((float)Value / Maximum) * rect.Width), rect.Height);
if (ProgressBarRenderer.IsSupported)
ProgressBarRenderer.DrawHorizontalChunks(g, clip);
else
g.FillRectangle(new SolidBrush(this.ForeColor), clip);
Notice that the fill will be a simple rectangle and not chunks. Chunks will be used only if ProgressBarRenderer is supported
I wold create a control named for example InfoProgresBar, that provide this functionality with a label or two (Main Job, Current Job) and ProgressBar and use it instead of that ProgressBar.
I have created a InfoProgressBar control which uses a TransparentLabel control. Testing on a form with a Timer, I get some slight glitches displaying the text every 30-40 value changes if using a timer interval of less than 250 milliseconds (probably because of the time required to update the screen is greater than the timer interval).
It would be possible to modify UpdateText method to insert all the calculated values into CustomText but it isn't something that I have needed yet. This would remove the need for the DisplayType property and enumerate.
The TransparentLabel class was created by adding a new UserControl and changing it to inheriting from Label with the following implementation:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Utils.GUI
{
public partial class TransparentLabel : Label
{
// hide the BackColor attribute as much as possible.
// setting the base value has no effect as drawing the
// background is disabled
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public override Color BackColor
{
get
{
return Color.Transparent;
}
set
{
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
return cp;
}
}
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
if(Parent != null) Parent.Invalidate(Bounds, false);
}
}
public override ContentAlignment TextAlign
{
get
{
return base.TextAlign;
}
set
{
base.TextAlign = value;
if(Parent != null) Parent.Invalidate(Bounds, false);
}
}
public TransparentLabel()
{
InitializeComponent();
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
base.BackColor = Color.Transparent;
}
protected override void OnMove(EventArgs e)
{
base.OnMove(e);
RecreateHandle();
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing
}
}
}
I did not make any changes to the related designer code but here it is for completeness.
namespace Utils.GUI
{
partial class TransparentLabel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}
I then created another new UserControl and changed it to derive from ProgressBar with the following implementation:
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Windows.Forms.Design.Behavior;
namespace Utils.GUI
{
[Designer(typeof(InfoProgressBarDesigner))]
public partial class InfoProgressBar : ProgressBar
{
// designer class to add font baseline snapline by copying it from the label
private class InfoProgressBarDesigner : ControlDesigner
{
public override IList SnapLines
{
get
{
IList snapLines = base.SnapLines;
InfoProgressBar control = Control as InfoProgressBar;
if(control != null)
{
using(IDesigner designer = TypeDescriptor.CreateDesigner(control.lblText, typeof(IDesigner)))
{
if(designer != null)
{
designer.Initialize(control.lblText);
ControlDesigner boxDesigner = designer as ControlDesigner;
if(boxDesigner != null)
{
foreach(SnapLine line in boxDesigner.SnapLines)
{
if(line.SnapLineType == SnapLineType.Baseline)
{
snapLines.Add(new SnapLine(SnapLineType.Baseline, line.Offset, line.Filter, line.Priority));
break;
}
}
}
}
}
}
return snapLines;
}
}
}
// enum to select the type of displayed value
public enum ProgressBarDisplayType
{
Custom = 0,
Percent = 1,
Progress = 2,
Remain = 3,
Value = 4,
}
private string _customText;
private ProgressBarDisplayType _displayType;
private int _range;
[Bindable(false)]
[Browsable(true)]
[DefaultValue("{0}")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
// {0} is replaced with the result of the selected calculation
public string CustomText
{
get
{
return _customText;
}
set
{
_customText = value;
UpdateText();
}
}
[Bindable(false)]
[Browsable(true)]
[DefaultValue(ProgressBarDisplayType.Percent)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public ProgressBarDisplayType DisplayType
{
get
{
return _displayType;
}
set
{
_displayType = value;
UpdateText();
}
}
[Bindable(false)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
// don't use the lblText font as if it is null, it checks the parent font (i.e. this property) and gives an infinite loop
public override Font Font
{
get
{
return base.Font;
}
set
{
base.Font = value;
}
}
[Bindable(false)]
[Browsable(true)]
[DefaultValue(100)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new int Maximum
{
get
{
return base.Maximum;
}
set
{
base.Maximum = value;
_range = base.Maximum - base.Minimum;
UpdateText();
}
}
[Bindable(false)]
[Browsable(true)]
[DefaultValue(0)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new int Minimum
{
get
{
return base.Minimum;
}
set
{
base.Minimum = value;
_range = base.Maximum - base.Minimum;
UpdateText();
}
}
[Bindable(false)]
[Browsable(true)]
[DefaultValue(ContentAlignment.MiddleLeft)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public ContentAlignment TextAlign
{
get
{
return lblText.TextAlign;
}
set
{
lblText.TextAlign = value;
}
}
[Bindable(false)]
[Browsable(true)]
[DefaultValue(typeof(Color), "0x000000")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public Color TextColor
{
get
{
return lblText.ForeColor;
}
set
{
lblText.ForeColor = value;
}
}
[Bindable(false)]
[Browsable(true)]
[DefaultValue(0)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new int Value
{
get
{
return base.Value;
}
set
{
base.Value = value;
UpdateText();
}
}
public InfoProgressBar()
{
InitializeComponent();
CustomText = "{0}";
DisplayType = ProgressBarDisplayType.Percent;
Maximum = 100;
Minimum = 0;
TextAlign = ContentAlignment.MiddleLeft;
TextColor = Color.Black;
Value = 0;
// means the label gets drawn in front of the progress bar
lblText.Parent = this;
_range = base.Maximum - base.Minimum;
}
protected void UpdateText()
{
switch(DisplayType)
{
case ProgressBarDisplayType.Custom:
{
lblText.Text = _customText;
break;
}
case ProgressBarDisplayType.Percent:
{
if(_range > 0)
{
lblText.Text = string.Format(_customText, string.Format("{0}%", (int)((Value * 100) / _range)));
}
else
{
lblText.Text = "100%";
}
break;
}
case ProgressBarDisplayType.Progress:
{
lblText.Text = string.Format(_customText, (Value - Minimum));
break;
}
case ProgressBarDisplayType.Remain:
{
lblText.Text = string.Format(_customText, (Maximum - Value));
break;
}
case ProgressBarDisplayType.Value:
{
lblText.Text = string.Format(_customText, Value);
break;
}
}
}
public new void Increment(int value)
{
base.Increment(value);
UpdateText();
}
public new void PerformStep()
{
base.PerformStep();
UpdateText();
}
}
}
And the designer code:
namespace Utils.GUI
{
partial class InfoProgressBar
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lblText = new Utils.GUI.TransparentLabel();
this.SuspendLayout();
//
// lblText
//
this.lblText.BackColor = System.Drawing.Color.Transparent;
this.lblText.Dock = System.Windows.Forms.DockStyle.Fill;
this.lblText.Location = new System.Drawing.Point(0, 0);
this.lblText.Name = "lblText";
this.lblText.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0);
this.lblText.Size = new System.Drawing.Size(100, 23);
this.lblText.TabIndex = 0;
this.lblText.Text = "transparentLabel1";
this.ResumeLayout(false);
}
#endregion
private TransparentLabel lblText;
}
}