init
This commit is contained in:
152
enriched-qwen3-coder-next/Common/DTS.CommonCore/RibbonControl.md
Normal file
152
enriched-qwen3-coder-next/Common/DTS.CommonCore/RibbonControl.md
Normal file
@@ -0,0 +1,152 @@
|
||||
---
|
||||
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<RibbonControlSelectionEventArgs>`)
|
||||
- **Purpose**: Prism event used to publish tab selection changes (add/remove operations) on the `Ribbon`.
|
||||
- **Usage**: Subscribers listen for tab operations via `IEventAggregator.GetEvent<RibbonControlSelectionChanged>().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<Ribbon>`)
|
||||
- **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<IEventAggregator>()` to publish events.
|
||||
|
||||
#### `RibbonRegionAdapter`
|
||||
- **Type**: `class` (inherits `RegionAdapterBase<Ribbon>`, implements `IDisposable`)
|
||||
- **Constructor**:
|
||||
```csharp
|
||||
RibbonRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory, IRegionManager regionManager, IEventAggregator eventAggregator)
|
||||
```
|
||||
- Registers for `RibbonControlSelectionChanged` events via `_eventAggregator.GetEvent<TabControlSelectionChanged>().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 `<add key="DefaultRibbonTab" value="TabHeaderName"/>`.
|
||||
- `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<IEventAggregator>()` 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.*
|
||||
Reference in New Issue
Block a user