--- 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 application’s 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 Prism’s 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 NotificationRequest { get; }`** Prism interaction request used to trigger notification popups (e.g., informational messages). - **`InteractionRequest 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.*