Progress indicator (ppptools.Progress)

Created: 2026-07-11 · Updated: 2026-07-11

Longer-running snippets/actions block the UI thread — without feedback you only see the wait cursor. PPPTools therefore shows a progress indicator that stays animated while your code runs (it runs on its own thread).

There are two levels:

  1. Automatic — for any run lasting longer than ~0.4 s, a "Running…" window (marquee) with a Cancel button appears. You don't have to do anything.
  2. With real progress — when your code knows the total (e.g. the number of slides), switch to a percentage bar with ppptools.Progress(...).

ppptools.Progress(text, total)

var p = ppptools.Progress("Formatting slides…", ppptools.SlideCount);
for (int s = 1; s <= ppptools.SlideCount; s++)
{
    p.Report(s, $"Slide {s} of {ppptools.SlideCount}");   // bar + text
    FormatShapes(ppptools.GetAllShapes(ppptools.GetSlide(s)));
}
  • Progress(text, total) — starts the determinate bar (0…total) and returns a handle.
  • Report(value, text) — updates bar and text. Report(text) (text only) also works for indeterminate steps.
  • The indicator closes automatically at the end of the run (or as soon as you show ppptools.ShowResult/ResultDialog).

Cancel

The window's "Cancel" behaves as follows:

  • With ppptools.Progress: the next Report(...) call throws an OperationCanceledException → your loop stops immediately and cleanly. To react without an exception, check p.IsCanceled.
  • Without Progress (auto indicator only): cancel takes effect at the next checkpoint — for a tight compute loop without Report possibly only at the end. So for reliable cancellation of long runs, use Progress.

Only when needed

Short snippets need nothing — the auto indicator only appears after ~0.4 s. Progress pays off once you iterate over many slides/shapes.


Full example

Search and format text across all slides — with a progress bar, clean cancel handling and a result dialog at the end:

// @param string SearchString "Search term" tooltip="Text to format"
// @param font   FormatFont   "Format"      default="Calibri,18,Bold"
// @button Run

string searchString = Params.GetString("SearchString", "");
var    fmt          = Params.GetFont("FormatFont");
int    replaced     = 0;

void FormatShapes(System.Collections.Generic.List<dynamic> shapes)
{
    foreach (dynamic sh in shapes)
    {
        if ((int)sh.HasTextFrame != (int)MsoTriState.msoTrue) continue;
        dynamic tr = sh.TextFrame.TextRange;

        dynamic found = tr.Find(searchString, 0, MsoTriState.msoFalse, MsoTriState.msoFalse);
        while (found != null)
        {
            found.Font.Name = fmt.Name;
            found.Font.Size = fmt.SizeInPoints;
            found.Font.Bold = fmt.Bold ? MsoTriState.msoTrue : MsoTriState.msoFalse;
            replaced++;
            int after = found.Start + found.Length - 1;
            found = tr.Find(searchString, after, MsoTriState.msoFalse, MsoTriState.msoFalse);
        }
    }
}

if (!string.IsNullOrWhiteSpace(searchString))
{
    // Progress across all slides
    var p = ppptools.Progress("Formatting slides…", ppptools.SlideCount);
    try
    {
        for (int s = 1; s <= ppptools.SlideCount; s++)
        {
            p.Report(s, $"Slide {s} of {ppptools.SlideCount}");   // Cancel → throws here
            FormatShapes(ppptools.GetAllShapes(ppptools.GetSlide(s)));
        }

        // Result (closes the progress indicator automatically)
        ppptools.ShowResult("Done",
            $"<b>{replaced}</b> hits formatted across {ppptools.SlideCount} slides.",
            "OK", "success");
    }
    catch (System.OperationCanceledException)
    {
        // "Cancel" was clicked — report cleanly
        ppptools.ShowResult("Cancelled",
            $"Stopped early — <b>{replaced}</b> hits formatted so far.",
            "OK", "warn");
    }
}

Flow: after ~0.4 s the window appears with a percentage bar and "Slide x of y". If the user clicks Cancel, the next p.Report(...) throws an OperationCanceledException → the catch reports how many hits were processed so far. On a normal finish, ShowResult closes the indicator and shows the result.