Repository navigation
Keep Model free of ViewModel and WPF types: models ask for messages and the file picker through the broker - #836
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
using CompMs.App.Msdial.ViewModel.Service;andErrorMessageBoxRequestinRawDataGuard,MethodModelBaseandProjectModel;MessageBoxImageinRawDataGuardandProjectModel;Microsoft.Win32.OpenFileDialoginProjectModel;ExportFailure(from Make an unstartable MS-DIAL say why, and stop a broken user.config from being fatal #801).This PR restores View → ViewModel → Model for that code.
What changes
Model/Service/MessageRequest, modelled on the existingShortMessageRequest. It is WPF-free: Caption, Content,MessageSeverity(Information/Warning/Error),AsksYesNo, and aResultthe View fills in.RawDataGuard,MethodModelBase,ExportFailureandProjectModelpublishMessageRequeston the broker instead ofErrorMessageBoxRequest.ProjectModel's picker for a missing.mddatais now anOpenFileRequeston the same broker.MainWindow'sOpenFileDialoghandler 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.MainWindowsubscribes toMessageRequestand shows it through the new View-layerMessageRequestBox. That class mapsAsksYesNoto YesNo/OK,Severityto the icon, and Yes/OK toResult = true, on the UI thread.ErrorMessageBoxRequestand 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 theIconproperty 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
MessageRequest: RawDataGuard, DatasetModel, MethodModelBase, ProjectModel and MethodViewModel.MessageRequestBoxTestspin the button and icon mapping, including the defaults of an empty request.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.MessageBoxcalls inProjectModelandMainWindowModel.ErrorMessageBoxRequest.MainWindow.OpenFileDialog, which ignoresRestoreDirectoryas it always has.For the reviewer
The choice of a new Model-layer
MessageRequestover movingErrorMessageBoxRequestintoModel.Serviceis yours. Moving it would touch the seven author-owned callers and keepMessageBoxImagein Model.🤖 Generated with Claude Code