Skip to content

Keep Model free of ViewModel and WPF types: models ask for messages and the file picker through the broker - #836

Merged
htsugawa merged 5 commits into
masterfrom
refactor/model-message-requests
Oct 16, 2026
Merged

htsugawa merged 5 commits into
masterfrom
refactor/model-message-requests

Conversation

@htsugawa

Copy link
Copy Markdown
Contributor

Why

The lead developer pointed out that PR #829 (browsing a project without raw data) broke the MVVM direction. Model classes referenced ViewModel types and WPF:

This PR restores View → ViewModel → Model for that code.

What changes

  • New Model/Service/MessageRequest, modelled on the existing ShortMessageRequest. It is WPF-free: Caption, Content, MessageSeverity (Information/Warning/Error), AsksYesNo, and a Result the View fills in.
  • Model side: RawDataGuard, MethodModelBase, ExportFailure and ProjectModel publish MessageRequest on the broker instead of ErrorMessageBoxRequest.
  • Dataset picker: ProjectModel's picker for a missing .mddata is now an OpenFileRequest on the same broker. MainWindow's OpenFileDialog handler marshals onto the dispatcher, written exactly as the 5.6 line (improve/dynamic-rawdata-loading) already writes it, so that merge gains no new conflict.
  • View side: MainWindow subscribes to MessageRequest and shows it through the new View-layer MessageRequestBox. That class maps AsksYesNo to YesNo/OK, Severity to the icon, and Yes/OK to Result = true, on the UI thread.
  • Revert: ErrorMessageBoxRequest and its handler go back byte-for-byte to their pre-Open and browse an MS-DIAL 5 project whose raw data files are missing #829 state, removing the Icon property Open and browse an MS-DIAL 5 project whose raw data files are missing #829 added.

Unchanged: every message text, caption, button set, icon and Yes/No meaning. For example, opening without raw data still proceeds only on Yes.

Tests

  • The GUI tests that asserted the old request type now assert MessageRequest: RawDataGuard, DatasetModel, MethodModelBase, ProjectModel and MethodViewModel.
  • New MessageRequestBoxTests pin the button and icon mapping, including the defaults of an empty request.
  • MsdialGuiApp builds with 0 errors. MsdialGuiAppTests pass, apart from the one test that Dispose a model's items even when its collection is cleared first #833 fixes.

Out of scope, left as the original authors wrote it

These are deliberately unchanged, though some are worth a follow-up:

  • ProjectModel's wait cursor and its "Loading project…" window.
  • Other MessageBox calls in ProjectModel and MainWindowModel.
  • The seven setting models that publish ErrorMessageBoxRequest.
  • MainWindow.OpenFileDialog, which ignores RestoreDirectory as it always has.

For the reviewer

The choice of a new Model-layer MessageRequest over moving ErrorMessageBoxRequest into Model.Service is yours. Moving it would touch the seven author-owned callers and keep MessageBoxImage in Model.

🤖 Generated with Claude Code

DESKTOP-382ETUR\Hiroshi Tsugawa and others added 4 commits October 16, 2026 00:37
The raw-data guard, MethodModelBase, ProjectModel and ExportFailure are
models, and they published ErrorMessageBoxRequest, which lives in
ViewModel.Service and carries MessageBoxButton, MessageBoxImage and
MessageBoxResult. RawDataGuard also imported System.Windows for them. So a
model referred to a view model namespace and to WPF types, the wrong way
round for View -> ViewModel -> Model.

MessageRequest, in Model.Service beside ShortMessageRequest and
OpenFileRequest, says the same things without them: Caption, Content, a
MessageSeverity (Information, Warning, Error), AsksYesNo, and a bool? Result
that is true for Yes or OK. MainWindow subscribes to it and shows it as
ShowErrorConfirmationMessage did: through the dispatcher, Yes/No or OK, the
icon of the severity, and no owner.

Every message keeps its text, caption, buttons and icon:
- ConfirmOpen still asks Yes or No with the warning icon, and opens only on
  Yes; with nobody to answer it still declines (Result stays null).
- The imaging refusal, Ensure, EnsureAll and the sample, peak list,
  alignment and MS-FINDER messages keep OK and their icons.
- "Dataset not loaded" and "Export failed" keep OK and the error icon.

ErrorMessageBoxRequest goes back to what it was before Icon was added for
these messages: the authors' setting models that publish it never set Icon,
and its handler shows the error icon again, as it did.

The tests listen for MessageRequest and answer with true or false, and pin
caption, severity and buttons where they pinned them before. A new test
pins what ExportFailure.Report publishes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ProjectModel.LocateDatasetFileAsync opened a Microsoft.Win32 OpenFileDialog
itself, through Application.Current.Dispatcher: a model building a dialog.
It now publishes an OpenFileRequest on the broker that reading the datasets
already has, as MainWindowModel does for the project picker, with the same
filter, title (MessageHelper.LocateDatasetFileTitle) and RestoreDirectory,
and returns the file picked, or null when none was.

The request is published from the thread that reads the datasets (the
Task.Run in LoadMdprojectAsync), so MainWindow's OpenFileDialog handler now
shows the dialog through Dispatcher.Invoke, as its message handlers do. On
the UI thread, where every other OpenFileRequest comes from, Invoke runs the
dialog inline, so nothing changes for them. The reading thread waits for the
answer instead of awaiting it, which is how the dataset messages before the
picker are already shown.

Two tests: through ReadDatasetsAsync, the picker is asked for after the
message about the same dataset, with its title and filter, and cancelling
still refuses the project; and the file picked in the view is returned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MainWindow.OpenFileDialog now shows the dialog through Dispatcher.Invoke so
that the dataset picker can be asked for from the thread that reads the
datasets. improve/dynamic-rawdata-loading wraps the same handler in
Dispatcher.Invoke too, but with the brace of the initializer on its own line
and without the comment. Written differently, the two sides changed the same
lines and the next merge of master into that line conflicts in
MainWindow.xaml.cs, where it does not conflict today. Written as it is
there, the change is the same on both sides and merges cleanly.

Why the request can come from off the UI thread is said where it is asked,
in ProjectModel.LocateDatasetFileAsync.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What keeps every message looking as it did is the view's mapping from a
MessageRequest to a message box: AsksYesNo to Yes/No or OK, the severity to
the information, warning or error icon, and Yes or OK to a Result of true.
It sat inline in MainWindow.ShowMessage, where no test reaches it (the test
project cannot bind to MainWindow, a RibbonWindow), so swapping two icons
went unnoticed. It moves, unchanged, to MessageRequestBox beside MainWindow,
and MessageRequestBoxTests pins it, including that a request with nothing
set is shown as an ErrorMessageBoxRequest was: "Error", OK, error icon.

The model tests also pin, for the messages that only had their caption or
text pinned, the buttons and the severity they had as ErrorMessageBoxRequests:
the sample, peak list, MS-FINDER, sample-open and alignment-open messages of
RawDataGuard, EnsureAll, and "Dataset not loaded".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@htsugawa
htsugawa merged commit 8ef9694 into master Oct 16, 2026
1 check passed
@htsugawa
htsugawa deleted the refactor/model-message-requests branch October 16, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant