Skip to content

v0.30.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 07:23
· 40 commits to main since this release
98abd33

What changed and why

Four changes:

  • New public API in CvInspect.Wpf: CvDispCtrl's toolbar and status bar colors can now come from the host theme. A consumer that
    switches light/dark at run time asked for it.
  • A fix in CvInspect.Wpf: CvDispCtrl no longer throws from its constructor under an application-level implicit style.
  • Two fixes to ReconnectingCam when starts and stops overlap on different threads.

Every new test fails on the code before its fix.

Take this release if your WPF host has a dark theme, switches themes at run time, or styles CvDispCtrl from the application's
resources, or if you call StartContinuous and StopContinuous on a ReconnectingCam from more than one thread.

Wpf — CvDispCtrl toolbar and status bar colors follow the host theme (new API)

The toolbar background, the status bar background and text, and the separator lines were fixed brushes set in code. Their value
source was Local, so no host resource could override them, and a dark host theme still showed two near-white bars (#FAFAFA)
around the image. A consumer measured this on 0.29.4.

  • Four resource keys, as constants on CvDispCtrl. A Brush under one of them anywhere above the control (application
    dictionary, window, the control's own Resources) paints every display below it:

    Constant Key string Default Paints
    ToolbarBackgroundKey CvDispToolbarBackgroundBrush #FAFAFA Toolbar background
    StatusBarBackgroundKey CvDispStatusBarBackgroundBrush #FAFAFA Status bar background
    StatusBarForegroundKey CvDispStatusBarForegroundBrush #555555 Status bar text
    SeparatorBrushKey CvDispSeparatorBrush #DDDDDD Toolbar group separators, the toolbar's edge line, the status bar's edge line
  • Four dependency properties with the same names: ToolbarBackground, StatusBarBackground, StatusBarForeground and
    SeparatorBrush. A value set on the instance wins over the key. It can be a direct value, a binding, a DynamicResource or a
    style setter. null (the default) means "follow the key". Clearing a direct value (ClearValue) goes back to the next source:
    a style setter if there is one, otherwise the key.

  • CvDispCtrl is not a Control. By WPF's rules, an implicit style in a window's or user control's resources therefore does not
    reach a CvDispCtrl created by a DataTemplate; one in the application's resources does. Inside templates, use the keys, which
    reach every display, or set the property on the element in the template.

  • The defaults are the old colors, so a host that sets nothing sees no change.

  • The keys are held as resource references. Swapping the host's color dictionary repaints without a restart, and removing the keys
    brings the defaults back.

  • A non-null value under one of these keys that is not a Brush (for example a Color) is ignored. Each display logs a CvLog
    warning naming the key when it picks the value up. It does not throw from the layout pass.

  • Write the key as {x:Static cv:CvDispCtrl.ToolbarBackgroundKey}. A typo then fails loudly when the dictionary loads, with a
    XamlParseException naming the member. The build does not check it. A mistyped key string is ignored without a message.

  • The same defect was fixed in two more places in this change:

    • The ⏯/✋ accents (PrimaryBrush/SuccessBrush/DangerBrush) were read at construction and again only at the next toggle. A
      theme swap left the old color until then, and a key on a parent element was not seen by the ⏯ accent at construction.
    • The property editor's caption and header colors (SecondaryTextBrush/PrimaryBrush) were copied on Loaded. A theme swap left
      the old color until the next Loaded.

    Both now follow the host keys the same way, with the same fixed fallbacks.

Wpf — CvDispCtrl no longer throws from its constructor under an application-level style

This affects 0.29.4 and earlier. An implicit CvDispCtrl style in the application's resources that set ToolbarDock,
IsToolbarVisible or IsCamControlVisible made the constructor throw (ArgumentNullException or NullReferenceException), so the
view holding the display failed to load. Hosts typically merge their global styles into the application's resources. The control's
first row definition was added at the top of the constructor, and adding it makes WPF raise Initialized and apply the implicit
style inside the constructor, before the fields that the property callbacks use existed. The rows and children are now added at the
end of the constructor. The review of this release found the problem while checking the new color properties, which travel the same
path.

Imaging — ReconnectingCam: a Start during our own Stop no longer rebuilds a healthy session

This was listed as a known limitation in the 0.29.4 notes; it is now fixed. StopContinuous lowers the intent, then stops the inner
camera outside the lock. The inner camera announces the stop only once it has finished stopping; on GevCam, that includes the pump
join and the AcquisitionStop round trip. If another thread's StartContinuous raised the intent in that window, the late stop
notification was read as "the camera stopped grabbing without being asked". The wrapper then logged a warning and rebuilt the
session. A disconnect was announced, and grabs failed with "Camera is reconnecting." during the backoff.

  • Measured on a Basler acA2500-14gm. The exposure was 30 ms, the stop took 40–62 ms, and the start came 0–30 ms after the stop:
    • 0.29.4: 25 of 26 overlapping start/stop pairs rebuilt the session.
    • This release: 0 of 25 rebuilt the session, with no warnings.
    • In both runs, the reported IsGrabbing matched whether frames actually arrived.
  • While our own stop is still stopping the inner camera, a stop notification from that inner camera is treated as the echo of our
    stop. The command called last still wins:
    • If the later start reached the inner camera before our stop did, the stop restarts live on the same session.
    • If the later start fails, whatever was started for it is stopped again, and nothing is reported live.
  • The reported state follows the facts. While the inner camera is off, IsGrabbing is false; it becomes true again when live
    actually runs. Subscribers can therefore see a false/true pair around such an overlap.
  • A genuine stream collapse inside that window is recovered by restarting live on the same session, not by a rebuild. On GevCam, a
    dead stream stops again outside the window, and that stop does rebuild the session.
  • Two adversarial review rounds found and pinned more interleavings. Examples: a start that fails inside the inner camera, a relight
    that is refused, and a late-starting inner camera.

Imaging — ReconnectingCam: two refused starts no longer leave live wanted

A refused StartContinuous put the intent back to the value it had when the call was made. When two starts overlapped, that value
for the later start was the "on" set by the earlier start, which was about to be refused too. If both were refused, in either order,
the intent stayed on while nothing ran. IsGrabbing was correctly false, but after the next connection loss the reconnect started
live that nobody had asked for. A consumer found this in its own copy of the wrapper, and ours had the same shape.

  • A refused start now puts the intent back only when the current intent is its own decision. This is tracked by the chain of
    starts, not by a version number. The intent goes back to the decision before it, and skips any earlier decision that was also
    refused.
  • A start that ends because the session was lost or replaced counts as accepted. Its intent is kept, and the reconnect resumes it.
    The first version of this fix counted it as refused, and a later refusal then erased it.
  • StopContinuous, Close, and an Open of a closed camera cut the chain and clear the records.

What can change for you when you upgrade from 0.29.4

  • Wpf: nothing changes on screen unless the host defines the new keys or sets the new properties.

  • Wpf: the ⏯/✋ accents and the property editor's caption and header colors now track the host keys continuously:

    • A theme swap repaints them at once. Before, the old color stayed until the next toggle (accents) or the next Loaded (editor).
    • The ⏯ accent now sees a key on a parent element from the start. Before, it saw only application keys until the first toggle.

    A host that redefines PrimaryBrush later and expects the display to keep the old color will see it change.

  • Wpf: the toolbar and status bar elements still carry Local values, because the control pushes the resolved brush into them. So
    DependencyPropertyHelper.GetValueSource on those inner elements still reads Local, although the colors follow the keys and
    properties above.

  • Wpf: if you reached into the control's visual tree to recolor the toolbar or status bar, move to the keys or properties. The inner
    elements are now repainted whenever a theme key changes, which overwrites values you set there. The fallback brushes are frozen and
    shared between displays, so changing their Color throws.

  • Wpf: a new Warning, only when one of the four CvDisp… keys holds a non-Brush value: Resource '<key>' is a <Type>, not a Brush; ignored, the default color is used. It is logged once per display each time the display picks the value up.

  • Wpf: CvDispCtrl adds its rows and children at the end of its constructor, so an application-level implicit style is applied
    there rather than at the first line. The resulting tree is the same.

  • ReconnectingCam: a StartContinuous that overlaps a StopContinuous on another thread no longer causes a disconnect/reconnect.
    The last command wins, on the same session.

  • ReconnectingCam: a new Warning appears only on that overlap: live could not be restarted after StopContinuous and a later StartContinuous overlapped — it stays off; call StartContinuous again. It is logged when the inner camera refuses the restart,
    for example because a single grab is waiting (GevCam). Live stays off and is reported off.

  • ReconnectingCam: a new Debug line appears on that overlap: a stop notification during our own StopContinuous was taken as its echo ….

  • ReconnectingCam: after two overlapping starts are both refused, the next reconnect no longer starts live.

Known limitation

If the restart on the same session is refused (see the warning above), live stays off while the recorded intent is still on. A
later reconnect restores live. The reported state is correct: nothing is reported live.

Version

0.30.0 — minor: CvInspect.Wpf adds four public constants and four dependency properties on CvDispCtrl. The four packages are
released in lockstep. CvInspect (core) and CvInspect.Imaging.Gev have no code change since 0.29.4.

Checks

  • dotnet build CvInspect.sln -c Release --no-incremental reports 0 warnings
  • Tests: 78 (core) + 44 (Wpf) pass
  • Wpf theme tests use offscreen renders at the system DPI. They check the toolbar, status bar, text and separator pixels, both
    status text brushes, the accents, and the property editor colors:
    • Fixed-color control: passes before and after the change, which shows the sampled pixels are the right ones.
    • Host keys, run-time swap and removal, accents, and editor colors: each fails on the code before the change.
    • All four instance properties: a value beats the key, clearing returns to the next source, and a style setter beats the key.
    • Application-level style and keys during construction: fails with the old constructor order (NullReferenceException), and
      also when only the row definitions are moved back to just after the status bar.
    • 52 of 53 mutations of the theme code fail at least one test. The survivor swaps two calls whose order does not change the
      result.
    • Simulated system DPI of 100/125/150/175/200 %: all theme tests pass. Before the DPI-aware rendering, 125 % and above failed on
      correct code.
  • Measurement scope: the suite swaps a parent element's Resources and does not swap the application dictionary at run time.
    The review measured that path separately on a real Application. It covered four ways of swapping the application dictionary,
    and a HandyControl light/dark theme swap. Every display followed (144 of 144 checks).
  • ReconnectingCam regressions 10-R28…10-R33: each fails on the code before its fix. Interleavings with several cases were
    checked one case at a time.
  • Hardware (ReconnectingCam overlap): shared Basler, 0.29.4 vs the fix, same probe, camera settings read back before and after.
  • Review: two adversarial passes on the start/stop fix and two on the refused-start fix. The Wpf theme surface had two passes:
    • The first found the constructor crash (critical, survived three refutations), test gaps, and doc errors; all were fixed.
    • The second was a delta pass on the fix. It found no code defect. All 16 public properties were set from an application style
      on the old and new builds. The visual tree, child order and focus order are unchanged. One test gap was found and closed.
  • main is an ancestor of this branch (the release-pr-guard job verifies it)
  • the tag will be created on the merge commit, main merged back into dev afterwards, and dev bumped to the next -dev version