Files

136 lines
7.8 KiB
Markdown
Raw Permalink Normal View History

2026-04-17 14:55:32 -04:00
---
source_files:
- DataPRO/Modules/Menu/HamburgerMenu/ViewModel/HamburgerMenuViewModel.cs
generated_at: "2026-04-16T04:48:30.206063+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "462d2b26bf58cd93"
---
# ViewModel
## Documentation: `HamburgerMenuViewModel`
---
### 1. **Purpose**
The `HamburgerMenuViewModel` class serves as the MVVM-compliant view model for the applications hamburger menu UI component. It manages the state and behavior of the menu—including item list, enabled/disabled status, busy state, and context menu construction—while acting as a bridge between the view (`IHamburgerMenuView`) and the broader system via Prisms event aggregation and Unity dependency injection. It subscribes to system-wide events (e.g., test lifecycle, busy indicators, notifications) to dynamically update its state and exposes interaction requests for modal UI (notifications, confirmations). It is a shared singleton (per container) responsible for rendering a context menu populated from a string array and raising a delegate when menu items are selected.
---
### 2. **Public Interface**
- **`IHamburgerMenuView View { get; set; }`**
Reference to the associated view; set during construction and used to bind `DataContext`.
- **`InteractionRequest<Notification> NotificationRequest { get; }`**
Prism interaction request used to trigger notification popups (e.g., informational messages).
- **`InteractionRequest<Confirmation> ConfirmationRequest { get; }`**
Prism interaction request used to trigger confirmation dialogs (e.g., yes/no prompts).
- **`event PropertyChangedEventHandler PropertyChanged;`**
Standard `INotifyPropertyChanged` implementation for data binding.
- **`void OnPropertyChanged(string propertyName);`**
Raises the `PropertyChanged` event for the specified property.
- **`ContextMenu GetContextMenu();`**
Returns the lazily-built `ContextMenu` instance. Builds it on first call if not already constructed. Thread-safe via `lock(MyLock)`.
- **`void SetMenuItems(string[] items);`**
Sets the list of menu item labels and immediately rebuilds the context menu.
- **`void ClearMenuItems();`**
Clears the internal `_menuItems` array and triggers a rebuild (resulting in an empty menu).
- **`void EnableMenu(bool enable);`**
Sets `IsEnabled` to `enable`, updating the UI state.
- **`void Unset();`**
Currently empty; no-op.
- **`void OnSetActive();`**
Currently empty; no-op.
- **`void Cleanup();`**
Currently empty; no-op.
- **`Task CleanupAsync();`**
Returns `Task.CompletedTask`; no-op.
- **`void Initialize();`**
Overload variants (`Initialize()`, `Initialize(object)`, `Initialize(object, object)`) are present but all currently no-op.
- **`Task InitializeAsync();`**
Overload variants (`InitializeAsync()`, `InitializeAsync(object)`) are present but all return `Task.CompletedTask`; no-op.
- **`void Activated();`**
Currently empty; no-op.
- **`bool IsEnabled { get; private set; }`**
Indicates whether the menu is enabled. Default `true`. Updated via `EnableMenu()`, `OnTestEvent()`, or internal logic.
- **`bool IsBusy { get; set; }`**
Indicates whether the menu is in a busy state (e.g., during test execution). Bound to `BusyIndicatorChangeNotification` event.
- **`bool IsMenuIncluded { get; set; }`**
Indicates whether the hamburger menu is included in the UI. Not used internally—likely for view-level visibility binding.
- **`bool IsNavigationIncluded { get; set; }`**
Indicates whether navigation controls are included in the UI. Not used internally—likely for view-level visibility binding.
- **`MenuItemPressedDelegate MenuItemPressed { get; set; }`**
Delegate invoked when a menu item is pressed. Signature: `void Delegate(string id)`. The `id` passed is the `Header` of the selected `MenuItem`.
---
### 3. **Invariants**
- `View.DataContext` is always set to `this` in the constructor.
- `_contextMenu` is lazily initialized on first call to `GetContextMenu()` and rebuilt only when `_menuItems` changes (via `SetMenuItems()` or `ClearMenuItems()`).
- `_menuItems` is never `null`; it is initialized to `new string[0]` and cleared to `new string[0]`.
- `IsEnabled` defaults to `true`.
- `IsBusy` is updated synchronously on the publisher thread (via `ThreadOption.PublisherThread`) in response to `BusyIndicatorChangeNotification`.
- Thread safety for context menu construction is ensured via `lock(MyLock)` in `GetContextMenu()` and `BuildContextMenu()`.
- Automation IDs are set on the `ContextMenu` (`"HamburgerMenu"`) and each `MenuItem` (`"MenuItem_{ItemName}"`, with spaces removed).
- `MenuItemPressed` is invoked with the `Header` string of the selected `MenuItem`.
---
### 4. **Dependencies**
**Imports/References (from source):**
- `System.ComponentModel`, `System.ComponentModel.Composition` (MEF)
- `Prism.Events`, `Prism.Regions` (Prism framework)
- `Unity` (Unity DI container)
- `DTS.Common.Events` (custom event types: `RaiseNotification`, `BusyIndicatorChangeNotification`, `TestEvent`)
- `DTS.Common.Interface.Menu.HamburgerMenu` (interface `IHamburgerMenuViewModel`)
- `DTS.Common.Interactivity` (interaction request types: `Notification`, `Confirmation`)
- `System.Windows.Controls`, `System.Windows.Automation`
**Depends on:**
- `IHamburgerMenuView` (view interface)
- `IRegionManager`, `IEventAggregator`, `IUnityContainer` (Prism/Unity infrastructure)
- `TestEvent`, `BusyIndicatorChangeNotification`, `RaiseNotification` (custom events via `IEventAggregator`)
**Used by:**
- Likely consumed by `IHamburgerMenuView` (WPF view) via data binding.
- Other modules may publish `TestEvent`, `BusyIndicatorChangeNotification`, or `RaiseNotification` to control its behavior.
---
### 5. **Gotchas**
- **Empty lifecycle methods**: `Initialize*`, `Cleanup*`, `Unset`, `OnSetActive`, and `Activated` are all no-ops. If lifecycle management is expected, this may be incomplete or deferred to the view.
- **`MenuItemPressed` is a delegate, not an event**: It is declared as `public MenuItemPressedDelegate MenuItemPressed { get; set; }`, meaning it can be overwritten and is not thread-safe for multicast subscriptions. Callers must ensure safe assignment.
- **`IsDirty` property exists but is never set**: Declared as `public bool IsDirty { get; private set; }`, but never assigned—likely unused or incomplete.
- **`IsMenuIncluded` and `IsNavigationIncluded` are never set internally**: Only exposed as properties; their values must be set externally (e.g., by view or another VM), but no logic uses them.
- **`AutomationProperties.AutomationIdProperty` is hardcoded**: Menu item IDs are derived by removing spaces from the header (`item.Replace(" ", "")`). This may cause collisions if headers differ only by whitespace (e.g., `"Run Test"` vs `"RunTest"` both become `"MenuItem_RunTest"`).
- **`GetContextMenu()` returns the same instance after first build**: Repeated calls return the cached `_contextMenu`. If `_menuItems` changes but `GetContextMenu()` is called before `SetMenuItems()`/`ClearMenuItems()` triggers `BuildContextMenu()`, stale items may be returned.
- **`OnTestEvent()` toggles `IsEnabled` only on `TestStarted`/`TestEnded`**: If `TestEventArg.Status` is anything else (e.g., `TestRunning`), `IsEnabled` remains unchanged—assumes only two statuses.
- **Thread safety**: Only `GetContextMenu()` and `BuildContextMenu()` are thread-safe. Other property setters (e.g., `IsBusy`) assume caller handles thread affinity (though `IsBusy` setter uses `OnPropertyChanged`, which may marshal to UI thread depending on binding context—*not guaranteed*).
- **No unsubscription from events**: The constructor subscribes to events but there is no `IDisposable` implementation or `Unsubscribe()` call—potential memory leak if the VM outlives its intended lifetime.
> *None of the above are necessarily bugs, but they are non-obvious and require awareness during maintenance or extension.*