Repository navigation
v0.34.0
What changed and why
0.34.0 adds a fifth package, CvInspect.Avalonia: the display control and property editor of CvInspect.Wpf, for
Avalonia, so a host can show frames, overlays and teaching shapes on Linux as well as Windows (Linux is
checked headless in CI only so far — see the package's section below). To make
that possible without two copies of the same logic, the UI-independent parts of the WPF controls moved into the core package —
mostly as internal code, plus one public move: the property editor's row view-models and their builder now live in CvInspect.
Both display controls also get three theme keys consumers asked for (the image-area background, the no-image text color and the
toolbar icon color), and the no-image text now follows a language switch at once.
Take this release if you want the display on Avalonia, want the image area, the no-image text or the toolbar icons to follow
your theme, switch the UI language at run time, or want to build property-editor rows without WPF.
Upgrading from 0.33.0:
- Raise all your CvInspect packages together. CvInspect.Wpf 0.34.0 requires
CvInspect >= 0.34.0; keeping the core on
0.33.x stops the restore with NU1605. CvInspect.Imaging and CvInspect.Imaging.Gev have no code change in this release — only the
version, the core dependency and the package README's package list move. - No code change is needed. Code and XAML built against 0.33 keep working (see Breaking).
- One default changes on screen: the toolbar icons without an accent now take the text color the control inherits instead of the
button style's text color. In most themes they are the same color. A dark WPF host whose theme styles controls but not the
Windowgets black icons — seeToolbarForegroundbelow. - If a source object of a property editor has a hand-written
PropertyChangedaccessor that walks its own handler list, read
"Changed" below.
Breaking
Nothing breaks at the source or binary level. One move, with what it can still change:
Core — the property editor's rows moved from CvInspect.Wpf into CvInspect
CvPropGroupVm, CvPropRowVm and its seven row types (Bool, Num, Str, Enum, Action, List, Nested), CvPropRowBldr
and the four notification records (CvPropCommittedEvt, CvPropActionExecutingEvt, CvPropActionExecutedEvt,
CvPropActionFailedEvt) are now in the core package, with the same names and the same namespace (CvInspect.Controls).
CvInspect.Wpf forwards all 14 types (TypeForwardedTo), so assemblies and compiled XAML built against 0.33 resolve them.
- Checked: the public metadata of 0.33.0 and 0.34 compared with no mismatch; the 14 forwards are pinned by a regression test.
- What can still change: the types' assembly is now
CvInspect, so anything that records an assembly-qualified type name, or asks a
row type for itsAssembly, sees the new assembly. Nothing in CvInspect does that. - A core-only or non-WPF host can now build the same rows itself with
CvPropRowBldr.Build. The builder is reflection-based: under
IL2CPP managed stripping keep the option types (for example withlink.xml), or rows silently go missing.
Added
Core — CvPropRowBldr.Detach(groups)
Unsubscribes rows from their source at once and drops their hooks. It is final: detached rows never write again. Call it only on rows
you built yourself — on an editor's live Groups it silently throws away later edits. The editors call it whenever they rebuild their
rows (Source, ExecuteText or ShowDesc changes). CvPropRowBldr.Build itself is not new — it was public in CvInspect.Wpf and now
lives in the core, usable without WPF.
Core — CvLoc.Changed
Raised when what CvLoc.T returns may have changed: Culture set to a different value, Resolver assigned, or Reload(). It runs
on the thread that made the change, outside the lock; a subscriber that throws is logged as a warning and does not reach the caller
or the other subscribers. A change made inside a handler (a handler that calls Reload(), say) is not notified again, so handlers
cannot recurse without end. Both CvDispCtrls listen to it while loaded, so the no-image text switches language at once — before, it
kept the old language until the next repaint (a frame or a theme switch). A consumer found this in a real Avalonia window and saw the
fix work there; the WPF control had the same structure and got the same fix, checked by reading only (its test suite runs without a
window, where the control is never loaded). Nothing to do on the host side.
Known limit, unchanged: CvPropEditCtrl reads its labels, group headers and the action-button text when it builds its rows, so after a
language switch they change only when it rebuilds — assigning the same Source object again does nothing; set Source to null and
back, or change ShowDesc or ExecuteText.
Wpf and Avalonia — three theme keys for CvDispCtrl
| Key constant | Key string | Property | Default when neither is set | Paints |
|---|---|---|---|---|
ViewBackgroundKey |
CvDispViewBackgroundBrush |
ViewBackground |
the control's Background (#2A2A2A, or what the host set) |
image area around the picture and the no-image screen |
PlaceholderForegroundKey |
CvDispPlaceholderForegroundBrush |
PlaceholderForeground |
#9E9E9E |
no-image title and load hint |
ToolbarForegroundKey |
CvDispToolbarForegroundBrush |
ToolbarForeground |
the text color the control inherits (TextElement.Foreground) |
toolbar icons without an accent (📸 ⛶ ➕ ➖ 🧹, a released ✋) |
The same names and the same source order (instance property, then key, then default) in both packages, so a host moving between
them keeps its color dictionary. A host with a light theme adds the first two keys to that theme's dictionary only.
PlaceholderForeground takes a solid-color brush only (other brush types keep the default and log a warning), because the text is
drawn from the core draw list's ARGB color. The named overlay colors were chosen against a dark view.
ToolbarForeground changes a default. Before, the icons took the button theme's or style's text color; a consumer on the Semi
theme, which paints button text in its brand color, saw every icon come out as an accent. Now the default is the inherited text color.
On Avalonia the color also holds with the pointer over a button and while it is pressed, where themes paint the inside of the button
template directly. Disabled buttons keep the theme's disabled look (no icon color is set on them); ⏯ and a pressed ✋ stay white.
- The default toolbar background is a fixed light
#FAFAFA. A dark theme should setToolbarBackgroundKeyas well, or give the
icons a dark color through this key. - WPF hosts: the inherited text color is often not themed — a theme library that styles controls but not the
Windowleaves it
at the system text color (black). A dark WPF host in that situation now gets black icons and should set this key or the window's
Foreground.
Consumers on pre-release packages: one applied the background key (#E6E6E6) and saw it take effect; another ran the toolbar key on
the Semi theme in a real Avalonia window, light and dark, normal, pointer-over and pressed, and saw the key's color hold.
New package — CvInspect.Avalonia (first release)
CvDispCtrl and CvPropEditCtrl for Avalonia, in CvInspect.Avalonia.Controls (not the WPF package's namespace, so one project can
reference both). Same member names and meanings as CvInspect.Wpf, including the seven theme keys; the differences — ToolbarDock is
Avalonia.Controls.Dock, no message box (ImageFileFailed event and a log warning instead), file dialogs through StorageProvider,
theme keys also follow theme-variant switches, and others — are listed in its README. Toolbar icons are vector paths, so no emoji or
symbol font is needed.
net8.0only (Avalonia 12 has nonetstandardbuild), Avalonia 12.1.4 or later. Of Avalonia the package references only
Avaloniaitself (plusCvInspect); the application picks the platform (Avalonia.Desktop), renderer, theme and fonts. Keep everyAvalonia.*package on the same
version — a lowerAvalonia.Desktopmixes versions without any warning.- What has been checked: a headless test suite in CI, on Windows and Linux — Skia drawing into an off-screen frame, input raised
by the tests; zoom and label size also at render scalings 1.25 and 1.5. 77/77 on both (CI run 40610669722). One consumer has run it
in a real window on one Windows development PC with a live camera and the mouse. - What has not: a Linux desktop, a known GPU renderer, high-DPI screens, macOS; in that real window, the right-click menu, the
property editor's action rows and shape dragging. - Limits, also in its README: frame upload costs more than in WPF (Gray8 and Bgr24 are converted to BGRA; on one development PC a
2448×2048 frame took about 1.9 / 3.5 ms back to back and 2.9 / 4.7 ms with idle gaps, against 0.08–1.6 ms for the WPF upload on the
same PC; a consumer's real-window figures are in the README with their conditions). Avalonia's assemblies are unsigned, so a Windows
PC enforcing Smart App Control can block them. Avalonia's build tooling (Avalonia.BuildServices) sends build statistics, also from
projects that reference only this package; setAVALONIA_TELEMETRY_OPTOUTon build machines to opt out (ignored with an Accelerate
Community or Trial license key). This package does not turn it off for you.
Samples — an Avalonia demo
samples/CvInspect.Demo.Avalonia is the WPF demo's Avalonia counterpart, sharing its view-model (sources, recipe, tools and editor).
It is in the repository only; the release's downloadable exe stays the WPF demo. In both demos, a --webcam argument that matches no
camera now keeps its "not found" notice on the status line after the synthetic source starts — before, the next status overwrote it.
Changed
Wpf — the property editor's change subscription
The editor follows the source's PropertyChanged through the core's weak subscription instead of WPF's PropertyChangedEventManager.
Notifications still arrive synchronously, on the thread that raised them. What differs is clean-up: after a dropped editor's rows are
collected, one small bridge object stays on the source and removes itself the next time that source raises PropertyChanged
(WPF's manager cleaned up when another subscription was made). Opening and dropping editors many times on a long-lived POCO that
rarely notifies, without changing Source, leaves that many bridges until it notifies; they hold neither rows nor controls.
That self-removal runs inside the source's raise. Ordinary field-like events are safe; a hand-written accessor that iterates its own
handler list must copy it before invoking, or it can throw "collection was modified" at that raise (read from the code, not
reproduced). Two consumers checked their sources on a pre-release package and found no such accessor.
Internal — the UI-independent parts of the display moved into the core
View transform, shape dragging, render geometry, the draw list and text-measure port, the frame buffer, status-bar text, command
state, image-file encode and decode rules, theme constants, the context-menu model and the property editor's wiring are now internal
code in the core (Display/), linked as source into both UI packages. No public surface changed and no behavior change is intended.
The first two steps (view transform, dragging, render geometry, draw list) were checked against the previous build: screen golden
images byte-identical (680 hashes after the first step, 4088 frames after the second, 300 drags each), and the WPF transform matrices
bit-identical (200 fits + 50 identities). The rest (frame buffer, command state, file rules, menu model, editor wiring) is covered by
the regression suites only. On a WPF host, a teaching-shape drag, an overlay, right-click load and save, and the camera buttons are
worth one look after upgrading.
Version
Minor: 0.34.0. Public API was added (the Avalonia package, CvLoc.Changed, CvPropRowBldr.Detach, three theme keys with their
properties) and one public move (the property-editor rows, forwarded).
Checks
-
dotnet build CvInspect.sln -c Release --no-incrementalreports 0 warnings (an incremental build reports none when it recompiles nothing) -
mainis an ancestor of this branch (the release-pr-guard job verifies it) - the tag will be created on the merge commit,
mainmerged back intodevafterwards, anddevbumped to the next-devversion -
CvInspect.Avaloniais a new package id: the nuget.org trusted-publishing policy (owner kintaein, globCvInspect*, scope "push
new packages and package versions", repository cmir79/CvInspect, workflowpublish.yml, active) allows its first push - decided — ship as is and watch (it fails the same way on v0.33.0, which has run without trouble in the field; it appeared after the
move to a new development PC): on a local .NET 10 runtime (roll-forward; CI is .NET 8 and has always passed it) the core test
ReconnectingCamStartDuringOurOwnStopDoesNotRebuildfails 8 of 20 isolated runs, in order ② —GrabbingChangedarrives as
[True, True, False]while the camera ends live. v0.33.0 fails it at the same 8/20, so it is not from this release; whether it
is the test's timing or a real ordering race inReconnectingCam(a host could show "stopped" while live) is not yet known - after publish, all five ids show
0.34.0athttps://api.nuget.org/v3-flatcontainer/<id>/index.jsonbefore consumers are told
| Run | Commit | Result |
|---|---|---|
| CI run 40425622253 | cb34214 | Windows build warnings 0; core 200/200, Wpf 65/65; Linux core 200/200 |
| CI run 40432256485 | 818ee10 | Windows warnings 0; core 208/208, Wpf 70/70; Linux core 208/208 |
| CI run 40438575927 | 6d9dc0c | Windows warnings 0; core 227/227, Wpf 71/71; Linux core 227/227 |
| CI run 40448798532 | 515697b | Windows warnings 0; core 241/241, Wpf 71/71; Linux core 241/241; CvInspect.Avalonia builds and packs (5 nupkg) |
| CI run 40452573991 | e994d97 | core 241/241, Wpf 71/71, Avalonia 70/70; Linux core 241/241, Avalonia 70/70 (first run) |
| CI run 40457427444 | cb286c3 | core 241/241, Wpf 71/71, Avalonia 72/72; Linux core 241/241, Avalonia 72/72 |
| CI run 40459599064 | 75dbe62 | core 241/241, Wpf 71/71, Avalonia 75/75; Linux core 241/241, Avalonia 75/75 |
| CI run 40610669722 | 6944d46 | core 243/243, Wpf 72/72, Avalonia 77/77; Linux core 243/243, Avalonia 77/77 |
| CI run 40613205503 | a03a052 (release head) | core 243/243, Wpf 72/72, Avalonia 77/77; Linux core 243/243, Avalonia 77/77 |
Pre-release packages applied by consumers on their own machines (their measurements; details on their side):
0.34.0-devfrom CI run 40432256485 (818ee10, before the no-image text key and the Avalonia package), two WPF consumers, no source
change on their side: solution builds with no warnings (non-incremental), property editor open / edit / commit /Sourceswap /
action button as in 0.33, no hand-writtenPropertyChangedaccessor, no directCvDispCtrl.Background; one also applied the
background key.0.34.0-devfrom CI run 40610669722 (6944d46), one Avalonia consumer, Semi theme, Release single-file build: no warnings
(non-incremental); toolbar key held in light and dark, normal / pointer-over / pressed; pressed ✋ white on its accent; disabled look
while the window was disabled; the no-image text switched language without another repaint. Not seen: ⏯ white, a button disabled
by its own command, real-camera runs on that build.