Files
2026-04-17 14:55:32 -04:00

9.4 KiB
Raw Permalink Blame History

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.CommonCore/Base/ViewModel/ViewModelBase.cs
Common/DTS.CommonCore/Base/ViewModel/BaseViewModel.cs
2026-04-16T02:51:04.199849+00:00 Qwen/Qwen3-Coder-Next-FP8 1 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>).
  • DoRefreshs 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.