Summary
This issue proposes a complete, phased plan to migrate DynVis from WinForms on .NET Framework 4.8.1 to .NET MAUI on .NET 9+, targeting Windows (WinUI 3) and macOS (Mac Catalyst) as first-class platforms. The full document (with project layout, exit criteria, and code references) lives in the repo: docs/MAUI-MIGRATION-PLAN.md (branch claude/maui-migration-plan-mltb39).
Key findings from code analysis
- Own application code is ~51 KLOC; vendored third-party code (Tao OpenGL bindings, SourceGrid + DevAge, SharpZipLib fork) is ~217 KLOC — 81% of the repo. Deleting the vendored code in favor of maintained packages is the highest-leverage move of the migration.
- UI surface: 27 Forms + 30 UserControls, with WinForms coupling deep inside "core" libraries —
DynVis.Core has 66 files referencing System.Windows.Forms, and dialogs are opened from inside domain logic (e.g. BaseSurface3D.SaveApplicateMatrixText calls FormFileProperty.ShowDialog() mid-save).
DynVis.Math (~16.7 KLOC of ALGLIB-derived numerics) has zero UI references and ports as-is.
Hard platform couplings (the real blockers)
- Legacy OpenGL 1.x via Tao —
wglChoosePixelFormatARB, immediate mode (glBegin), display lists, GL_SELECT selection-buffer picking (GeometryDrawEngine.cs:176), wglUseFontOutlinesA text. None of this exists in GLES/ANGLE, and MAUI has no OpenGL control → the 3D renderer must be rewritten, not ported.
- GDI+ 2D contour engine —
System.Drawing.Graphics is Windows-only on modern .NET.
BinaryFormatter .sam document format (DynVis.Core/Serialization.cs:19) — removed from .NET 9 and a security liability → new zip+JSON format plus a one-time converter tool.
- Plugin loader (
Assembly.LoadFile from plugin/, interface matching by name string) → AssemblyLoadContext + a real contract assembly; built-in methods (LEPS, IRC, Dynamic, CriticalPoints, GridSurface) compile in statically.
- SourceGrid WinForms grid in ~10 editors → MAUI DataGrid behind an internal wrapper component.
- Dead endpoints & obsolete code — updater and bug-report e-mail pointing at defunct
dynvis.narod.ru over plain HTTP, WININET P/Invoke, .NET Framework version-detection code → delete in Phase 0.
- Latent culture bugs — file parsing under
ru-RU default culture; must be pinned to invariant culture with regression tests before anything else moves.
Proposed strategy
- Rendering: replace both engines with SkiaSharp (
SKCanvasView/SKGLView). 3D = CPU transforms (matrices already exist in DynVis.Math) + Skia rasterization, with a time-boxed spike and a GLES-shader fallback for very large grids. Picking via ray-cast replaces GL_SELECT.
- Architecture: UI-free
DynVis.Kernel + DynVis.Methods + DynVis.Sdk (plugin contracts with parameter metadata instead of WinForms editor controls), DynVis.Rendering, and a MAUI DynVis.App using MVVM (CommunityToolkit.Mvvm). The current Paint-event menu-enabling hack becomes plain CanExecute.
- UI model: single main window with docked panes replacing the five floating tool windows; localization consolidated from dozens of per-form
.resx into central ru+en resources; options.ini → MAUI Preferences behind the existing GlobalParams API.
Phases (each independently mergeable, ~3–4 months total)
| Phase |
Content |
Estimate |
| 0 |
SDK-style csproj on net481, characterization ("golden") tests from Samples/, delete dead code + ZLib, fix culture handling |
1–2 wk |
| 1 |
Extract UI-free Kernel/Methods (net9.0-compatible), IProgressReporter/IInteractionService seams, replace BinaryFormatter, converter tool |
3–4 wk |
| 2 |
SkiaSharp rendering library: camera, meshes, contours, trajectories, picking, image export; snapshot-test parity vs old renderers, then delete DynVis.Draw*/Tao.* |
3–4 wk |
| 3 |
MAUI app shell: panes, DataGrid-based editors, metadata-driven property panels, wizards, localization, plugins (desktop) |
4–6 wk |
| 4 |
CI (GitHub Actions win+mac), MSIX / signed .app, optional GitHub-Releases update check, delete InstallShield/ClickOnce/Localizer |
1–2 wk |
Top risks
- 3D fidelity/perf of the rewrite → Phase 2 spike with FPS budget; old app stays runnable until image-snapshot parity.
- Old
.sam files unreadable → converter tool shipped with releases; legacy format frozen.
- MAUI desktop rough edges (no first-party DataGrid, menu/multi-window quirks) → wrapper components; honest note: for a desktop-only scientific app Avalonia would be lower-risk — Phases 0–2 are destination-agnostic, so this decision can be revisited after Phase 2 at zero extra cost.
- Culture regressions (
ru-RU decimal commas in existing data files) → golden tests first, tolerant reader.
Explicit non-goals (v1)
Android/iOS targets, numerical/algorithm changes, backward-writing legacy .sam, manual rewrite beyond screenshots.
Full details, target project layout, and the complete risk register: docs/MAUI-MIGRATION-PLAN.md.
Summary
This issue proposes a complete, phased plan to migrate DynVis from WinForms on .NET Framework 4.8.1 to .NET MAUI on .NET 9+, targeting Windows (WinUI 3) and macOS (Mac Catalyst) as first-class platforms. The full document (with project layout, exit criteria, and code references) lives in the repo:
docs/MAUI-MIGRATION-PLAN.md(branchclaude/maui-migration-plan-mltb39).Key findings from code analysis
DynVis.Corehas 66 files referencingSystem.Windows.Forms, and dialogs are opened from inside domain logic (e.g.BaseSurface3D.SaveApplicateMatrixTextcallsFormFileProperty.ShowDialog()mid-save).DynVis.Math(~16.7 KLOC of ALGLIB-derived numerics) has zero UI references and ports as-is.Hard platform couplings (the real blockers)
wglChoosePixelFormatARB, immediate mode (glBegin), display lists,GL_SELECTselection-buffer picking (GeometryDrawEngine.cs:176),wglUseFontOutlinesAtext. None of this exists in GLES/ANGLE, and MAUI has no OpenGL control → the 3D renderer must be rewritten, not ported.System.Drawing.Graphicsis Windows-only on modern .NET.BinaryFormatter.samdocument format (DynVis.Core/Serialization.cs:19) — removed from .NET 9 and a security liability → new zip+JSON format plus a one-time converter tool.Assembly.LoadFilefromplugin/, interface matching by name string) →AssemblyLoadContext+ a real contract assembly; built-in methods (LEPS, IRC, Dynamic, CriticalPoints, GridSurface) compile in statically.dynvis.narod.ruover plain HTTP, WININET P/Invoke, .NET Framework version-detection code → delete in Phase 0.ru-RUdefault culture; must be pinned to invariant culture with regression tests before anything else moves.Proposed strategy
SKCanvasView/SKGLView). 3D = CPU transforms (matrices already exist inDynVis.Math) + Skia rasterization, with a time-boxed spike and a GLES-shader fallback for very large grids. Picking via ray-cast replacesGL_SELECT.DynVis.Kernel+DynVis.Methods+DynVis.Sdk(plugin contracts with parameter metadata instead of WinForms editor controls),DynVis.Rendering, and a MAUIDynVis.Appusing MVVM (CommunityToolkit.Mvvm). The currentPaint-event menu-enabling hack becomes plainCanExecute..resxinto centralru+enresources;options.ini→ MAUIPreferencesbehind the existingGlobalParamsAPI.Phases (each independently mergeable, ~3–4 months total)
Samples/, delete dead code + ZLib, fix culture handlingKernel/Methods(net9.0-compatible),IProgressReporter/IInteractionServiceseams, replaceBinaryFormatter, converter toolDynVis.Draw*/Tao.*Top risks
.samfiles unreadable → converter tool shipped with releases; legacy format frozen.ru-RUdecimal commas in existing data files) → golden tests first, tolerant reader.Explicit non-goals (v1)
Android/iOS targets, numerical/algorithm changes, backward-writing legacy
.sam, manual rewrite beyond screenshots.Full details, target project layout, and the complete risk register:
docs/MAUI-MIGRATION-PLAN.md.