178 lines
12 KiB
Markdown
178 lines
12 KiB
Markdown
|
|
---
|
||
|
|
source_files:
|
||
|
|
- DTS Viewer/DTS.Viewer/Settings.cs
|
||
|
|
- DTS Viewer/DTS.Viewer/ExportModule.cs
|
||
|
|
- DTS Viewer/DTS.Viewer/ViewerModule.cs
|
||
|
|
- DTS Viewer/DTS.Viewer/ViewerSession.cs
|
||
|
|
- DTS Viewer/DTS.Viewer/Bootstrapper.cs
|
||
|
|
generated_at: "2026-04-16T10:57:48.975205+00:00"
|
||
|
|
model: "zai-org/GLM-5-FP8"
|
||
|
|
schema_version: 1
|
||
|
|
sha256: "f841428d718c70bf"
|
||
|
|
---
|
||
|
|
|
||
|
|
# DTS.Viewer Module Documentation
|
||
|
|
|
||
|
|
## 1. Purpose
|
||
|
|
|
||
|
|
The `DTS.Viewer` namespace provides the core module infrastructure for a Prism-based WPF viewer application. It implements a modular architecture using Unity dependency injection and Prism's modularity framework, enabling dynamic loading of viewer and export functionality. The module manages application bootstrapping, session lifecycle, plugin discovery, and region-based view composition. It serves as the entry point for initializing the viewer shell, registering view/viewmodel pairs, and coordinating module communication via event aggregation.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Public Interface
|
||
|
|
|
||
|
|
### Settings (DTS.Viewer.Properties)
|
||
|
|
```csharp
|
||
|
|
internal sealed partial class Settings
|
||
|
|
```
|
||
|
|
- **Settings()** - Constructor with optional event handler registration (currently commented out).
|
||
|
|
- **SettingChangingEventHandler(object sender, SettingChangingEventArgs e)** - Handles the `SettingChanging` event before a setting's value is changed. Currently empty implementation.
|
||
|
|
- **SettingsSavingEventHandler(object sender, CancelEventArgs e)** - Handles the `SettingsSaving` event before settings are saved. Currently empty implementation.
|
||
|
|
|
||
|
|
### ExportModule
|
||
|
|
```csharp
|
||
|
|
[Module(ModuleName = "Export")]
|
||
|
|
public class ExportModule : IExportModule
|
||
|
|
```
|
||
|
|
- **ExportModule(IUnityContainer unityContainer)** - Constructor accepting an injected Unity container.
|
||
|
|
- **SessionStarted** (property: `bool`) - Indicates whether a session has been started. Set to `true` after `StartSession()` completes.
|
||
|
|
- **Initialize()** - Registers `IExportModule` to `ExportModule` with container-controlled lifetime.
|
||
|
|
- **StartSession()** - Resolves `IEventAggregator`, publishes `LoadExportModuleEvent` with `LoadExportModuleArg`, sets `SessionStarted = true`.
|
||
|
|
- **RegisterTypes(IContainerRegistry containerRegistry)** - Calls `Initialize()`.
|
||
|
|
- **OnInitialized(IContainerProvider containerProvider)** - Empty implementation.
|
||
|
|
|
||
|
|
### ExportNameAttribute
|
||
|
|
```csharp
|
||
|
|
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
|
||
|
|
public class ExportNameAttribute : TextAttribute
|
||
|
|
```
|
||
|
|
- **ExportNameAttribute()** - Default constructor, sets `_assemblyName = "Export"`.
|
||
|
|
- **ExportNameAttribute(string s)** - Parameterized constructor, ignores parameter and sets `_assemblyName = "Export"`.
|
||
|
|
- **AssemblyName** (property: `string`) - Returns `_assemblyName` ("Export").
|
||
|
|
- **GetAttributeType()** - Returns `typeof(TextAttribute)`.
|
||
|
|
- **GetAssemblyName()** - Returns `AssemblyName`.
|
||
|
|
|
||
|
|
### ViewerModule
|
||
|
|
```csharp
|
||
|
|
[Module(ModuleName = "Viewer")]
|
||
|
|
public class ViewerModule : IViewerModule
|
||
|
|
```
|
||
|
|
- **ViewerModule(IUnityContainer unityContainer)** - Constructor accepting an injected Unity container.
|
||
|
|
- **SessionStarted** (property: `bool`) - Indicates whether a session has been started.
|
||
|
|
- **Initialize()** - Registers `IViewerModule` to `ViewerModule` with container-controlled lifetime.
|
||
|
|
- **StartSession()** - Resolves `IEventAggregator`, publishes `LoadViewModulEvent` with `LoadViewModulArg`, sets `SessionStarted = true`.
|
||
|
|
- **RegisterTypes(IContainerRegistry containerRegistry)** - Calls `Initialize()`.
|
||
|
|
- **OnInitialized(IContainerProvider containerProvider)** - Empty implementation.
|
||
|
|
|
||
|
|
### ViewerNameAttribute
|
||
|
|
```csharp
|
||
|
|
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
|
||
|
|
public class ViewerNameAttribute : TextAttribute
|
||
|
|
```
|
||
|
|
- **ViewerNameAttribute()** - Default constructor, sets `_assemblyName = "Viewer"`.
|
||
|
|
- **ViewerNameAttribute(string s)** - Parameterized constructor, ignores parameter and sets `_assemblyName = "Viewer"`.
|
||
|
|
- **AssemblyName** (property: `string`) - Returns `_assemblyName` ("Viewer").
|
||
|
|
- **GetAttributeType()** - Returns `typeof(TextAttribute)`.
|
||
|
|
- **GetAssemblyName()** - Returns `AssemblyName`.
|
||
|
|
|
||
|
|
### ViewerSession
|
||
|
|
```csharp
|
||
|
|
public class ViewerSession
|
||
|
|
```
|
||
|
|
- **Container** (property: `IUnityContainer`) - Gets the Unity container after `CreateSession()` is called.
|
||
|
|
- **_serviceLocator** (property: `IServiceLocator`) - Gets the service locator after `CreateSession()`.
|
||
|
|
- **_eventAggregator** (property: `IEventAggregator`) - Gets the event aggregator after `CreateSession()`.
|
||
|
|
- **_regionManager** (property: `IRegionManager`) - Gets the region manager after `CreateSession()`.
|
||
|
|
- **CustomConfigPath** (property: `string`) - Gets/sets custom configuration path for plugin loading.
|
||
|
|
- **ViewerSession()** - Empty constructor.
|
||
|
|
- **CreateSession(bool standalone, string customConfigPath = "")** - Creates the bootstrapper, initializes container/services, loads plugins via `PluginManager`, and publishes `AssemblyListNotificationViewer` event.
|
||
|
|
- **Terminate()** - Called during JMPS shutdown. Empty implementation.
|
||
|
|
|
||
|
|
### Bootstrapper
|
||
|
|
```csharp
|
||
|
|
public class Bootstrapper : UnityBootstrapper
|
||
|
|
```
|
||
|
|
- **Bootstrapper(bool standalone, string customConfigPath = "")** - Constructor accepting standalone mode flag and optional custom config path.
|
||
|
|
- **Standalone** (property: `bool`) - Gets/sets whether running in standalone mode.
|
||
|
|
- **CustomConfigPath** (property: `string`) - Gets/sets custom configuration path.
|
||
|
|
- **_ServiceLocator** (property: `IServiceLocator`) - Gets the service locator after `CreateShell()`.
|
||
|
|
- **_EventAggregator** (property: `IEventAggregator`) - Gets the event aggregator after `CreateShell()`.
|
||
|
|
- **ConfigureContainer()** - Registers `IViewerMainViewGrid` to `ViewerMainViewGrid` and `IViewerMainViewModel` to `ViewerMainViewModel` (singleton).
|
||
|
|
- **ConfigureRegionAdapterMappings()** - Registers region adapters for `Selector`, `ItemsControl`, `ContentControl`, and conditionally `StackPanel` (standalone only). Uses try/catch to ignore already-registered mappings.
|
||
|
|
- **CreateShell()** - Creates the main shell, resolves `IViewerMainViewModel`, registers regions, sets DataContext, and initializes the view model. Returns `DependencyObject` or `null` on exception.
|
||
|
|
- **CreateModuleCatalog()** - Returns resolved `IModuleCatalog` or new `AggregateModuleCatalog`.
|
||
|
|
- **ConfigureModuleCatalog()** - In standalone mode, reads plugin folders from config section `DTS.Common.Core.PluginLib.Config` under key `viewerPlugins`, creates `DirectoryModuleCatalog`.
|
||
|
|
- **InitializeModules()** - In standalone mode, registers `IDTSViewRegionManager` to `DTSViewRegionManager` (singleton), then calls base implementation.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Invariants
|
||
|
|
|
||
|
|
1. **Bootstrapper Singleton**: The `ViewerSession._bootstrapper` field should only be created once. The `CreateBootstrapper` method checks for null before creating a new instance.
|
||
|
|
|
||
|
|
2. **Session State Consistency**: Both `ExportModule.SessionStarted` and `ViewerModule.SessionStarted` are `false` by default and only set to `true` after `StartSession()` publishes its respective event.
|
||
|
|
|
||
|
|
3. **Module Registration Pattern**: Both `ExportModule` and `ViewerModule` register themselves as implementations of their respective interfaces using `ContainerControlledLifetimeManager` (singleton behavior within the container).
|
||
|
|
|
||
|
|
4. **Standalone Mode Behavior**:
|
||
|
|
- `ConfigureModuleCatalog()` only loads directory-based modules when `Standalone == true`.
|
||
|
|
- `InitializeModules()` only registers `IDTSViewRegionManager` when `Standalone == true`.
|
||
|
|
- `ConfigureRegionAdapterMappings()` only registers `StackPanel` adapter when `Standalone == true`.
|
||
|
|
|
||
|
|
5. **Attribute Constructor Behavior**: Both `ExportNameAttribute` and `ViewerNameAttribute` ignore their string parameter in the parameterized constructor, always returning hardcoded "Export" or "Viewer" respectively.
|
||
|
|
|
||
|
|
6. **Region Registration**: In `CreateShell()`, regions are only added if they don't already exist (`ContainsRegionWithName` check).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Dependencies
|
||
|
|
|
||
|
|
### External Dependencies (Imports)
|
||
|
|
|
||
|
|
| Namespace | Purpose |
|
||
|
|
|-----------|---------|
|
||
|
|
| `DTS.Common.Events` | Event types: `LoadExportModuleEvent`, `LoadViewModulEvent`, `AssemblyListNotificationViewer` |
|
||
|
|
| `DTS.Common.Interface` | Interfaces: `IExportModule`, `IViewerModule`, `IViewerMainViewGrid`, `IViewerMainViewModel`, `IShellViewModel`, `IDTSViewRegionManager` |
|
||
|
|
| `DTS.Common.Core.PluginLib` | `PluginManager`, `PluginConfigSectionHandler`, `FilterHashElement`, `AssemblyListInfo` |
|
||
|
|
| `DTS.Common.Base` | `TextAttribute` base class |
|
||
|
|
| `Prism.Events` / `Microsoft.Practices.Prism.Events` | `IEventAggregator`, event base classes |
|
||
|
|
| `Prism.Ioc` | `IContainerRegistry`, `IContainerProvider` |
|
||
|
|
| `Prism.Modularity` / `Microsoft.Practices.Prism.Modularity` | `IModule`, `IModuleCatalog`, `ModuleAttribute`, `AggregateModuleCatalog`, `DirectoryModuleCatalog` |
|
||
|
|
| `Prism.Regions` / `Microsoft.Practices.Prism.Regions` | `IRegionManager`, `Region`, `RegionAdapterMappings`, region adapters |
|
||
|
|
| `Unity` / `Microsoft.Practices.Unity` | `IUnityContainer`, `ContainerControlledLifetimeManager`, `InjectionMember` |
|
||
|
|
| `Microsoft.Practices.ServiceLocation` | `IServiceLocator`, `ServiceLocator` |
|
||
|
|
| `System.Configuration` | `ConfigurationManager`, configuration section handling |
|
||
|
|
| `System.ComponentModel.Composition.Hosting` | MEF composition support |
|
||
|
|
|
||
|
|
### Downstream Dependencies
|
||
|
|
|
||
|
|
The following types are registered by this module and expected to be consumed by other components:
|
||
|
|
- `IExportModule` → `ExportModule`
|
||
|
|
- `IViewerModule` → `ViewerModule`
|
||
|
|
- `IViewerMainViewGrid` → `ViewerMainViewGrid`
|
||
|
|
- `IViewerMainViewModel` → `ViewerMainViewModel`
|
||
|
|
- `IDTSViewRegionManager` → `DTSViewRegionManager`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Gotchas
|
||
|
|
|
||
|
|
1. **Ignored Constructor Parameter**: Both `ExportNameAttribute(string s)` and `ViewerNameAttribute(string s)` accept a string parameter but completely ignore it, always returning hardcoded values. This is misleading API design.
|
||
|
|
|
||
|
|
2. **Mixed Prism Namespace Versions**: The code imports from both legacy `Microsoft.Practices.Prism.*` namespaces and newer `Prism.*` namespaces. This suggests a migration in progress or dependency on both old and new Prism versions.
|
||
|
|
|
||
|
|
3. **Bootstrapper Memory Footprint**: The comment in `ViewerSession` notes: *"It appears that the current bootstrapper loads around 40 MB into memory. To completely unload the bootstrapper would take same research and effort."* There is currently no mechanism to unload or recreate the bootstrapper.
|
||
|
|
|
||
|
|
4. **Empty Event Handlers**: `Settings.SettingChangingEventHandler` and `Settings.SettingsSavingEventHandler` have empty implementations with only placeholder comments.
|
||
|
|
|
||
|
|
5. **Silent Failures in Region Adapter Registration**: `ConfigureRegionAdapterMappings()` uses empty catch blocks (`try { ... } catch { }`) when registering region adapters, silently ignoring any registration failures.
|
||
|
|
|
||
|
|
6. **Exception Swallowing in CreateShell**: The `CreateShell()` method catches all exceptions, stores the message in a local variable `s` that is never used, and returns `null`. This makes debugging shell creation failures difficult.
|
||
|
|
|
||
|
|
7. **Commented-Out Code in ConfigureContainer**: There is significant commented-out code for conditional view registration based on `Standalone` mode, suggesting unfinished or experimental functionality.
|
||
|
|
|
||
|
|
8. **Redundant Null Check Pattern**: In `CreateBootstrapper`, the method checks `_bootstrapper == null` twice—once before the try block and once after, throwing an exception if still null. The inner catch already wraps and rethrows with context.
|
||
|
|
|
||
|
|
9. **Private Field Naming Convention**: Several fields use underscore prefix but are exposed via public properties with different names (e.g., `_customConfigPath` vs `CustomConfigPath`), while others like `_serviceLocator` have public getters but inconsistent naming.
|
||
|
|
|
||
|
|
10. **Module Self-Registration**: Both `ExportModule` and `ViewerModule` register themselves in `Initialize()`, which is called from `RegisterTypes()`. This is unusual—typically the container is configured before module initialization, not by the module itself.
|