--- 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` (a minimal, model-centric base) and `BaseViewModel` (a richer, infrastructure-aware base integrating Prism, Unity DI, and region management). `ViewModelBase` serves as a low-level abstraction for custom ViewModel implementations requiring explicit control over model lifecycle, async initialization, and property change notifications. `BaseViewModel` 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` (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 ErrorOccurred;`** Event raised when an error occurs during processing. - **`public virtual event PropertyChangedEventHandler PropertyChanged;`** Standard `INotifyPropertyChanged` event for property change notifications. - **`protected abstract Task InitializeAsync();`** Override to implement async model initialization. The returned `Task` result is used to populate the `Model` property. - **`protected abstract void DoRefresh(Func 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` implements `INotifyPropertyChanged` and `IViewModel` (interface not shown), and inherits from `DependencyObject`. --- #### `BaseViewModel` (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.Model` which is `object`). - **`public InteractionRequest ConfirmationRequest { get; }`** Prism `InteractionRequest` for displaying confirmation dialogs. - **`public DelegateCommand 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.IsBusy`; no synchronization between the two). - **`public bool IsDirty { get; set; }`** Dirty state flag (redundant with `ViewModelBase.IsDirty`; no synchronization). - **`public virtual void Cleanup()`** Sets `Model` to `default(TModel)`. - **`public Task CleanupAsync()`** **Throws `NotImplementedException`** — not implemented. > **Note**: `BaseViewModel` inherits from `BasePropertyChanged` (not shown), implements `IBaseViewModel` (not shown), and requires `TModel : class`. --- ### 3. Invariants - **`ViewModelBase`**: - `InitializeAsync()` must return a `Task` 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`**: - `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` - **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` - **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.CleanupAsync()` is unimplemented** — throws `NotImplementedException`. Do not call this method. - **Redundant state flags**: Both `ViewModelBase` and `BaseViewModel` 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.Model` is `object`, while `BaseViewModel.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`) or rely on application logic (in `BaseViewModel`). - **`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` beyond its minimal design. For `BaseViewModel`, the above are the primary concerns.