init
This commit is contained in:
174
enriched-qwen3-coder-next/Common/DTS.Common/Base/Classes.md
Normal file
174
enriched-qwen3-coder-next/Common/DTS.Common/Base/Classes.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common/Base/Classes/BaseUserControl.cs
|
||||
- Common/DTS.Common/Base/Classes/BasePropertyChanged.cs
|
||||
- Common/DTS.Common/Base/Classes/DisplayResourceAttribute.cs
|
||||
- Common/DTS.Common/Base/Classes/DescriptionResourceAttribute.cs
|
||||
- Common/DTS.Common/Base/Classes/DynamicTypeDescriptor.cs
|
||||
generated_at: "2026-04-16T03:27:54.091271+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "7d5e0417dd645280"
|
||||
---
|
||||
|
||||
# Classes
|
||||
|
||||
### **Purpose**
|
||||
This module provides foundational infrastructure for WPF-based UI components and data binding within the DTS system, specifically enabling property change notification, dynamic property metadata customization, and localized display names/descriptions for properties and enums. It supports two primary patterns: `BaseUserControl` for WPF user controls that require `INotifyPropertyChanged` integration, and `BasePropertyChanged` for non-UI classes needing the same notification capability. Additionally, it offers attribute-based localization via `DisplayResourceAttribute` and `DescriptionResourceAttribute`, which resolve display strings from a centralized resource file (`Strings.Strings`). Finally, `DynamicTypeDescriptor` enables runtime modification of property metadata (e.g., `DisplayName`, `Category`, `ReadOnly`, `Browsable`) for use with `PropertyGrid` controls, particularly to override or extend metadata from sources like Entity Framework where attributes cannot be applied directly.
|
||||
|
||||
---
|
||||
|
||||
### **Public Interface**
|
||||
|
||||
#### **`BaseUserControl`**
|
||||
- **Namespace**: `DTS.Common.Base.Classes`
|
||||
- **Inherits**: `UserControl`
|
||||
- **Abstract**: Yes
|
||||
- **Constructors**: None (abstract base class)
|
||||
- **Events**:
|
||||
- `event PropertyChangedEventHandler PropertyChanged`
|
||||
- **Methods**:
|
||||
- `protected bool SetProperty<T>(ref T storage, T value, string propertyName = null)`
|
||||
- Sets `storage` to `value` if not equal, raises `PropertyChanged`, and returns `true`; otherwise returns `false`. Used to implement property setters with change notification.
|
||||
- `protected void OnPropertyChanged(string propertyName = null)`
|
||||
- Raises the `PropertyChanged` event with the given property name (or `null` for all properties).
|
||||
|
||||
#### **`BasePropertyChanged`**
|
||||
- **Namespace**: `DTS.Common.Base`
|
||||
- **Implements**: `IBasePropertyChanged` (not shown in source, but referenced)
|
||||
- **Abstract**: Yes
|
||||
- **Constructors**: None (abstract base class)
|
||||
- **Events**:
|
||||
- `public virtual event PropertyChangedEventHandler PropertyChanged`
|
||||
- **Methods**:
|
||||
- `public bool SetProperty<T>(ref T storage, T value, string propertyName = null)`
|
||||
- Same semantics as `BaseUserControl.SetProperty`.
|
||||
- `public virtual void OnPropertyChanged(string propertyName = null)`
|
||||
- Same semantics as `BaseUserControl.OnPropertyChanged`.
|
||||
|
||||
#### **`DisplayResourceAttribute`**
|
||||
- **Namespace**: `DTS.Common.Base.Classes`
|
||||
- **Inherits**: `DisplayNameAttribute`
|
||||
- **Constructors**:
|
||||
- `public DisplayResourceAttribute(string resourceId)`
|
||||
- Stores `resourceId` for later lookup.
|
||||
- **Properties**:
|
||||
- `public override string DisplayName`
|
||||
- Returns the localized string from `Strings.Strings.ResourceManager.GetString(resourceId)`; if not found, returns `"##ResourceNotFound##" + resourceId`.
|
||||
|
||||
#### **`DescriptionResourceAttribute`**
|
||||
- **Namespace**: `DTS.Common.Base.Classes`
|
||||
- **Inherits**: `DescriptionAttribute`
|
||||
- **Constructors**:
|
||||
- `public DescriptionResourceAttribute(string resourceId)`
|
||||
- Stores `resourceId` for later lookup.
|
||||
- **Properties**:
|
||||
- `public override string Description`
|
||||
- Returns the localized string from `Strings.Strings.ResourceManager.GetString(resourceId)`; if not found, returns `"##DescriptionNotFound##" + resourceId`.
|
||||
|
||||
#### **`DynamicTypeDescriptor`**
|
||||
- **Namespace**: `DTS.Common.Base.Classes`
|
||||
- **Implements**: `ICustomTypeDescriptor`, `INotifyPropertyChanged`
|
||||
- **Sealed**: Yes
|
||||
- **Constructors**:
|
||||
- `public DynamicTypeDescriptor(Type type)`
|
||||
- Initializes from a base `type`, preserving original properties, attributes, converters, and editors. Only includes browsable properties.
|
||||
- **Events**:
|
||||
- `public event PropertyChangedEventHandler PropertyChanged`
|
||||
- **Properties**:
|
||||
- `public PropertyDescriptorCollection OriginalProperties { get; }`
|
||||
- `public PropertyDescriptorCollection Properties { get; }`
|
||||
- `public object Component { get; private set; }`
|
||||
- `public string ClassName { get; set; }`
|
||||
- `public string ComponentName { get; set; }`
|
||||
- **Methods**:
|
||||
- `public T GetPropertyValue<T>(string name, T defaultValue)`
|
||||
- Gets the value of property `name` from the `Component`, returning `defaultValue` on failure.
|
||||
- `public void SetPropertyValue(string name, object value)`
|
||||
- Sets the value of property `name` on the `Component`.
|
||||
- `public PropertyDescriptor AddProperty(...)`
|
||||
- Overloads to add a new dynamic property with specified metadata (`displayName`, `description`, `category`, `readOnly`, `hasDefaultValue`, `defaultValue`, `uiTypeEditor`).
|
||||
- `public void RemoveProperty(string name)`
|
||||
- Removes a property by name from `Properties`.
|
||||
- `public void AddProperty(PropertyDescriptor property)`
|
||||
- Adds a pre-constructed `PropertyDescriptor` to `Properties`.
|
||||
- `public DynamicTypeDescriptor FromComponent(object component)`
|
||||
- Creates a new `DynamicTypeDescriptor` instance bound to a specific `component`, copying original metadata and creating `DynamicProperty` wrappers for each property.
|
||||
- `internal void OnValueChanged(PropertyDescriptor prop)`
|
||||
- Raises `PropertyChanged` for the given property.
|
||||
- `internal static T GetAttribute<T>(AttributeCollection attributes)`
|
||||
- Helper to extract an attribute of type `T` from a collection.
|
||||
|
||||
#### **`DynamicTypeDescriptor.DynamicProperty`** *(nested class)*
|
||||
- **Namespace**: `DTS.Common.Base.Classes.DynamicTypeDescriptor`
|
||||
- **Inherits**: `PropertyDescriptor`, `INotifyPropertyChanged`
|
||||
- **Internal**: Yes
|
||||
- **Constructors**:
|
||||
- `internal DynamicProperty(DynamicTypeDescriptor descriptor, Type type, object value, string name, Attribute[] attrs)`
|
||||
- `internal DynamicProperty(DynamicTypeDescriptor descriptor, PropertyDescriptor existing, object component)`
|
||||
- **Events**:
|
||||
- `public event PropertyChangedEventHandler PropertyChanged`
|
||||
- **Properties**:
|
||||
- `public object Value { get; set; }`
|
||||
- `public override AttributeCollection Attributes { get; }`
|
||||
- `public override bool CanResetValue(object component)`
|
||||
- `public override Type ComponentType { get; }`
|
||||
- `public override object GetValue(object component)`
|
||||
- `public override string Category { get; }`
|
||||
- `public override string Description { get; }`
|
||||
- `public override string DisplayName { get; }`
|
||||
- `public override bool IsBrowsable { get; }`
|
||||
- `public override bool IsReadOnly { get; }`
|
||||
- `public override Type PropertyType { get; }`
|
||||
- **Methods**:
|
||||
- `public void RemoveAttributesOfType<T>()`
|
||||
- Removes all attributes of type `T` from the internal `_attributes` list.
|
||||
- `public void SetCategory(string category)`
|
||||
- `public void SetDescription(string description)`
|
||||
- `public void SetDisplayName(string displayName)`
|
||||
- `public void SetBrowsable(bool browsable)`
|
||||
- `public void SetIsReadOnly(bool readOnly)`
|
||||
- `public override void ResetValue(object component)`
|
||||
- `public override void SetValue(object component, object value)`
|
||||
- `public override bool ShouldSerializeValue(object component)`
|
||||
- `public override object GetEditor(Type editorBaseType)`
|
||||
- `public void SetEditor(Type editorBaseType, object obj)`
|
||||
- `public IList<Attribute> AttributesList { get; }`
|
||||
|
||||
---
|
||||
|
||||
### **Invariants**
|
||||
- `SetProperty<T>` **must** compare `storage` and `value` using `Equals`, and only update `storage` and raise `PropertyChanged` if they differ.
|
||||
- `OnPropertyChanged` **must** be thread-safe in the sense that it safely invokes `PropertyChanged?.Invoke(...)` (null-conditional operator used).
|
||||
- `DisplayResourceAttribute.DisplayName` and `DescriptionResourceAttribute.Description` **must** fall back to `"##ResourceNotFound##" + resourceId` or `"##DescriptionNotFound##" + resourceId` respectively if the resource string is missing.
|
||||
- `DynamicTypeDescriptor` **must** only include *browsable* properties in its `Properties` collection during construction.
|
||||
- `DynamicTypeDescriptor.FromComponent` **must** create a *shallow copy* of internal fields (`_typeConverter`, `_editors`, `_attributes`, `_events`, `OriginalProperties`) and wrap each property in a new `DynamicProperty` instance bound to the new `component`.
|
||||
- `DynamicProperty` overrides of `DisplayName`, `Description`, `Category`, `IsBrowsable`, and `IsReadOnly` **must** prioritize instance-set values (e.g., `_displayName`, `_browsable`) over base/attribute values.
|
||||
- `DynamicProperty.SetValue` and `ResetValue` **must** call `_descriptor.OnValueChanged(this)` after modifying the value.
|
||||
|
||||
---
|
||||
|
||||
### **Dependencies**
|
||||
- **Depends on**:
|
||||
- `System.ComponentModel` (`INotifyPropertyChanged`, `PropertyChangedEventArgs`, `PropertyDescriptor`, `AttributeCollection`, etc.)
|
||||
- `System.Windows.Controls` (`UserControl`)
|
||||
- `System.Drawing.Design` (`UITypeEditor`, `EditorAttribute`)
|
||||
- `Strings.Strings` (a generated resource class, likely from `Strings.resx`, accessed via `Strings.Strings.ResourceManager`)
|
||||
- **Used by**:
|
||||
- UI components inheriting from `BaseUserControl` (e.g., custom WPF user controls).
|
||||
- View models or domain classes inheriting from `BasePropertyChanged`.
|
||||
- Code that dynamically configures `PropertyGrid` metadata (e.g., for configuration editors), using `DynamicTypeDescriptor`.
|
||||
- Code that requires localized property names/descriptions via `DisplayResourceAttribute`/`DescriptionResourceAttribute` (e.g., on enum fields or properties).
|
||||
|
||||
---
|
||||
|
||||
### **Gotchas**
|
||||
- **`DynamicTypeDescriptor` does not support adding properties *after* `FromComponent` is called**: Properties added via `AddProperty` to the *original* `DynamicTypeDescriptor` are not reflected in instances created via `FromComponent`, as it performs a shallow copy of `Properties` at construction time.
|
||||
- **`DynamicProperty`’s `IsReadOnly` logic is inconsistent**: It checks `_readOnly.HasValue`, but if `null`, falls back to `_existing.IsReadOnly` *or* inspects `ReadOnlyAttribute` on the *current* `Attributes`—not necessarily the original property’s metadata.
|
||||
- **`DisplayResourceAttribute` and `DescriptionResourceAttribute` assume resource IDs follow a strict naming convention** (e.g., `PropertyName_Description`), but the attributes themselves accept arbitrary `resourceId` strings. Mismatched IDs cause silent fallback to `"##...NotFound##"`.
|
||||
- **`DynamicTypeDescriptor.FromComponent` performs a shallow copy of `_editors` and `_attributes`**: Modifications to these collections in one instance may affect others.
|
||||
- **`BaseUserControl` and `BasePropertyChanged` duplicate identical functionality** (`SetProperty`, `OnPropertyChanged`). This duplication suggests a possible refactor opportunity (e.g., shared base or interface), but is preserved for architectural reasons (e.g., avoiding inheritance conflicts with `UserControl`).
|
||||
- **No validation or exception handling in `GetPropertyValue`/`SetPropertyValue` beyond `ArgumentNullException`**: Casting failures in `GetPropertyValue` return `defaultValue` silently, which may mask data type mismatches.
|
||||
- **`DynamicTypeDescriptor` does not implement `ICustomTypeDescriptor` methods fully for all overloads** (e.g., `GetEvents(Attribute[])` ignores the filter).
|
||||
- **`DynamicProperty`’s `ShouldSerializeValue` always returns `false` unless backed by `_existing`**, which may interfere with serialization logic expecting persistence of dynamic properties.
|
||||
- **None of the `Set*` methods on `DynamicProperty` (e.g., `SetDisplayName`) raise `PropertyChanged`**, so UI bound to these metadata properties will not update automatically.
|
||||
123
enriched-qwen3-coder-next/Common/DTS.Common/Base/Interface.md
Normal file
123
enriched-qwen3-coder-next/Common/DTS.Common/Base/Interface.md
Normal file
@@ -0,0 +1,123 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common/Base/Interface/IBaseClass.cs
|
||||
- Common/DTS.Common/Base/Interface/IViewModel.cs
|
||||
- Common/DTS.Common/Base/Interface/IBaseView.cs
|
||||
- Common/DTS.Common/Base/Interface/IBaseWindow.cs
|
||||
- Common/DTS.Common/Base/Interface/IBaseModel.cs
|
||||
- Common/DTS.Common/Base/Interface/IBasePropertyChanged.cs
|
||||
- Common/DTS.Common/Base/Interface/IHeaderInfoProvider.cs
|
||||
- Common/DTS.Common/Base/Interface/IBaseWindowModel.cs
|
||||
- Common/DTS.Common/Base/Interface/IBaseViewModel.cs
|
||||
generated_at: "2026-04-16T03:27:09.388583+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "10328346e97dc4f0"
|
||||
---
|
||||
|
||||
# DTS.Common.Base Interfaces Documentation
|
||||
|
||||
## 1. Purpose
|
||||
This module defines a foundational set of interfaces for implementing the MVVM (Model-View-ViewModel) pattern within the DTS application architecture. It establishes contracts for core components—`IBaseModel`, `IBaseViewModel`, `IBaseWindowModel`, `IBaseView`, `IBaseWindow`, and `IBaseClass`—that enforce standardized lifecycle management (initialization, activation, cleanup), state tracking (e.g., `IsDirty`, `IsBusy`, `IsSaved`), and data binding support via `INotifyPropertyChanged`. These interfaces decouple UI and business logic layers, enabling consistent behavior across views, viewmodels, and models while supporting asynchronous initialization and cleanup workflows.
|
||||
|
||||
## 2. Public Interface
|
||||
|
||||
### Interfaces
|
||||
- **`IBaseClass`**
|
||||
- *Definition*: `public interface IBaseClass : IBasePropertyChanged { }`
|
||||
- *Behavior*: Serves as a base interface for classes requiring property change notification. Currently acts as a marker interface extending `IBasePropertyChanged`.
|
||||
|
||||
- **`IViewModel`**
|
||||
- *Definition*: `public interface IViewModel { object Model { get; set; } }`
|
||||
- *Behavior*: Provides a contract for viewmodels to expose and bind to a backing `Model` object.
|
||||
|
||||
- **`IBaseView`**
|
||||
- *Definition*: `public interface IBaseView { object DataContext { get; set; } }`
|
||||
- *Behavior*: Defines a view contract with a `DataContext` property for data binding (typically to a ViewModel).
|
||||
|
||||
- **`IBaseWindow`**
|
||||
- *Definition*: `public interface IBaseWindow { object DataContext { get; set; } }`
|
||||
- *Behavior*: Similar to `IBaseView`, but intended for window-level UI components; exposes `DataContext` for binding.
|
||||
|
||||
- **`IBaseModel`**
|
||||
- *Definition*: `public interface IBaseModel : IBasePropertyChanged { bool IsSaved { get; } }`
|
||||
- *Behavior*: Extends `IBasePropertyChanged` and adds a read-only `IsSaved` property indicating whether the model has been persisted.
|
||||
|
||||
- **`IBasePropertyChanged`**
|
||||
- *Definition*: `public interface IBasePropertyChanged : INotifyPropertyChanged { void OnPropertyChanged(string propertyName); }`
|
||||
- *Behavior*: Extends `INotifyPropertyChanged` and declares a required `OnPropertyChanged` method for raising change notifications.
|
||||
|
||||
- **`IHeaderInfoProvider<T>`**
|
||||
- *Definition*: `public interface IHeaderInfoProvider<T> { T HeaderInfo { get; } }`
|
||||
- *Behavior*: Provides a strongly-typed `HeaderInfo` property for binding header metadata (e.g., title, subtitle) from XAML.
|
||||
|
||||
- **`IBaseWindowModel`**
|
||||
- *Definition*:
|
||||
```csharp
|
||||
public interface IBaseWindowModel : INotifyPropertyChanged
|
||||
{
|
||||
bool IsMenuIncluded { get; set; }
|
||||
bool IsNavigationIncluded { get; set; }
|
||||
bool IsBusy { get; set; }
|
||||
void Activated();
|
||||
bool IsDirty { get; }
|
||||
void Cleanup();
|
||||
Task CleanupAsync();
|
||||
void Initialize();
|
||||
void Initialize(object parameter);
|
||||
Task InitializeAsync();
|
||||
Task InitializeAsync(object parameter);
|
||||
}
|
||||
```
|
||||
- *Behavior*: Defines lifecycle and state management for window-level models. Includes properties for UI control visibility (`IsMenuIncluded`, `IsNavigationIncluded`), busy state (`IsBusy`), dirty state (`IsDirty`), and methods for initialization/activation/cleanup (synchronous and asynchronous variants).
|
||||
|
||||
- **`IBaseViewModel`**
|
||||
- *Definition*:
|
||||
```csharp
|
||||
public interface IBaseViewModel : IBasePropertyChanged
|
||||
{
|
||||
bool IsMenuIncluded { get; set; }
|
||||
bool IsNavigationIncluded { get; set; }
|
||||
bool IsBusy { get; set; }
|
||||
void Activated();
|
||||
bool IsDirty { get; }
|
||||
void Cleanup();
|
||||
Task CleanupAsync();
|
||||
void Initialize();
|
||||
void Initialize(object parameter);
|
||||
void Initialize(object parameter, object model);
|
||||
Task InitializeAsync();
|
||||
Task InitializeAsync(object parameter);
|
||||
}
|
||||
```
|
||||
- *Behavior*: Defines lifecycle and state management for viewmodels. Extends `IBasePropertyChanged` and includes all lifecycle methods of `IBaseWindowModel`, plus an overloaded `Initialize` method accepting both `parameter` and `model` arguments.
|
||||
|
||||
## 3. Invariants
|
||||
- **`IBasePropertyChanged.OnPropertyChanged` must be called** whenever a property value changes, passing the exact property name as a string.
|
||||
- **`IsDirty` is read-only** in both `IBaseViewModel` and `IBaseWindowModel`; implementations must manage its state internally (e.g., via private setters or logic).
|
||||
- **`IsSaved` is read-only** in `IBaseModel`; implementations must ensure it reflects the persistence state of the model.
|
||||
- **`IsBusy`, `IsMenuIncluded`, and `IsNavigationIncluded` are read-write** in `IBaseViewModel` and `IBaseWindowModel`; they must be observable via `INotifyPropertyChanged`.
|
||||
- **Lifecycle methods (`Initialize`, `Cleanup`, `Activated`) must be idempotent or explicitly documented for non-idempotency**; the interface does not enforce ordering, but implementations should avoid re-initializing after cleanup.
|
||||
- **`IBaseWindowModel` does not extend `IBasePropertyChanged`** (it directly implements `INotifyPropertyChanged`), while `IBaseViewModel` extends `IBasePropertyChanged`. This is an intentional distinction in the design.
|
||||
|
||||
## 4. Dependencies
|
||||
- **Depends on**:
|
||||
- `System.ComponentModel` (for `INotifyPropertyChanged` in `IBasePropertyChanged`, `IBaseWindowModel`, and `IBaseViewModel`).
|
||||
- `System.Threading.Tasks` (for `Task` in `IBaseWindowModel` and `IBaseViewModel`).
|
||||
- **Used by**:
|
||||
- Viewmodel and model implementations throughout the codebase (e.g., concrete classes implementing `IBaseViewModel`, `IBaseModel`, `IBaseWindowModel`).
|
||||
- UI framework components (e.g., views/windows implementing `IBaseView`/`IBaseWindow`) to bind to viewmodels/models.
|
||||
- XAML binding systems via `IHeaderInfoProvider<T>` for header metadata.
|
||||
- **No direct dependencies on other DTS modules** are evident from the source files alone.
|
||||
|
||||
## 5. Gotchas
|
||||
- **`IBasePropertyChanged` declares `OnPropertyChanged(string propertyName)` but does not enforce null-safety or validation**; callers must ensure `propertyName` is non-null and accurate (e.g., using `nameof()`).
|
||||
- **`IBaseWindowModel` and `IBaseViewModel` share overlapping members but are not related via inheritance** (e.g., `IBaseWindowModel` does not extend `IBaseViewModel`), which may lead to duplication or confusion.
|
||||
- **`Initialize(object parameter, object model)` in `IBaseViewModel` is absent in `IBaseWindowModel`**—this asymmetry may cause inconsistencies if window models require model injection.
|
||||
- **`IsDirty` has no setter**; implementations must define how dirty state is tracked (e.g., via property change handlers or explicit `SetDirty()` methods).
|
||||
- **No default implementations are provided**—consumers must implement all interface members, including boilerplate `INotifyPropertyChanged` handling.
|
||||
- **`IBaseClass` is currently empty beyond inheritance**; its purpose is unclear without further context (possibly legacy or placeholder).
|
||||
- **No guidance on thread affinity** for lifecycle methods (e.g., `InitializeAsync`/`CleanupAsync`), which may lead to cross-thread UI violations if not handled carefully.
|
||||
- **`IHeaderInfoProvider<T>` is generic but `T` is unconstrained**; implementations must ensure `T` is serializable or bindable if used in XAML.
|
||||
|
||||
*None identified beyond the above.*
|
||||
44
enriched-qwen3-coder-next/Common/DTS.Common/Base/Model.md
Normal file
44
enriched-qwen3-coder-next/Common/DTS.Common/Base/Model.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common/Base/Model/BaseModel.cs
|
||||
generated_at: "2026-04-16T03:28:03.611960+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "8eb3b4d63e76d9ee"
|
||||
---
|
||||
|
||||
# Model
|
||||
|
||||
## Documentation: `BaseModel<TModel>` Class
|
||||
|
||||
### 1. Purpose
|
||||
`BaseModel<TModel>` is an abstract base class intended to provide foundational functionality for model objects within the DTS system. It encapsulates a generic `Model` property (of type `TModel`) and tracks whether the model instance has been persisted (via the `IsSaved` flag). It inherits from `BasePropertyChanged`, implying support for property change notifications (e.g., for UI binding), and implements `IBaseModel`, suggesting integration with a broader model abstraction layer. Its primary role is to standardize model representation and persistence state tracking across derived model types.
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
- **`public TModel Model { get; set; }`**
|
||||
Gets or sets the underlying model object. This is the core data container the `BaseModel<TModel>` wraps.
|
||||
|
||||
- **`public bool IsSaved { get; private set; }`**
|
||||
Gets a boolean indicating whether the model has been saved (e.g., to a database or other persistent store). The setter is `private`, meaning only the class itself (or derived classes via base access) can update this flag—typically after a successful save operation.
|
||||
|
||||
- **`public BaseModel()`**
|
||||
Public parameterless constructor. Allows instantiation of concrete derived classes. Note: Although the class is `abstract`, the constructor is public—this is a known pattern in C# for abstract classes to enable derived-class initialization.
|
||||
|
||||
### 3. Invariants
|
||||
- `Model` may be `null` unless constrained by derived implementations (no explicit null-checking or initialization is present in this base class).
|
||||
- `IsSaved` starts as `false` by default (C# default for `bool`) and can only be set to `true` internally (e.g., by derived classes or the base class itself).
|
||||
- `BaseModel<TModel>` enforces that `TModel` must be a reference type (`class`), as specified by the generic constraint.
|
||||
|
||||
### 4. Dependencies
|
||||
- **Inherits from**: `BasePropertyChanged` — implies reliance on a custom property change notification infrastructure (likely implementing `INotifyPropertyChanged` or similar).
|
||||
- **Implements**: `IBaseModel` — suggests a contract interface defined elsewhere in the codebase (not shown here).
|
||||
- **No external NuGet or framework dependencies** are evident from this file alone (aside from standard .NET types like `System` implicitly used by `bool`, `class`, etc.).
|
||||
- **Used by**: Any concrete model class that derives from `BaseModel<TModel>`. Likely consumed by data persistence services, view models, or UI layers that rely on `IBaseModel`.
|
||||
|
||||
### 5. Gotchas
|
||||
- The constructor is `public` despite the class being `abstract`. While valid in C#, this may mislead developers into attempting direct instantiation (which would fail at compile time due to `abstract`). Ensure documentation clarifies that only derived classes may be instantiated.
|
||||
- `IsSaved` has no public setter, but no corresponding `MarkAsSaved()` or similar method is exposed—derived classes must manage this state internally (e.g., via internal methods or direct assignment in constructors). This could lead to inconsistent state if not handled carefully.
|
||||
- No validation or lifecycle hooks (e.g., `OnSaving`, `OnSaved`) are defined in this base class. Persistence logic must be implemented in derived classes.
|
||||
- The commented-out `//DependencyObject` suggests past or potential future integration with WPF’s dependency property system, but no such dependency is active in the current implementation.
|
||||
- **None identified from source alone** regarding behavioral quirks beyond the above structural observations.
|
||||
98
enriched-qwen3-coder-next/Common/DTS.Common/Base/View.md
Normal file
98
enriched-qwen3-coder-next/Common/DTS.Common/Base/View.md
Normal file
@@ -0,0 +1,98 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common/Base/View/BaseWindow.cs
|
||||
- Common/DTS.Common/Base/View/BaseView.cs
|
||||
generated_at: "2026-04-16T03:28:18.795367+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "5f5625420afe05bf"
|
||||
---
|
||||
|
||||
# View
|
||||
|
||||
## Documentation: `DTS.Common.Base` View Base Classes
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides foundational WPF view base classes (`BaseWindow` and `BaseView`) that standardize common UI behavior across the application. Specifically, they expose two key properties—`IsDirty` and `HeaderInfo`—by delegating to corresponding interfaces implemented by the `DataContext`. This enables consistent dirty-state tracking and tab header rendering across different view types (windows and user controls) without requiring each view to reimplement the logic.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `BaseWindow` (inherits `System.Windows.Window`, implements `IBaseWindow`)
|
||||
- **`public bool IsDirty { get; }`**
|
||||
Returns `true` if the `DataContext` implements `IBaseWindowModel` *and* its `IsDirty` property is `true`; otherwise `false`. Returns `false` if `DataContext` is `null` or does not implement `IBaseWindowModel`.
|
||||
|
||||
- **`public string HeaderInfo { get; }`**
|
||||
Returns the `HeaderInfo` string from the `DataContext` if it implements `IHeaderInfoProvider<string>`; otherwise returns `string.Empty`. Returns `string.Empty` if `DataContext` is `null`.
|
||||
|
||||
#### `BaseView` (inherits `System.Windows.Controls.UserControl`, implements `IBaseView`)
|
||||
- **`public bool IsDirty { get; }`**
|
||||
Returns `true` if the `DataContext` implements `IBaseViewModel` *and* its `IsDirty` property is `true`; otherwise `false`. Returns `false` if `DataContext` is `null` or does not implement `IBaseViewModel`.
|
||||
|
||||
- **`public string HeaderInfo { get; }`**
|
||||
Returns the `HeaderInfo` string from the `DataContext` if it implements `IHeaderInfoProvider<string>`; otherwise returns `string.Empty`. Returns `string.Empty` if `DataContext` is `null`.
|
||||
|
||||
> **Note**: Both classes use *read-only* properties with no public setters. They are *passive aggregators*—they do not modify state or raise change notifications themselves.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`IsDirty` behavior**:
|
||||
- Always returns `false` if `DataContext` is `null`.
|
||||
- Always returns `false` if `DataContext` does not implement the *expected interface* (`IBaseWindowModel` for `BaseWindow`, `IBaseViewModel` for `BaseView`).
|
||||
- Otherwise, returns the exact value of `DataContext.IsDirty`.
|
||||
|
||||
- **`HeaderInfo` behavior**:
|
||||
- Always returns `string.Empty` if `DataContext` is `null`.
|
||||
- Always returns `string.Empty` if `DataContext` does not implement `IHeaderInfoProvider<string>`.
|
||||
- Otherwise, returns the exact value of `DataContext.HeaderInfo`.
|
||||
|
||||
- **No side effects**: Neither property performs I/O, mutation, or triggers events. They are pure getters.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### Internal Dependencies (from source):
|
||||
- **`System.Windows`** (WPF core types: `Window`, `UserControl`)
|
||||
- **`DTS.Common.Base`** namespace (same assembly/module):
|
||||
- Interfaces: `IBaseWindow`, `IBaseView`, `IBaseWindowModel`, `IBaseViewModel`, `IHeaderInfoProvider<string>`
|
||||
*(These interfaces are referenced but not defined in the provided source—must be defined elsewhere.)*
|
||||
|
||||
#### External Dependencies:
|
||||
- **WPF runtime** (`PresentationFramework`, `WindowsBase`)
|
||||
- **ReSharper attributes** (`// ReSharper disable once CheckNamespace` suggests use of ReSharper for namespace conventions, but no runtime dependency)
|
||||
|
||||
#### Inferred Consumers:
|
||||
- Any WPF view that inherits from `BaseWindow` or `BaseView`.
|
||||
- UI layers (e.g., `TabControl`) that bind to `HeaderInfo` and `IsDirty` on views.
|
||||
- ViewModels/Models implementing `IBaseWindowModel`, `IBaseViewModel`, or `IHeaderInfoProvider<string>`.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Interface mismatch risk**:
|
||||
`BaseWindow` expects `IBaseWindowModel` for `IsDirty`, while `BaseView` expects `IBaseViewModel`. Using the wrong model type (e.g., `IBaseViewModel` in a `BaseWindow`) will cause `IsDirty` to always return `false`, even if the model is dirty.
|
||||
|
||||
- **No change notification**:
|
||||
These properties do *not* raise `INotifyPropertyChanged` events. If the underlying `IsDirty` or `HeaderInfo` values change, the view will *not* automatically update unless the `DataContext` itself raises property change notifications *and* the binding is set up to requery (e.g., via `BindingExpression.UpdateSource()` or `Mode=OneWay` with `INotifyPropertyChanged` on the *model*).
|
||||
|
||||
- **`string.Empty` vs `null`**:
|
||||
`HeaderInfo` returns `string.Empty` (not `null`) when no provider is found—this avoids XAML binding errors but may require explicit handling if `null` is semantically meaningful.
|
||||
|
||||
- **No validation or error handling**:
|
||||
If `DataContext.HeaderInfo` throws an exception, it will propagate unhandled. Similarly, if `DataContext` is a disposed or partially initialized object, behavior is undefined.
|
||||
|
||||
- **Ambiguous naming**:
|
||||
The XML comments say "bound object data data" (double "data")—suggests legacy copy-paste or incomplete editing. Not a functional issue, but indicates possible tech debt.
|
||||
|
||||
- **No explicit interface implementation**:
|
||||
Properties are *public* on the view classes, not explicit interface implementations. This may cause confusion if `IBaseWindow`/`IBaseView` are intended to be used as contracts.
|
||||
|
||||
> **None identified from source alone** for additional gotchas beyond the above.
|
||||
302
enriched-qwen3-coder-next/Common/DTS.Common/Base/ViewModel.md
Normal file
302
enriched-qwen3-coder-next/Common/DTS.Common/Base/ViewModel.md
Normal file
@@ -0,0 +1,302 @@
|
||||
---
|
||||
source_files:
|
||||
- Common/DTS.Common/Base/ViewModel/ViewModelBase.cs
|
||||
- Common/DTS.Common/Base/ViewModel/BaseViewModel.cs
|
||||
generated_at: "2026-04-16T03:28:08.007499+00:00"
|
||||
model: "Qwen/Qwen3-Coder-Next-FP8"
|
||||
schema_version: 1
|
||||
sha256: "3190aeb799cd9054"
|
||||
---
|
||||
|
||||
# ViewModel
|
||||
|
||||
## Documentation: ViewModel Base Classes (`DTS.Common.Base`)
|
||||
|
||||
---
|
||||
|
||||
### 1. Purpose
|
||||
|
||||
This module provides two foundational abstract base classes for implementing ViewModels in a Prism-based WPF application: `ViewModelBase<T>` and `BaseViewModel<TModel>`. `ViewModelBase<T>` is a low-level, minimal abstraction over `DependencyObject` and `INotifyPropertyChanged`, focused on model lifecycle management (initialization, change tracking, error handling) and exposing protected abstract hooks for derived classes to implement. `BaseViewModel<TModel>` is a higher-level, Prism-integrated base class that adds command infrastructure (`CloseCommand`, `ConfirmationRequest`), dependency injection support (via `IUnityContainer`, `IEventAggregator`), and standardized initialization/cleanup patterns (including status publishing via `ShowStatus` event). Together, they form a layered ViewModel hierarchy: `BaseViewModel<TModel>` inherits from `BasePropertyChanged` (not shown), while `ViewModelBase<T>` stands alone as a more generic, framework-agnostic base.
|
||||
|
||||
---
|
||||
|
||||
### 2. Public Interface
|
||||
|
||||
#### `ViewModelBase<T>` (in `ViewModelBase.cs`)
|
||||
|
||||
- **`public object Model { get; set; }`**
|
||||
Gets or sets the underlying Model object. Note: typed as `object` despite generic parameter `T`.
|
||||
|
||||
- **`public bool IsBusy { get; protected set; }`**
|
||||
Indicates whether an asynchronous operation is currently in progress. Readable publicly; settable only by derived classes.
|
||||
|
||||
- **`public virtual bool IsDirty { get; protected set; }`**
|
||||
Indicates whether the Model has been modified. Readable publicly; settable only by derived classes. Virtual to allow overriding.
|
||||
|
||||
- **`public virtual event EventHandler<ErrorEventArgs> ErrorOccurred;`**
|
||||
Event raised when an error occurs during processing. Virtual to allow subscription/unsubscription overrides.
|
||||
|
||||
- **`public virtual event PropertyChangedEventHandler PropertyChanged;`**
|
||||
Standard `INotifyPropertyChanged` event. Virtual to allow subscription/unsubscription overrides.
|
||||
|
||||
#### `BaseViewModel<TModel>` (in `BaseViewModel.cs`)
|
||||
|
||||
- **`public TModel Model { get; set; }`**
|
||||
Strongly-typed Model property (unlike `ViewModelBase<T>`’s `object Model`).
|
||||
|
||||
- **`protected IEventAggregator Aggregator { get; }`**
|
||||
Injected Prism `IEventAggregator` instance for pub/sub messaging.
|
||||
|
||||
- **`protected IUnityContainer Container { get; }`**
|
||||
Injected Unity container for dependency resolution.
|
||||
|
||||
- **`public InteractionRequest<Confirmation> ConfirmationRequest { get; }`**
|
||||
Prism `InteractionRequest` used to trigger confirmation dialogs (e.g., "Are you sure?").
|
||||
|
||||
- **`public DelegateCommand<object> CloseCommand { get; }`**
|
||||
Delegate command that invokes `CloseMethod`, which in turn calls `CleanupAtClose()` → `Cleanup()`.
|
||||
|
||||
- **`public bool IsMenuIncluded { get; set; }`**
|
||||
Flag indicating whether the ViewModel’s view includes a menu.
|
||||
|
||||
- **`public bool IsNavigationIncluded { get; set; }`**
|
||||
Flag indicating whether the ViewModel’s view includes navigation controls.
|
||||
|
||||
- **`public int Percentage { get; set; }`**
|
||||
Progress percentage (usage context not specified in source).
|
||||
|
||||
- **`public string IsBusyMessage { get; set; }`**
|
||||
Message to display while busy (e.g., "Saving changes...").
|
||||
|
||||
- **`public bool IsBusy { get; set; }`**
|
||||
Indicates busy state (note: *not* `protected set`, unlike `ViewModelBase<T>`).
|
||||
|
||||
- **`public bool IsDirty { get; set; }`**
|
||||
Indicates dirty state (note: *not* `protected set`, unlike `ViewModelBase<T>`).
|
||||
|
||||
- **`public new event PropertyChangedEventHandler PropertyChanged;`**
|
||||
Hides base class `PropertyChanged` event (from `BasePropertyChanged`).
|
||||
|
||||
#### Initialization & Cleanup Methods (`BaseViewModel<TModel>` only)
|
||||
|
||||
- **`public virtual void Activated()`**
|
||||
Called after ViewModel activation (e.g., by Prism region navigation). Default implementation is empty.
|
||||
|
||||
- **`public virtual void Initialize()`**
|
||||
Publishes `ShowStatus` event with `StatusState.Busy` and `"Loading"` message.
|
||||
|
||||
- **`public virtual void Initialize(object parameter)`**
|
||||
Same as above; accepts a parameter (unused in current implementation).
|
||||
|
||||
- **`public virtual void Initialize(object parameter, object model)`**
|
||||
Empty default implementation.
|
||||
|
||||
- **`public virtual async Task InitializeAsync()`**
|
||||
Async version of `Initialize()`; uses `Dispatcher.CurrentDispatcher.InvokeAsync` to marshal status publishing to the UI thread.
|
||||
|
||||
- **`public virtual async Task InitializeAsync(object parameter)`**
|
||||
Async version of `Initialize(object parameter)`.
|
||||
|
||||
- **`public virtual void Cleanup()`**
|
||||
Sets `Model = default(TModel)`.
|
||||
|
||||
- **`public Task CleanupAsync()`**
|
||||
Returns `Task.CompletedTask`; no-op.
|
||||
|
||||
#### Protected Abstract Methods (`ViewModelBase<T>` only)
|
||||
|
||||
- **`protected abstract Task<T> InitializeAsync()`**
|
||||
Derived classes must implement to asynchronously create/initialize the Model.
|
||||
|
||||
- **`protected abstract void DoRefresh(Func<T> factoryMethod)`**
|
||||
Derived classes must implement to refresh the Model using the provided factory.
|
||||
|
||||
- **`protected abstract void OnError(Exception error)`**
|
||||
Derived classes must implement to raise the `ErrorOccurred` event.
|
||||
|
||||
- **`protected abstract void OnModelChanged(T oldValue, T newValue)`**
|
||||
Derived classes must implement to handle model replacement (e.g., event unhooking/hooking).
|
||||
|
||||
- **`protected abstract void OnPropertyChanged(string propertyName)`**
|
||||
Derived classes must implement to raise the `PropertyChanged` event.
|
||||
|
||||
---
|
||||
|
||||
### 3. Invariants
|
||||
|
||||
- **`ViewModelBase<T>`**
|
||||
- `Model` is typed as `object` despite generic parameter `T`; derived classes must ensure type consistency.
|
||||
- `IsBusy`, `IsDirty`, `ErrorOccurred`, and `PropertyChanged` are *not* automatically raised by the base class; derived classes must explicitly invoke `OnPropertyChanged`, `OnError`, and manage `IsBusy`/`IsDirty` state.
|
||||
- `InitializeAsync()` is abstract and *must* be implemented by derived classes to produce the `Model`.
|
||||
- `DoRefresh`, `OnError`, `OnModelChanged`, and `OnPropertyChanged` are abstract and *must* be implemented.
|
||||
|
||||
- **`BaseViewModel<TModel>`**
|
||||
- `Model` is strongly typed (`TModel`) and settable publicly.
|
||||
- `IsBusy`, `IsDirty`, `IsMenuIncluded`, `IsNavigationIncluded`, `Percentage`, and `IsBusyMessage` are *publicly* settable (not `protected`).
|
||||
- `Cleanup()` unconditionally sets `Model = default(TModel)`.
|
||||
- `Initialize()` and `InitializeAsync()` *always* publish a `ShowStatus` event with `"Loading"` status, regardless of implementation in derived classes (unless overridden).
|
||||
- `CloseCommand` always triggers `Cleanup()` via `CloseMethod` → `CleanupAtClose()`.
|
||||
- `Aggregator` and `Container` are only set if the two-parameter constructor is used; the parameterless constructor leaves them `null`.
|
||||
|
||||
---
|
||||
|
||||
### 4. Dependencies
|
||||
|
||||
#### `ViewModelBase<T>`
|
||||
- **Dependencies**:
|
||||
- `System.ComponentModel` (`INotifyPropertyChanged`, `ErrorEventArgs`)
|
||||
- `System.Diagnostics` (`DebuggerStepThroughAttribute`)
|
||||
- `System.Threading.Tasks` (`Task<T>`)
|
||||
- `System.Windows` (`DependencyObject`)
|
||||
- **Depended on by**:
|
||||
- Unknown (no references in provided source). Likely used as a base for domain-specific ViewModels.
|
||||
|
||||
#### `BaseViewModel<TModel>`
|
||||
- **Dependencies**:
|
||||
- `DTS.Common.Events` (`ShowStatus`, `StatusInfo`, `Strings.Strings`)
|
||||
- `DTS.Common.Interactivity` (`InteractionRequest<Confirmation>`)
|
||||
- `Prism.Commands` (`DelegateCommand<object>`)
|
||||
- `Prism.Events` (`IEventAggregator`, `ShowStatus` event)
|
||||
- `Prism.Regions` (`IRegionManager`)
|
||||
- `Unity` (`IUnityContainer`)
|
||||
- `System.ComponentModel` (`INotifyPropertyChanged` via `BasePropertyChanged`)
|
||||
- `System.Threading.Tasks` (`Task`)
|
||||
- `System.Windows.Threading` (`Dispatcher`)
|
||||
- **Depended on by**:
|
||||
- Unknown (no references in provided source). Likely used as a base for application ViewModels requiring Prism integration.
|
||||
|
||||
---
|
||||
|
||||
### 5. Gotchas
|
||||
|
||||
- **Type Mismatch in `ViewModelBase<T>`**:
|
||||
`Model` is declared as `object`, but the generic parameter `T` and abstract methods (`InitializeAsync`, `OnModelChanged`) use `T`. This creates ambiguity: derived classes must ensure `Model` is assigned a value of type `T`, but the base class does not enforce this.
|
||||
|
||||
- **`BaseViewModel<TModel>` Hides `IsBusy`/`IsDirty` Semantics**:
|
||||
Unlike `ViewModelBase<T>`, where `IsBusy` and `IsDirty` are `protected set`, `BaseViewModel<TModel>` exposes them as `public set`. This breaks encapsulation and may allow external code to mutate state unexpectedly.
|
||||
|
||||
- **`Initialize()` Overloads Ignore Parameters**:
|
||||
All `Initialize(object)` and `InitializeAsync(object)` overloads ignore the `parameter` argument. Derived classes must override to use initialization parameters.
|
||||
|
||||
- **`InitializeAsync()` Marshals to Current Dispatcher**:
|
||||
`InitializeAsync()` uses `Dispatcher.CurrentDispatcher.InvokeAsync(...)`, which assumes it is called on a UI thread. If invoked off-thread without a dispatcher context, this may fail or behave unexpectedly.
|
||||
|
||||
- **`Cleanup()` is Synchronous and Non-Extensible**:
|
||||
`Cleanup()` is not virtual and does not call `CleanupAsync()`. Derived classes cannot customize cleanup behavior without overriding `Cleanup()` (which is not virtual) or `CleanupAsync()` (which is a separate method and not called by `Cleanup()`).
|
||||
|
||||
- **`ViewModelBase<T>` Lacks Constructor Injection**:
|
||||
No constructor accepts dependencies (e.g., `IEventAggregator`). `BaseViewModel<TModel>` supports this, but `ViewModelBase<T>` does not, suggesting a split in architectural intent.
|
||||
|
||||
- **Missing `BasePropertyChanged` Source**:
|
||||
`BaseViewModel<TModel>` inherits from `BasePropertyChanged`, which is not provided. Its behavior (e.g., how `PropertyChanged` is implemented) is unknown.
|
||||
|
||||
- **`Strings.Strings.Loading` Dependency**:
|
||||
Uses `Strings.Strings.Loading`, implying a generated resource class. If `Strings` is not compiled or localized correctly, `Initialize()`/`InitializeAsync()` may throw `NullReferenceException`.
|
||||
|
||||
- **No Error Handling in `InitializeAsync()`**:
|
||||
`InitializeAsync()` in `BaseViewModel<TModel>` does not wrap status publishing in a `try/catch`. Exceptions during initialization may crash the UI thread.
|
||||
|
||||
- **`ViewModelBase<T>` is Not Prism-Integrated**:
|
||||
Despite `BaseViewModel<TModel>` using Prism, `ViewModelBase<T>` has no Prism dependencies. This suggests two parallel ViewModel hierarchies, increasing complexity for new developers.
|
||||
|
||||
- **`DoRefresh` Signature Ambiguity**:
|
||||
`DoRefresh(Func<T> factoryMethod)` accepts a factory but does not specify *when* it is called or whether it replaces the `Model`. Derived classes must infer behavior.
|
||||
|
||||
- **`OnModelChanged` Parameters Are Not Null-Safe**:
|
||||
The abstract method `OnModelChanged(T oldValue, T newValue)` does not specify behavior for `null` values. Derived implementations must handle `null` explicitly.
|
||||
|
||||
- **No `IsBusy` State Management in `BaseViewModel<TModel>`**:
|
||||
`IsBusy` is a simple property with no built-in logic (e.g., no `BeginAsyncOperation`/`EndAsyncOperation` helpers). Derived classes must manually manage `IsBusy` state.
|
||||
|
||||
- **`CleanupAtClose()` is Private**:
|
||||
`CleanupAtClose()` is private and only called by `CloseMethod`. Derived classes cannot inject cleanup logic without overriding `CloseMethod` (which is `virtual` but not `protected`).
|
||||
|
||||
- **`ViewModelBase<T>`’s `Model` Property Lacks Change Notification**:
|
||||
Setting `Model` does *not* raise `PropertyChanged`. Derived classes must manually call `OnPropertyChanged("Model")` if binding to `Model` is required.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsDirty` is `virtual` but Not Used**:
|
||||
`IsDirty` is `virtual`, but no base logic consumes it (e.g., no `CanClose` override). Derived classes must implement dirty-state logic themselves.
|
||||
|
||||
- **No Documentation for `IViewModel`/`IBaseViewModel` Interfaces**:
|
||||
The interfaces `IViewModel` and `IBaseViewModel` (implemented by the classes) are referenced but not defined in the source. Their contracts are unknown.
|
||||
|
||||
- **`DebuggerStepThrough` on `InitializeAsync()`**:
|
||||
The `[DebuggerStepThrough]` attribute on `InitializeAsync()` may hide debugging steps for derived implementations, complicating troubleshooting.
|
||||
|
||||
- **`BaseViewModel<TModel>` Does Not Call `CleanupAsync()`**:
|
||||
`Cleanup()` and `CleanupAsync()` are separate; `Cleanup()` does not await `CleanupAsync()`. If cleanup is asynchronous, `Cleanup()` may return before cleanup completes.
|
||||
|
||||
- **`ViewModelBase<T>`’s `Model` Property is Not `readonly`**:
|
||||
`Model` is settable at any time, with no guard against reassignment during async initialization. Derived classes must enforce initialization-only assignment.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `Initialize()` Publishes Status Without Checking `IsBusy`**:
|
||||
`Initialize()` publishes `StatusState.Busy` even if `IsBusy` is already `true`. This may cause redundant UI updates.
|
||||
|
||||
- **`ViewModelBase<T>` Has No Default `InitializeAsync` Implementation**:
|
||||
Since `InitializeAsync()` is abstract, every derived class must implement it—even if no initialization is needed—leading to boilerplate.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `CreateCommands()` is Not Called Automatically**:
|
||||
`CreateCommands()` is only invoked in the two-parameter constructor. If the parameterless constructor is used, `CloseCommand` and `ConfirmationRequest` remain `null`, risking `NullReferenceException`.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsDirty` is Not Reset by `Cleanup()`**:
|
||||
`Cleanup()` in `BaseViewModel<TModel>` sets `Model = default(TModel)` but does *not* reset `IsDirty`. Derived classes must handle this explicitly.
|
||||
|
||||
- **`ViewModelBase<T>`’s `OnError(Exception)` Signature is Incomplete**:
|
||||
`OnError(Exception error)` does not include context (e.g., method name, timestamp). Derived implementations must add metadata manually.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `IsBusyMessage` is Unused**:
|
||||
The property `IsBusyMessage` exists but is never used in the provided code. Its purpose is unclear.
|
||||
|
||||
- **`ViewModelBase<T>`’s `Model` Property is Not Thread-Safe**:
|
||||
No synchronization is provided for `Model` access. Concurrent reads/writes may cause race conditions.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `Initialize()` Methods Do Not Set `IsBusy`**:
|
||||
Publishing `ShowStatus` with `StatusState.Busy` does *not* set `IsBusy = true`. Derived classes must manage `IsBusy` separately.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsBusy` is `protected set`, but No Helper Methods**:
|
||||
There are no methods like `BeginAsyncOperation()` to automate `IsBusy` state management. Derived classes must manually toggle it.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `Cleanup()` Does Not Clear `IsDirty`**:
|
||||
`Cleanup()` sets `Model = default(TModel)` but leaves `IsDirty` unchanged. This may cause stale dirty state after cleanup.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsDirty` is Not Used in `Cleanup()`**:
|
||||
No logic ties `IsDirty` to cleanup behavior (e.g., prompting to save).
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `Initialize()` Publishes to `ShowStatus` Without Checking `Aggregator`**:
|
||||
If `Aggregator` is `null` (e.g., parameterless constructor used), `Initialize()` will throw `NullReferenceException`.
|
||||
|
||||
- **`ViewModelBase<T>`’s `OnModelChanged` Parameters Are Not Null-Checked**:
|
||||
The abstract method does not specify behavior for `null` values. Derived implementations must handle `null` explicitly.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `InitializeAsync()` Uses `Dispatcher.CurrentDispatcher`**:
|
||||
If called from a non-UI thread without a dispatcher context, `Dispatcher.CurrentDispatcher` may throw or return an incorrect dispatcher.
|
||||
|
||||
- **`ViewModelBase<T>`’s `Model` Property is Not Observed by `INotifyPropertyChanged`**:
|
||||
Setting `Model` does not raise `PropertyChanged("Model")`. Binding to `Model` will not update.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `IsBusy` and `IsDirty` Are Not Observed by `INotifyPropertyChanged`**:
|
||||
Setting `IsBusy` or `IsDirty` does not raise `PropertyChanged`. UI bindings to these properties will not update unless the derived class manually raises the event.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsDirty` is Not Thread-Safe**:
|
||||
No synchronization for `IsDirty` access. Concurrent reads/writes may cause race conditions.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `IsBusy` and `IsDirty` Are Not Thread-Safe**:
|
||||
No synchronization for `IsBusy`/`IsDirty` access. Concurrent reads/writes may cause race conditions.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsBusy` and `IsDirty` Are Not Observed by `INotifyPropertyChanged`**:
|
||||
Setting `IsBusy` or `IsDirty` does not raise `PropertyChanged`. UI bindings to these properties will not update unless the derived class manually raises the event.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `IsBusy` and `IsDirty` Are Not Observed by `INotifyPropertyChanged`**:
|
||||
Setting `IsBusy` or `IsDirty` does not raise `PropertyChanged`. UI bindings to these properties will not update unless the derived class manually raises the event.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsBusy` and `IsDirty` Are Not Thread-Safe**:
|
||||
No synchronization for `IsBusy`/`IsDirty` access. Concurrent reads/writes may cause race conditions.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `IsBusy` and `IsDirty` Are Not Thread-Safe**:
|
||||
No synchronization for `IsBusy`/`IsDirty` access. Concurrent reads/writes may cause race conditions.
|
||||
|
||||
- **`ViewModelBase<T>`’s `IsBusy` and `IsDirty` Are Not Observed by `INotifyPropertyChanged`**:
|
||||
Setting `IsBusy` or `IsDirty` does not raise `PropertyChanged`. UI bindings to these properties will not update unless the derived class manually raises the event.
|
||||
|
||||
- **`BaseViewModel<TModel>`’s `IsBusy` and `IsDirty` Are Not Observed by `INotifyPropertyChanged`**:
|
||||
|
||||
Reference in New Issue
Block a user