This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
---
source_files:
- DTS Viewer/DTS.Viewer/Modules/Main/View/MainView.xaml.cs
- DTS Viewer/DTS.Viewer/Modules/Main/View/ViewerShellView.xaml.cs
- DTS Viewer/DTS.Viewer/Modules/Main/View/MainViewLite.xaml.cs
- DTS Viewer/DTS.Viewer/Modules/Main/View/ExportMainView.xaml.cs
- DTS Viewer/DTS.Viewer/Modules/Main/View/ViewerMainView.xaml.cs
- DTS Viewer/DTS.Viewer/Modules/Main/View/ExportMainViewGrid.xaml.cs
- DTS Viewer/DTS.Viewer/Modules/Main/View/ViewerMainViewGrid.xaml.cs
generated_at: "2026-04-16T14:05:18.299277+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "a7a3a3c725d7b68b"
---
# Documentation: DTS.Viewer Main View Module
## 1. Purpose
This module contains the main view components for the DTS Viewer application, implementing a WPF-based UI with multiple view variants (standard, lite, export, and viewer modes). The views serve as code-behind files for XAML-defined user interfaces, handling view initialization, event subscription via Prism's event aggregator, and PDF/PNG export functionality. These views implement interfaces from `DTS.Common.Interface` to enable loose coupling with view models in what appears to be a MVVM architecture.
---
## 2. Public Interface
### MainView
```csharp
public partial class MainView : IMainView
```
- **Constructor:** `MainView()` — Initializes the component via `InitializeComponent()`.
- **Role:** Primary main window view implementation.
### ViewerShellView
```csharp
public partial class ViewerShellView : IViewerShellView
```
- **Constructor:** `ViewerShellView()` — Initializes the component via `InitializeComponent()`.
- **Role:** Shell container view for the viewer mode.
### MainViewLite
```csharp
public partial class MainViewLite : IMainViewerView
```
- **Constructor:** `MainViewLite()` — Initializes the component via `InitializeComponent()`.
- **Role:** Lightweight version of the main viewer view.
### ExportMainView
```csharp
public partial class ExportMainView : IExportMainView
```
- **Constructor:** `ExportMainView()` — Initializes the component via `InitializeComponent()`.
- **Role:** Main view for export functionality.
### ViewerMainView
```csharp
public partial class ViewerMainView : IViewerMainView
```
- **Constructor:** `ViewerMainView()` — Initializes the component via `InitializeComponent()`.
- **Role:** Main view for viewer mode. Contains commented-out AvalonDock layout serialization/deserialization logic.
### ExportMainViewGrid
```csharp
public partial class ExportMainViewGrid : IExportMainViewGrid
```
- **Constructor:** `ExportMainViewGrid()` — Initializes component and subscribes to `Loaded` event.
- **Methods:**
- `public int SaveToPDF(string directory, string pdfFileName)` — Renders `MainShell` to a PDF and PNG file. Returns `> 0` on success, `< 0` on failure, `0` if `MainShell` is not ready.
- **Event Handlers:**
- `ExportMainViewGrid_Loaded` — Resolves `IEventAggregator` and subscribes to `GraphLoadedCountNotification`.
- `OnGraphLoadedCountNotification(GraphLoadedCountNotificationArg arg)` — Triggers focus setting after 3-second delay if `DataContext` matches `arg.ParentVM`.
- `SetFocus()`**Empty implementation** (no-op).
### ViewerMainViewGrid
```csharp
public partial class ViewerMainViewGrid : IViewerMainViewGrid
```
- **Constructor:** `ViewerMainViewGrid()` — Initializes component and subscribes to `Loaded` event.
- **Methods:**
- `public int SaveToPDF(string directory, string pdfFileName)` — Renders `MainShell` to a PDF and PNG file. Returns `> 0` on success, `< 0` on failure, `0` if `MainShell` is not ready.
- **Event Handlers:**
- `ViewerMainViewGrid_Loaded` — Resolves `IEventAggregator` and subscribes to `GraphLoadedCountNotification`.
- `OnGraphLoadedCountNotification(GraphLoadedCountNotificationArg arg)` — Triggers focus setting after 3-second delay if `DataContext` matches `arg.ParentVM`.
- `SetFocus()` — Sets `chartOptTab.IsSelected = true`, makes it focusable, and calls `Focus()`.
---
## 3. Invariants
1. **Interface Implementation:** All view classes implement their respective interfaces from `DTS.Common.Interface` (`IMainView`, `IViewerShellView`, `IMainViewerView`, `IExportMainView`, `IViewerMainView`, `IExportMainViewGrid`, `IViewerMainViewGrid`).
2. **SaveToPDF Preconditions:**
- `directory` must be non-null and non-empty.
- `pdfFileName` must be non-null, non-empty, and end with `.pdf`.
- `MainShell.DesiredSize.Height` and `MainShell.DesiredSize.Width` must be `> 0` for export to proceed.
3. **Event Subscription Timing:** `IEventAggregator` is resolved and event subscriptions occur in the `Loaded` event handler, not the constructor (per FB 14797).
4. **Focus Timing:** Focus is set via `Dispatcher.BeginInvoke` after a 3-second `Thread.Sleep` following `GraphLoadedCountNotification`.
5. **DataContext Matching:** `OnGraphLoadedCountNotification` only proceeds if `DataContext` is non-null and equals `arg.ParentVM` cast to `IBaseViewModel`.
---
## 4. Dependencies
### External Dependencies (Imports)
| Namespace | Purpose |
|-----------|---------|
| `DTS.Common.Interface` | View interfaces (`IMainView`, `IViewerShellView`, `IMainViewerView`, `IExportMainView`, `IViewerMainView`, `IExportMainViewGrid`, `IViewerMainViewGrid`) |
| `DTS.Common.Base` | `IBaseViewModel` interface |
| `DTS.Common.Events` | `GraphLoadedCountNotification` event, `GraphLoadedCountNotificationArg` argument class |
| `DTS.Common.Utilities.Logging` | `APILogger.LogException()` for error logging |
| `DTS.Common.Utils` | `PNGImageUtil.SaveImage()` for PNG export |
| `Prism.Events` | `IEventAggregator` for pub/sub messaging |
| `Prism.Ioc` | `ContainerLocator` for service location |
| `C1.WPF.Pdf` | `C1PdfDocument` for PDF generation (ComponentOne library) |
| `System.Windows.Media` | `VisualTreeHelper`, `PixelFormats` for visual rendering |
| `System.Windows.Media.Imaging` | `RenderTargetBitmap`, `WriteableBitmap` for bitmap rendering |
### Downstream Dependencies
- Unknown from source alone. These views are likely referenced by view models or a bootstrapper/module initializer that resolves them via dependency injection.
---
## 5. Gotchas
1. **Hardcoded 3-Second Delay:** Both `ExportMainViewGrid` and `ViewerMainViewGrid` use `Thread.Sleep(TimeSpan.FromSeconds(3))` before setting focus. This is a timing-based workaround (FB 14797) that may be unreliable on slower systems.
2. **Empty SetFocus() in ExportMainViewGrid:** `ExportMainViewGrid.SetFocus()` is empty while `ViewerMainViewGrid.SetFocus()` has actual implementation. This appears to be intentional (perhaps the `chartOptTab` element doesn't exist in the export view), but is non-obvious.
3. **Side Effect in SaveToPDF:** The `SaveToPDF` method also generates a PNG file as a side effect via `PNGImageUtil.SaveImage()`, which may not be expected from the method name alone.
4. **Service Locator Pattern:** `IEventAggregator` is resolved via `ContainerLocator.Container.Resolve<IEventAggregator>()` rather than constructor injection, making the dependency implicit.
5. **Commented-Out AvalonDock Code:** `ViewerMainView` contains significant commented-out code for AvalonDock layout serialization (`XmlLayoutSerializer`, `DockManager`). This suggests either deprecated functionality or a feature that was intentionally disabled.
6. **Return Value Ambiguity in SaveToPDF:** The method returns `1` for success but the documentation states `> 0`. Callers should check `> 0` rather than `== 1` for forward compatibility.
7. **ReSharper Disable Directives:** Multiple files contain `// ReSharper disable` comments, indicating suppressed static analysis warnings. This may mask potential issues.

View File

@@ -0,0 +1,192 @@
---
source_files:
- DTS Viewer/DTS.Viewer/Modules/Main/ViewModel/ViewerShellViewModel.cs
- DTS Viewer/DTS.Viewer/Modules/Main/ViewModel/MainViewModel.cs
- DTS Viewer/DTS.Viewer/Modules/Main/ViewModel/ExportMainViewModel.cs
generated_at: "2026-04-16T14:05:37.474639+00:00"
model: "zai-org/GLM-5-FP8"
schema_version: 1
sha256: "ab73d8a45f8ea2f6"
---
# DTS Viewer Main Module View Models Documentation
## 1. Purpose
This module contains the core view models for the DTS Viewer application's main shell and content regions. It implements the MVVM pattern using Microsoft Prism and Unity IoC to manage view composition, region navigation, and event-driven communication. The three view models form a hierarchy: `ViewerShellViewModel` serves as the application shell container, `MainViewModel` manages primary content regions (graphs, properties, navigation), and `ExportMainViewModel` extends functionality for data export, PDF generation, and layout persistence.
---
## 2. Public Interface
### ViewerShellViewModel
**Signature:** `public class ViewerShellViewModel : NotificationObject, IViewerShellViewModel`
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `ViewerShellViewModel(IViewerShellView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)` | Initializes the shell, sets up notification requests, subscribes to `RaiseNotification` events, and registers `IMainView`/`IMainViewModel` types with Unity. |
| View | `IViewerShellView View { get; private set; }` | Gets the associated shell view. |
| NotificationRequest | `InteractionRequest<Notification> NotificationRequest { get; private set; }` | Interaction request for displaying notifications. |
| ConfirmationRequest | `InteractionRequest<Confirmation> ConfirmationRequest { get; private set; }` | Interaction request for displaying confirmations. |
| Initialize | `void Initialize()` | No-op implementation (assigns local variable `i = 10`). |
| Initialize | `void Initialize(object parameter)` | No-op implementation (assigns local variable `i = 22`). |
| Initialize | `void Initialize(object parameter, object model)` | Empty implementation. |
| Activated | `void Activated()` | Called on activation; currently no-op. |
| GetRegions | `List<FrameworkElement> GetRegions()` | Returns all FrameworkElements named "Region" within the MainShell. |
| ContextMainRegion | `Object ContextMainRegion { get; set; }` | Gets/sets the content of the MainRegion. |
| IsMenuIncluded | `bool IsMenuIncluded { get; set; }` | Indicates whether the menu is included in the shell. |
| IsNavigationIncluded | `bool IsNavigationIncluded { get; set; }` | Indicates whether navigation is included in the shell. |
| HeaderInfo | `string HeaderInfo { get; }` | Returns constant string "MainRegion". |
| IsBusy | `bool IsBusy { get; }` | **Throws `NotImplementedException`.** |
| IsDirty | `bool IsDirty { get; }` | **Throws `NotImplementedException`.** |
| Cleanup | `void Cleanup()` | **Throws `NotImplementedException`.** |
| CleanupAsync | `Task CleanupAsync()` | **Throws `NotImplementedException`.** |
| InitializeAsync | `Task InitializeAsync()` | **Throws `NotImplementedException`.** |
| InitializeAsync | `Task InitializeAsync(object parameter)` | **Throws `NotImplementedException`.** |
---
### MainViewModel
**Signature:** `public class MainViewModel : BaseViewModel<IMainViewModel>, IMainViewModel`
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `MainViewModel(IMainView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)` | Initializes the view model, sets up notification/confirmation requests, and subscribes to `RaiseNotification` event. |
| View | `IBaseView View { get; private set; }` | Gets the associated main view. |
| Initialize | `override void Initialize()` | Empty override. |
| Initialize | `override void Initialize(object parameter)` | Sets `Parent` from parameter, propagates menu/navigation settings to parent, subscribes to `AssemblyListNotification` and `BusyIndicatorChangeNotification` events. |
| Activated | `override void Activated()` | Empty override. |
| GetRegions | `List<FrameworkElement> GetRegions()` | Returns all FrameworkElements named "Region" within the MainShell. |
| ContextNavigationRegion | `object ContextNavigationRegion { get; set; }` | Gets/sets NavigationRegion content. |
| ContextGraphRegion | `object ContextGraphRegion { get; set; }` | Gets/sets GraphRegion content. |
| ContextTestsRegion | `object ContextTestsRegion { get; set; }` | Gets/sets TestsRegion content. |
| ContextGraphsRegion | `object ContextGraphsRegion { get; set; }` | Gets/sets GraphsRegion content. |
| ContextLegendRegion | `object ContextLegendRegion { get; set; }` | Gets/sets LegendRegion content. |
| ContextDiagRegion | `object ContextDiagRegion { get; set; }` | Gets/sets DiagRegion content. |
| ContextStatsRegion | `object ContextStatsRegion { get; set; }` | Gets/sets StatsRegion content. |
| ContextCursorRegion | `object ContextCursorRegion { get; set; }` | Gets/sets CursorRegion content. |
| ContextPropertyRegion | `object ContextPropertyRegion { get; set; }` | Gets/sets PropertyRegion content. |
| IsBusy | `new bool IsBusy { get; set; }` | Gets/sets busy indicator state. |
| IsBusyMessage | `new string IsBusyMessage { get; set; }` | Gets/sets busy indicator message. |
| IsMenuIncluded | `new bool IsMenuIncluded { get; set; }` | Gets/sets menu inclusion flag. |
| IsNavigationIncluded | `new bool IsNavigationIncluded { get; set; }` | Gets/sets navigation inclusion flag. |
| HeaderInfo | `string HeaderInfo { get; }` | Returns constant string "MainRegion". |
---
### ExportMainViewModel
**Signature:** `public class ExportMainViewModel : BaseViewModel<IExportMainViewModel>, IExportMainViewModel`
| Member | Signature | Description |
|--------|-----------|-------------|
| Constructor | `ExportMainViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer)` | Initializes the view model, resolves `IExportMainViewGrid` as the view, and sets up interaction requests. |
| View | `IBaseView View { get; set; }` | Gets/sets the associated view. |
| Standalone | `bool Standalone { get; set; }` | Determines whether to use `ExportMainView` (standalone) or `ExportMainViewGrid` for region access. |
| Initialize | `override void Initialize()` | Calls `Subscribe()` to register event handlers. |
| Initialize | `override void Initialize(object parameter)` | Sets `Parent` from parameter, propagates settings, calls `Subscribe()`. |
| Activated | `override void Activated()` | Empty override. |
| AddSelectedEvents | `void AddSelectedEvents(string groupName, List<ITestEvent> events)` | Adds events to `SelectedEventList`, publishes busy indicator notifications. |
| SelectAndIncludeDataFile | `void SelectAndIncludeDataFile(string value)` | Sets selected data file and publishes `DataFolderChangedEvent`. |
| ZoomReset | `void ZoomReset()` | Publishes `ResetZoomChangedEvent` with `true`. |
| LeftKeyPress | `void LeftKeyPress()` | Publishes `ShiftT0Event` with step `-1`. |
| RightKeyPress | `void RightKeyPress()` | Publishes `ShiftT0Event` with step `+1`. |
| GetRegions | `List<FrameworkElement> GetRegions()` | Returns regions based on `Standalone` mode. |
| LoadLayoutCommand | `ICommand LoadLayoutCommand { get; }` | Loads AvalonDock layout from `.\DataProViewerAvalonDock.config`. |
| SaveLayoutCommand | `ICommand SaveLayoutCommand { get; }` | Saves AvalonDock layout to `.\AvalonDock.config`. |
| ContextNavigationRegion | `object ContextNavigationRegion { get; set; }` | Gets/sets NavigationRegion content (mode-dependent). |
| ContextGraphRegion | `object ContextGraphRegion { get; set; }` | Gets/sets GraphRegion content (mode-dependent). |
| ContextGraphListRegion | `object ContextGraphListRegion { get; set; }` | Gets/sets GraphListRegion content (mode-dependent). |
| ContextTestsRegion | `object ContextTestsRegion { get; set; }` | Gets/sets TestsRegion content (mode-dependent). |
| ContextGraphsRegion | `object ContextGraphsRegion { get; set; }` | Gets/sets GraphsRegion content (mode-dependent). |
| ContextPropertyRegion | `object ContextPropertyRegion { get; set; }` | Gets/sets PropertyRegion content. |
| SelectedEventList | `List<ITestEvent> SelectedEventList { get; set; }` | List of selected test events. |
| SelectedDataFolder | `string SelectedDataFolder { get; set; }` | Selected data folder path; publishes `DataFolderChangedEvent` on set. |
| SelectedDataFile | `string SelectedDataFile { get; set; }` | Selected data file path; publishes `DataFolderChangedEvent` on set. |
| TotalSelectedTests | `int TotalSelectedTests { get; set; }` | Count of selected tests; updates `TitleTests`. |
| TotalLoadedTests | `int TotalLoadedTests { get; set; }` | Count of loaded tests; updates `TitleTests`. |
| TotalSelectedGraphs | `int TotalSelectedGraphs { get; set; }` | Count of selected graphs; updates `TitleTestIDs`. |
| TotalLoadedGraphs | `int TotalLoadedGraphs { get; set; }` | Count of loaded graphs; updates `TitleTestIDs`. |
| ShowModifications | `bool ShowModifications { get; set; }` | Indicates if T0 modifications are shown. |
| ChannelCodeViewMode | `IsoViewMode ChannelCodeViewMode { get; set; }` | Channel code view mode; publishes `ChannelCodesViewChangedEvent`. |
| CalibrationBehaviorSetting | `CalibrationBehaviors CalibrationBehaviorSetting { get; set; }` | Calibration behavior; publishes `ExportCalibrationBehaviorSettingChangedEvent`. |
| CalibrationBehaviorSettableInViewer | `bool CalibrationBehaviorSettableInViewer { get; set; }` | Whether calibration behavior is settable; publishes event and selects graphs tab. |
| SettingsVisibility | `Visibility SettingsVisibility { get; private set; }` | Visibility of settings panel. |
| IsBusy | `new bool IsBusy { get; set; }` | Busy indicator state. |
| IsBusyMessage | `new string IsBusyMessage { get; set; }` | Busy indicator message. |
| HeaderInfo | `string HeaderInfo { get; }` | Returns constant string "MainRegion". |
---
## 3. Invariants
1. **Region Content Consistency**: All `Context*Region` properties directly access the underlying view's region content. The view must be properly initialized before any region access.
2. **Standalone Mode Switching**: In `ExportMainViewModel`, the `Standalone` property determines which view type (`ExportMainView` vs `ExportMainViewGrid`) is used for region access. This must be set before accessing any region properties.
3. **Event Subscription Timing**: Event subscriptions occur in `Initialize()` or `Initialize(object parameter)`. Calling region properties or event-triggering methods before initialization may result in null reference exceptions or missed events.
4. **Parent Parameter Casting**: `MainViewModel.Initialize(object parameter)` and `ExportMainViewModel.Initialize(object parameter)` cast the parameter to `IBaseWindowModel`. Passing an incompatible type will cause a runtime exception.
5. **Assembly Attribute Requirements**: `MainViewModel.OnAssemblyListChange` expects assemblies to have attributes whose type names end with "ImageAttribute" and are castable to `ImageAttribute`.
6. **PDF Save Thread Safety**: `OnSaveToPDFRequested` uses `lock(saveLock)` for thread safety. The view's `SaveToPDF` method must be thread-safe.
7. **Layout File Existence**: `CanLoadLayout` returns `false` if `.\DataProViewerAvalonDock.config` does not exist, preventing command execution.
---
## 4. Dependencies
### External Dependencies (from imports)
| Namespace | Purpose |
|-----------|---------|
| `Microsoft.Practices.Prism.Events` / `Prism.Events` | Event aggregation for pub/sub messaging |
| `Microsoft.Practices.Prism.Regions` / `Prism.Regions` | Region management for view composition |
| `Microsoft.Practices.Prism.ViewModel` | `NotificationObject` base class for INPC |
| `Microsoft.Practices.Prism.Interactivity.InteractionRequest` | Dialog/notification interaction requests |
| `Microsoft.Practices.Unity` / `Unity` | IoC container for dependency injection |
| `System.ComponentModel.Composition` | MEF attributes for component export |
| `Xceed.Wpf.AvalonDock.Layout.Serialization` | Docking layout serialization |
| `DTS.Common.Base` | Base interfaces (`IBaseViewModel`, `IBaseView`, `IBaseWindowModel`) |
| `DTS.Common.Events` | Event types (`RaiseNotification`, `AssemblyListNotification`, etc.) |
| `DTS.Common.Interface` | View/model interfaces |
| `DTS.Common.Utils` | Utility methods (`Utils.GetChildrenByName`) |
| `DTS.Common.Enums` | Enumeration types (`IsoViewMode`, `CalibrationBehaviors`, `eAssemblyRegion`) |
| `DTS.Common.Classes.Viewer.Commands` | `RelayCommand` implementation |
### Internal Dependencies
| Dependent | Dependency | Relationship |
|-----------|------------|--------------|
| `ViewerShellViewModel` | `IViewerShellView`, `ViewerShellView` | View contract and concrete type |
| `ViewerShellViewModel` | `IMainView`, `IMainViewModel`, `MainView`, `MainViewModel` | Registers and creates main content |
| `MainViewModel` | `IMainView`, `MainView` | View contract and concrete type |
| `MainViewModel` | `INavigationView`, `INavigationViewModel` | Creates navigation region content |
| `MainViewModel` | `IPropertyView`, `IPropertyViewModel` | Creates property region content |
| `MainViewModel` | `IGraphView`, `IGraphViewModel` | Creates graph region content |
| `ExportMainViewModel` | `IExportMainViewGrid`, `ExportMainViewGrid`, `ExportMainView` | View contracts and concrete types |
| `ExportMainViewModel` | `IGraphView`, `IGraphViewModel` | Creates graph region content |
| `ExportMainViewModel` | `IExportGraphMainView`, `IExportGraphMainViewModel` | Creates graph list region content |
| `ExportMainViewModel` | `ITestSummaryListView`, `ITestSummaryListViewModel` | Creates test summary region content |
---
## 5. Gotchas
1. **NotImplementedException Methods in ViewerShellViewModel**: The following methods throw `NotImplementedException`: `IsBusy` getter, `IsDirty` getter, `Cleanup()`, `CleanupAsync()`, `InitializeAsync()`, and `InitializeAsync(object parameter)`. These appear to be interface requirements that were never implemented.
2. **Property Hiding with `new` Keyword**: Both `MainViewModel` and `ExportMainViewModel` use `new` to hide base class properties (`IsBusy`, `IsBusyMessage`, `IsMenuIncluded`, `IsNavigationIncluded`, `PropertyChanged`). This can cause unexpected behavior when casting to base types.
3. **Dead Code in Initialize Methods**: `ViewerShellViewModel.Initialize()` and `Initialize(object parameter)` contain assignments to local variables (`int i = 10`, `int i = 22`) that have no effect. This appears to be placeholder/debug code.
4. **Region Property Setter Mismatch**: In `MainViewModel`, `ContextGraphRegion` setter calls `OnPropertyChanged("ContextGraphsRegion")` (note the 's' in Graphs), which does not match the property name. This may cause binding issues.
5. **Standalone Mode View Casting**: `ExportMainViewModel` performs direct casts to either `ExportMainView` or `ExportMainViewGrid` based on `Standalone` flag. If `Standalone` is changed after initial access, cached region content may become invalid.
6. **Event Handler Identity Checks**: Several event handlers (e.g., `OnGraphLoadedCountChanged`, `OnTestLoadedChanged`) check `if (this != arg?.ParentVM) return;`. This means events are only processed if the sender explicitly set the `ParentVM` property to match.
7. **CalibrationBehaviorSettableInViewer Side Effect**: Setting `CalibrationBehaviorSettableInViewer` has a side effect of selecting the graphs tab (`((ExportMainViewGrid)