9.4 KiB
source_files, generated_at, model, schema_version, sha256
| source_files | generated_at | model | schema_version | sha256 | ||
|---|---|---|---|---|---|---|
|
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 asobject; cast toTinternally. -
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 theModelhas 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;
StandardINotifyPropertyChangedevent for property change notifications. -
protected abstract Task<T> InitializeAsync();
Override to implement async model initialization. The returnedTask<T>result is used to populate theModelproperty. -
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 theErrorOccurredevent. -
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 thePropertyChangedevent.
Note
:
ViewModelBase<T>implementsINotifyPropertyChangedandIViewModel(interface not shown), and inherits fromDependencyObject.
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 withViewModelBase<T>.Modelwhich isobject). -
public InteractionRequest<Confirmation> ConfirmationRequest { get; }
PrismInteractionRequestfor displaying confirmation dialogs. -
public DelegateCommand<object> CloseCommand { get; }
Command to close the view/viewmodel; executesCloseMethod, which in turn callsCleanupAtClose()→Cleanup(). -
protected virtual void CloseMethod(object parameter)
Default implementation invokesCleanupAtClose(). -
public virtual void Activated()
Hook called after viewmodel activation (e.g., by Prism region navigation). Default is no-op. -
public virtual void Initialize()
Publishes aShowStatusevent withStatusState.Busyand"Loading"message viaAggregator. -
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 ofInitialize(), marshalsShowStatuspublish to UI thread viaDispatcher.CurrentDispatcher.InvokeAsync. -
public virtual async Task InitializeAsync(object parameter)
Async version ofInitialize(object). -
public new event PropertyChangedEventHandler PropertyChanged;
Shadows basePropertyChangedevent (likely fromBasePropertyChanged, 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 withViewModelBase<T>.IsBusy; no synchronization between the two). -
public bool IsDirty { get; set; }
Dirty state flag (redundant withViewModelBase<T>.IsDirty; no synchronization). -
public virtual void Cleanup()
SetsModeltodefault(TModel). -
public Task CleanupAsync()
ThrowsNotImplementedException— not implemented.
Note
:
BaseViewModel<TModel>inherits fromBasePropertyChanged(not shown), implementsIBaseViewModel(not shown), and requiresTModel : class.
3. Invariants
-
ViewModelBase<T>:InitializeAsync()must return aTask<T>whose result is assigned toModel.OnModelChangedmust be called wheneverModelchanges (implementation responsibility of derived class).OnPropertyChangedmust be called for all property changes requiring UI updates.OnErrormust be called to raiseErrorOccurred.
-
BaseViewModel<TModel>:Initialize()/InitializeAsync()must publish aShowStatusevent withStatusInfo.StatusState.Busyand"Loading"message during initialization.CloseCommandalways triggersCleanup()(viaCleanupAtClose()).Cleanup()setsModel = default(TModel).IsBusy,IsDirty,Percentage,IsBusyMessage,IsMenuIncluded, andIsNavigationIncludedare 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(forShowStatus,StatusInfo,Strings). - Inherits:
BasePropertyChanged(unseen, assumed to provideINotifyPropertyChanged). - 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 — throwsNotImplementedException. Do not call this method.- Redundant state flags: Both
ViewModelBase<T>andBaseViewModel<TModel>defineIsBusyandIsDirty. There is no synchronization between them. If a class inherits from both (or uses both), these flags may diverge. Modeltype mismatch:ViewModelBase<T>.Modelisobject, whileBaseViewModel<TModel>.Modelis strongly-typedTModel. 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.BaseViewModelusesnew event PropertyChangedEventHandler— this shadows any basePropertyChanged(e.g., fromBasePropertyChanged), which may cause confusion if event handlers are attached to the wrong reference.- No automatic
IsBusy/IsDirtymanagement: Derived classes must manually updateIsBusy/IsDirty(inViewModelBase<T>) or rely on application logic (inBaseViewModel<TModel>). DoRefresh’s contract is underspecified: The source does not clarify how/whenDoRefreshshould be called or how it interacts withInitializeAsync.Strings.Strings.Loadingis referenced but not defined here — assumes aStringsresource class exists inDTS.Commonwith aLoadingproperty.
None identified from source alone for
ViewModelBase<T>beyond its minimal design. ForBaseViewModel<TModel>, the above are the primary concerns.