--- source_files: - Common/DTS.CommonCore/RibbonControl/RibbonControlSelectionChanged.cs - Common/DTS.CommonCore/RibbonControl/RibbonControlOperation.cs - Common/DTS.CommonCore/RibbonControl/RibbonControlSelectionEventArgs.cs - Common/DTS.CommonCore/RibbonControl/RibbonControlSelectionChangeBehavior.cs - Common/DTS.CommonCore/RibbonControl/RibbonRegionAdapter.cs generated_at: "2026-04-16T02:16:32.989533+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "c0e1c8bd7f1a18f4" --- # RibbonControl ## Documentation: `DTS.Common.RibbonControl` Module --- ### 1. Purpose This module provides infrastructure for integrating the Microsoft Ribbon control (from the *RibbonControlsLibrary*) into a Prism-based WPF application, specifically enabling Prism region management and event-driven tab selection coordination for `Ribbon` and `RibbonTab` elements. It defines event types for tab selection changes, a behavior to bridge `Ribbon.SelectionChanged` to Prism events, and a region adapter to manage `RibbonTab` and `RibbonApplicationMenu` views within the `RibbonRegion`. Its role is to decouple view navigation logic from UI controls while preserving Prism’s region-based architecture and enabling reactive tab selection behavior based on view model metadata. --- ### 2. Public Interface #### `RibbonControlSelectionChanged` - **Type**: `class` (inherits `CompositePresentationEvent`) - **Purpose**: Prism event used to publish tab selection changes (add/remove operations) on the `Ribbon`. - **Usage**: Subscribers listen for tab operations via `IEventAggregator.GetEvent().Subscribe(...)`. - **Payload**: `RibbonControlSelectionEventArgs` #### `RibbonControlOperation` - **Type**: `enum` - **Values**: - `AddedItem`: Indicates a tab was added to the `Ribbon`. - `RemovedItem`: Indicates a tab was removed from the `Ribbon`. #### `RibbonControlSelectionEventArgs` - **Type**: `class` - **Properties**: - `Operation`: `RibbonControlOperation` — the type of operation (`AddedItem` or `RemovedItem`). - `Item`: `object` — the `RibbonTab` (or other item) involved in the operation. - **Constructor**: `RibbonControlSelectionEventArgs(RibbonControlOperation operation, object item)` Initializes the event args with the operation and item. #### `RibbonControlSelectionChangeBehavior` - **Type**: `class` (inherits `Behavior`) - **Properties**: - `TargetRibbonControl`: `Ribbon` (dependency property) — *Note: Property name mismatch in XAML usage; registered as `"TargetRibbonControl"` but exposed as `TargetRibbonControl`.* - **Behavior**: - Attaches to `Ribbon.SelectionChanged` event. - On selection change, publishes **two** events (one for `AddedItem`, one for `RemovedItem`) via `RibbonControlSelectionChanged`, using the first item in `e.AddedItems` and `e.RemovedItems` respectively. - Uses `ServiceLocator.Current.GetInstance()` to publish events. #### `RibbonRegionAdapter` - **Type**: `class` (inherits `RegionAdapterBase`, implements `IDisposable`) - **Constructor**: ```csharp RibbonRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory, IRegionManager regionManager, IEventAggregator eventAggregator) ``` - Registers for `RibbonControlSelectionChanged` events via `_eventAggregator.GetEvent().Subscribe(OnTabControlSelectionChanged)`. ⚠️ **Note**: Event name mismatch — uses `TabControlSelectionChanged` (see *Gotchas*). - **Methods**: - `Adapt(IRegion region, Ribbon regionTarget)`: Subscribes to `region.ActiveViews.CollectionChanged`, handling `RibbonTab` and `RibbonApplicationMenu` additions/removals: - Adds `RibbonTab` to `regionTarget.Items`, assigns a `Uid` if missing, sorts by `TabIndex`. - Adds `RibbonApplicationMenu` to `regionTarget.ApplicationMenu`. - Sets `IsSelected = true` on the first added tab if `App.config` contains ``. - `AddRibbonTabToRegion(RibbonTab, Ribbon)`: Internal helper. - `AddApplicationMenuToRegion(RibbonApplicationMenu, Ribbon)`: Internal helper. - `RemoveRibbonTabFromRibbonRegion(RibbonTab, Ribbon)`: Removes tab from `Ribbon.Items`. - `OnTabControlSelectionChanged(TabControlSelectionEventArgs)`: Reacts to tab selection changes: - Ignores `RemovedItem` operations. - Extracts `IBaseView` → `IRibbonTabInfoProvider` from view’s `DataContext`. - Uses `RibbonTabUid` to programmatically select the corresponding `RibbonTab` in the region. - `CreateRegion()`: Returns `new AllActiveRegion()` (all views remain active). - **IDisposable**: - Unsubscribes from `RibbonControlSelectionChanged` in `Dispose(bool)`. --- ### 3. Invariants - **Event naming consistency**: `RibbonControlSelectionChanged` (defined in `RibbonControlSelectionChanged.cs`) is *not* the same as `TabControlSelectionChanged` (used in `RibbonRegionAdapter.cs`). This is a critical mismatch (see *Gotchas*). - **Item identity**: `RibbonControlSelectionEventArgs.Item` is always the *first* item in `AddedItems` or `RemovedItems` — only single-item operations are handled. - **Tab selection logic**: `RibbonRegionAdapter.OnTabControlSelectionChanged` only acts on `AddedItem` operations and only if: - `e.Item` is an `IBaseView`, - its `DataContext` implements `IRibbonTabInfoProvider`, - `IRibbonTabInfoProvider.RibbonTabUid` is non-null/non-empty, - and the `RibbonTab` with matching `Uid` exists in the region. - **UID assignment**: `RibbonTab.Uid` and `RibbonApplicationMenu.Uid` are auto-generated (via `Guid`) if missing during `Adapt()`. --- ### 4. Dependencies #### Dependencies *of* this module: - **Prism libraries**: `Microsoft.Practices.Prism.Events`, `Microsoft.Practices.Prism.Regions`, `Microsoft.Practices.ServiceLocation`. - **WPF & Ribbon**: `System.Windows`, `System.Windows.Controls`, `Microsoft.Windows.Controls.Ribbon` (from *RibbonControlsLibrary*). - **Custom types**: - `DTS.Common.Classes.IBaseView` - `DTS.Common.Enums.IRibbonTabInfoProvider` - `DTS.Common.Events.TabControlSelectionChanged` *(note: event name mismatch)* - `DTS.Common.Base.RegionNames.RibbonRegion` #### Dependencies *on* this module: - Application code that uses Prism regions (`RegionNames.RibbonRegion`) to host `Ribbon` controls. - View models implementing `IRibbonTabInfoProvider` to enable programmatic tab selection. - Behaviors or services that subscribe to `RibbonControlSelectionChanged` for tab lifecycle monitoring. --- ### 5. Gotchas - **Event name mismatch**: `RibbonRegionAdapter` subscribes to `TabControlSelectionChanged`, but the event defined in this module is `RibbonControlSelectionChanged`. This will cause `OnTabControlSelectionChanged` to *never fire*, breaking tab selection coordination. → **Fix required**: Change `TabControlSelectionChanged` to `RibbonControlSelectionChanged` in `RibbonRegionAdapter` constructor and `Dispose`. - **Behavior uses `ServiceLocator`**: `RibbonControlSelectionChangeBehavior` uses `ServiceLocator.Current.GetInstance()` instead of constructor injection. This violates DI best practices and makes testing harder. - **Single-item assumption**: Only the *first* added/removed item is used (`e.AddedItems[0]`, `e.RemovedItems[0]`). Multi-select scenarios (if supported by `Ribbon`) will be silently ignored. - **Property name mismatch**: The dependency property is registered as `"TargetRibbonControl"` but exposed as `TargetRibbonControl`. While syntactically valid, this may cause confusion in XAML binding (e.g., `TargetRibbonControl="{Binding ...}"` is required — not `TargetRibbon`). - **Hardcoded config key**: `DefaultRibbonTab` is read from `App.config` without validation or fallback. If the header string doesn’t match exactly (case-insensitive), selection won’t occur. - **No null safety for `Item`**: `RibbonControlSelectionEventArgs.Item` is `object`, but downstream logic (e.g., `OnTabControlSelectionChanged`) assumes it is an `IBaseView`. Casting failures will be silent (via `as` operator). - **Thread-safety via `lock`**: `AddRibbonTabToRegion` uses a `static readonly lock`, but `RibbonRegionAdapter` is instantiated per region (via DI), so the lock is shared across *all* ribbon regions — potentially causing contention or deadlocks if multiple regions are initialized concurrently. - **Missing `RibbonControlOperation` usage**: `RibbonControlOperation` is defined but only used in `RibbonControlSelectionEventArgs`. No other code references it directly. --- *Documentation generated from provided source files. No external behavior or APIs inferred.*