ProgressBarMessager ClassCleanCode C# Libraries v1.2.03 API
Enhances a standard OnlineProgressBar with progress messages that appear sequentially beneath the bar, to provide useful feedback during a lengthy operation.
Inheritance Hierarchy

OnlineSystem Object
  OnlineSystem MarshalByRefObject
    OnlineSystem.ComponentModel Component
      OnlineSystem.Windows.Forms Control
        OnlineSystem.Windows.Forms ScrollableControl
          OnlineSystem.Windows.Forms ContainerControl
            OnlineSystem.Windows.Forms UserControl
              CleanCode.GeneralComponents.Controls ProgressBarMessager

Namespace: CleanCode.GeneralComponents.Controls
Assembly: CleanCode.GeneralComponents (in CleanCode.GeneralComponents.dll) Version: 1.2.3.0 (1.2.03)
Syntax

public class ProgressBarMessager : UserControl
Remarks

OnlineProgressBarMessager -- click for full size This control is composed of a standard OnlineProgressBar, a Cancel button that allows the user to signal to your application to cancel the lengthy operation being monitored, and a panel that displays a message corresponding to each step of the ProgressBar. Typical operation should first invoke Reset() followed by a call to ReportInitialMessage() with your first message. This displays your initial message just below the ProgressBar with a small green arrow preceding it, indicating it is the current step being executed. Subsequent messages should be sent to the PerformStep() method. The first such message changes the arrow in front of the first message to a check and optionally adds an elapsed time for that step. It then displays the second message with an arrow indicating that it is now the step being executed. Subsequent calls to PerformStep() repeat this process. Completion of your final step should be indicated by passing a null to PerformStep(). Click on the thumbnail at right for a screenshot of the ProgressBarMessager.

As you add messages the message panel (and therefore the ProgressBarMessager) expands vertically to contain a property-selectable number of messages (10 by default). Messages beyond that count cause the panel to effectively scroll messages.

The Cancel button provides a simple mechanism for the user to signal to you to cancel the lengthy operation in progress. All it does, though, is set the Cancelled property. It is up to your code to poll it and take appropriate action.

This control is instrumented with a ContainerTest property that provides additional functionality when run in the User Container of Visual Studio and set to true. See the property description for details of the added diagnostic functionality.

Since CleanCode 0.9.21.

Examples

Here is a complete example to wire up the ProgressBarMessager on a dedicated form. Some key points of the sample code:

  • The form title is set to the IDLE_TITLE when idle, and the RUN_TITLE during execution. The idle state is entered in 3 conditions: at startup, upon your indication of a final step (PerformStep(null)), or upon the user pressing Cancel.
  • The form is centered on top of the parent window upon initial display as long as the user has not manually moved it; see ProgressBarForm_VisibleChanged.
  • If the user presses the Cancel button a CancelledException is thrown that you need to handle; see UpdateProgress.
  • The exposed methods of this form are: ReportInitialMessage, UpdateProgress, and FinishLastMessage. You must wire these up to your main application.
  • The code insures this form is the top window once it opens; see ReportInitialMessage.
public partial class ProgressBarForm : Form
{

[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

private const string RUN_TITLE = "Processing... please wait";
private const string IDLE_TITLE = "My Progress Monitor";

private Form parent;

public ProgressBarForm(Form parent)
{
    InitializeComponent();
    this.parent = parent;
    progressBarMessager.Reset();
    Text = IDLE_TITLE;
}

private void ProgressBarForm_VisibleChanged(object sender, EventArgs e)
{
    if (Visible && !movedByUser)
    {
        Move -= new EventHandler(ProgressBarForm_Move);
        Location = new Point(
            Math.Max(0, (parent.Location.X + (parent.Width - Width) / 2)),
            Math.Max(0, (parent.Location.Y + (parent.Height - Height) / 2)));
        Move += new EventHandler(ProgressBarForm_Move);
        Refresh();
    }
}

private void ProgressBarForm_Move(object sender, EventArgs e)
{
    movedByUser = true;
}

public void ReportInitialMessage(string message)
{
    progressBarMessager.Reset();
    Text = RUN_TITLE;
    if (!Visible) { Show(); }
    // Also need to bring it to the foreground if buried!
    SetForegroundWindow(Handle);
    progressBarMessager.ReportInitialMessage(message);
    Refresh();
}

public void UpdateProgress(string message)
{
    Application.DoEvents();
    if (progressBarMessager.Cancelled)
    {
        Hide();
        Text = IDLE_TITLE;
        throw new CancelledException();
    }
    progressBarMessager.PerformStep(message);
    Refresh();
}

public void FinishLastMessage()
{
    Application.DoEvents();
    progressBarMessager.PerformStep(null);
    Refresh();
    Hide();
    Text = IDLE_TITLE;
}

}

public class CancelledException : ApplicationException
{
    // Use the default ApplicationException constructors 
    public CancelledException() : base() { }
    public CancelledException(string s) : base(s) { }
    public CancelledException(string s, Exception ex) : base(s, ex) { }
}
See Also