Files
DP44/enriched-qwen3-coder-next/Common/DTS.CommonCore/Base/ViewModel.md

182 lines
9.4 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- Common/DTS.CommonCore/Base/ViewModel/ViewModelBase.cs
- Common/DTS.CommonCore/Base/ViewModel/BaseViewModel.cs
generated_at: "2026-04-16T02:51:04.199849+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "e292dc2f8a859c0e"
---
# ViewModel
## Documentation: ViewModel Base Classes (`DTS.Common.Base`)
---
### 1. Purpose
This module provides two foundational abstract base classes for implementing ViewModels in the Prism-based WPF UI layer: `ViewModelBase<T>` (a minimal, model-centric base) and `BaseViewModel<TModel>` (a richer, infrastructure-aware base integrating Prism, Unity DI, and region management). `ViewModelBase<T>` serves as a low-level abstraction for custom ViewModel implementations requiring explicit control over model lifecycle, async initialization, and property change notifications. `BaseViewModel<TModel>` extends this with Prism-specific services (event aggregator, region manager, container), built-in command infrastructure (`CloseCommand`, `ConfirmationRequest`), and standardized initialization/cleanup hooks—aiming to reduce boilerplate in typical ViewModels while enforcing consistent lifecycle management and status reporting.
---
### 2. Public Interface
#### `ViewModelBase<T>` (in `ViewModelBase.cs`)
- **`public object Model { get; set; }`**
Holds the underlying model object. Stored as `object`; cast to `T` internally.
- **`public bool IsBusy { get; protected set; }`**
Read-only public property indicating whether an asynchronous operation is in progress. Protected setter allows derived classes to update it.
- **`public virtual bool IsDirty { get; protected set; }`**
Read-only public property indicating whether the `Model` has unsaved changes. Virtual to allow overriding.
- **`public virtual event EventHandler<ErrorEventArgs> ErrorOccurred;`**
Event raised when an error occurs during processing.
- **`public virtual event PropertyChangedEventHandler PropertyChanged;`**
Standard `INotifyPropertyChanged` event for property change notifications.
- **`protected abstract Task<T> InitializeAsync();`**
Override to implement async model initialization. The returned `Task<T>` result is used to populate the `Model` property.
- **`protected abstract void DoRefresh(Func<T> factoryMethod);`**
Override to implement model refresh logic using a static factory method.
- **`protected abstract void OnError(Exception error);`**
Override to raise the `ErrorOccurred` event.
- **`protected abstract void OnModelChanged(T oldValue, T newValue);`**
Override to handle model replacement (e.g., unhooking/hooking event handlers on the old/new model).
- **`protected abstract void OnPropertyChanged(string propertyName);`**
Override to raise the `PropertyChanged` event.
> **Note**: `ViewModelBase<T>` implements `INotifyPropertyChanged` and `IViewModel` (interface not shown), and inherits from `DependencyObject`.
---
#### `BaseViewModel<TModel>` (in `BaseViewModel.cs`)
- **`protected IEventAggregator Aggregator { get; }`**
Prism event aggregator for pub/sub messaging.
- **`protected IUnityContainer Container { get; }`**
Unity DI container for service resolution.
- **`protected IRegionManager _regionManager { get; }`**
Prism region manager for view navigation/region population.
- **`public TModel Model { get; set; }`**
Strongly-typed model object (contrasted with `ViewModelBase<T>.Model` which is `object`).
- **`public InteractionRequest<Confirmation> ConfirmationRequest { get; }`**
Prism `InteractionRequest` for displaying confirmation dialogs.
- **`public DelegateCommand<object> CloseCommand { get; }`**
Command to close the view/viewmodel; executes `CloseMethod`, which in turn calls `CleanupAtClose()``Cleanup()`.
- **`protected virtual void CloseMethod(object parameter)`**
Default implementation invokes `CleanupAtClose()`.
- **`public virtual void Activated()`**
Hook called after viewmodel activation (e.g., by Prism region navigation). Default is no-op.
- **`public virtual void Initialize()`**
Publishes a `ShowStatus` event with `StatusState.Busy` and `"Loading"` message via `Aggregator`.
- **`public virtual void Initialize(object parameter)`**
Same as above; accepts initialization parameter (unused in current implementation).
- **`public virtual void Initialize(object parameter, object model)`**
Placeholder with no implementation.
- **`public virtual async Task InitializeAsync()`**
Async version of `Initialize()`, marshals `ShowStatus` publish to UI thread via `Dispatcher.CurrentDispatcher.InvokeAsync`.
- **`public virtual async Task InitializeAsync(object parameter)`**
Async version of `Initialize(object)`.
- **`public new event PropertyChangedEventHandler PropertyChanged;`**
Shadows base `PropertyChanged` event (likely from `BasePropertyChanged`, not shown).
- **`public bool IsMenuIncluded { get; set; }`**
Flag indicating whether the view includes a menu.
- **`public bool IsNavigationIncluded { get; set; }`**
Flag indicating whether the view includes navigation controls.
- **`public int Percentage { get; set; }`**
Status progress percentage (e.g., for loading bars).
- **`public string IsBusyMessage { get; set; }`**
Custom busy message to display.
- **`public bool IsBusy { get; set; }`**
Busy state flag (redundant with `ViewModelBase<T>.IsBusy`; no synchronization between the two).
- **`public bool IsDirty { get; set; }`**
Dirty state flag (redundant with `ViewModelBase<T>.IsDirty`; no synchronization).
- **`public virtual void Cleanup()`**
Sets `Model` to `default(TModel)`.
- **`public Task CleanupAsync()`**
**Throws `NotImplementedException`** — not implemented.
> **Note**: `BaseViewModel<TModel>` inherits from `BasePropertyChanged` (not shown), implements `IBaseViewModel` (not shown), and requires `TModel : class`.
---
### 3. Invariants
- **`ViewModelBase<T>`**:
- `InitializeAsync()` must return a `Task<T>` whose result is assigned to `Model`.
- `OnModelChanged` must be called whenever `Model` changes (implementation responsibility of derived class).
- `OnPropertyChanged` must be called for all property changes requiring UI updates.
- `OnError` must be called to raise `ErrorOccurred`.
- **`BaseViewModel<TModel>`**:
- `Initialize()`/`InitializeAsync()` *must* publish a `ShowStatus` event with `StatusInfo.StatusState.Busy` and `"Loading"` message during initialization.
- `CloseCommand` always triggers `Cleanup()` (via `CleanupAtClose()`).
- `Cleanup()` sets `Model = default(TModel)`.
- `IsBusy`, `IsDirty`, `Percentage`, `IsBusyMessage`, `IsMenuIncluded`, and `IsNavigationIncluded` are *not* synchronized with any internal state machine — their values are purely application-defined.
---
### 4. Dependencies
#### `ViewModelBase<T>`
- **System namespaces**: `System`, `System.ComponentModel`, `System.Diagnostics`, `System.IO`, `System.Threading.Tasks`, `System.Windows`.
- **Implements**: `INotifyPropertyChanged`, `IViewModel` (external interface).
- **Inherits**: `DependencyObject`.
- **Used by**: Any ViewModel requiring low-level control over model lifecycle and notifications.
#### `BaseViewModel<TModel>`
- **Prism namespaces**: `Microsoft.Practices.Prism.Events`, `Microsoft.Practices.Prism.Commands`, `Microsoft.Practices.Prism.Regions`, `Microsoft.Practices.Prism.Interactivity.InteractionRequest`.
- **Unity DI**: `Microsoft.Practices.Unity`.
- **Internal namespaces**: `DTS.Common.Events` (for `ShowStatus`, `StatusInfo`, `Strings`).
- **Inherits**: `BasePropertyChanged` (unseen, assumed to provide `INotifyPropertyChanged`).
- **Implements**: `IBaseViewModel` (external interface).
- **Depends on**:
- `IRegionManager`, `IEventAggregator`, `IUnityContainer` (injected via constructor).
- `Strings.Strings.Loading` (string resource).
- `Dispatcher.CurrentDispatcher` (for async marshaling).
- **Used by**: Most ViewModels in the application requiring Prism integration.
---
### 5. Gotchas
- **`BaseViewModel<TModel>.CleanupAsync()` is unimplemented** — throws `NotImplementedException`. Do not call this method.
- **Redundant state flags**: Both `ViewModelBase<T>` and `BaseViewModel<TModel>` define `IsBusy` and `IsDirty`. There is *no synchronization* between them. If a class inherits from both (or uses both), these flags may diverge.
- **`Model` type mismatch**: `ViewModelBase<T>.Model` is `object`, while `BaseViewModel<TModel>.Model` is strongly-typed `TModel`. Mixing these bases may lead to casting issues.
- **`Initialize(object parameter, object model)` is a no-op** — despite accepting parameters, it does nothing. Initialization logic must be implemented in other overloads.
- **`BaseViewModel` uses `new event PropertyChangedEventHandler`** — this shadows any base `PropertyChanged` (e.g., from `BasePropertyChanged`), which may cause confusion if event handlers are attached to the wrong reference.
- **No automatic `IsBusy`/`IsDirty` management**: Derived classes must manually update `IsBusy`/`IsDirty` (in `ViewModelBase<T>`) or rely on application logic (in `BaseViewModel<TModel>`).
- **`DoRefresh`s contract is underspecified**: The source does not clarify how/when `DoRefresh` should be called or how it interacts with `InitializeAsync`.
- **`Strings.Strings.Loading` is referenced but not defined here** — assumes a `Strings` resource class exists in `DTS.Common` with a `Loading` property.
> **None identified from source alone** for `ViewModelBase<T>` beyond its minimal design. For `BaseViewModel<TModel>`, the above are the primary concerns.