10 KiB
source_files, generated_at, model, schema_version, sha256
| source_files | generated_at | model | schema_version | sha256 | |||||
|---|---|---|---|---|---|---|---|---|---|
|
2026-04-16T02:56:16.038197+00:00 | Qwen/Qwen3-Coder-Next-FP8 | 1 | bf8430cdc3eeb064 |
RibbonControl
Documentation: Ribbon Control Selection Module
1. Purpose
This module provides infrastructure for integrating Prism-based region management with the Microsoft Ribbon control (Microsoft.Windows.Controls.Ribbon.Ribbon) and for publishing selection-change events when ribbon tabs are added, removed, or selected. It enables decoupled communication between ribbon UI components and view models via Prism’s event aggregation system. Specifically, it adapts the Ribbon control to Prism regions, manages the addition/removal of RibbonTab and RibbonApplicationMenu items, and publishes RibbonControlSelectionChanged events whenever tab selection changes (e.g., due to user interaction or programmatic activation). This supports view synchronization and state management in a modular WPF application.
2. Public Interface
RibbonControlSelectionChanged
- Type:
classinheriting fromPubSubEvent<RibbonControlSelectionEventArgs> - Behavior: A Prism
PubSubEventused to broadcast tab selection changes. Subscribers receiveRibbonControlSelectionEventArgsinstances indicating the operation type (AddedItemorRemovedItem) and the affected item.
RibbonControlOperation
- Type:
enum - Values:
AddedItem: Indicates an item was added to the ribbon (e.g., a tab).RemovedItem: Indicates an item was removed from the ribbon.
RibbonControlSelectionEventArgs
- Constructor:
RibbonControlSelectionEventArgs(RibbonControlOperation operation, object item)- Parameters:
operation: The operation type (AddedItemorRemovedItem).item: The ribbon item (typically aRibbonTab) involved in the operation.
- Parameters:
- Properties:
Operation: Gets the operation type.Item: Gets the added/removed item (strongly typed asobject; callers must cast appropriately).
RibbonControlSelectionChangeBehavior
- Type:
classinheriting fromBehavior<Ribbon> - Properties:
TargetRibbonControl:Ribbondependency property (note: backing field name isTargetRibbonProperty, but property name isTargetRibbonControl).
- Methods:
OnAttached(): Subscribes toRibbon.SelectionChanged; initializes_eventAggregatorviaContainerLocator.Container.OnDetaching(): Unsubscribes fromRibbon.SelectionChanged.Ribbon_SelectionChanged(object sender, SelectionChangedEventArgs e):- Publishes two events per
SelectionChangedEventArgsif bothAddedItemsandRemovedItemsare non-empty:- One
RibbonControlSelectionChangedevent forAddedItemwithe.AddedItems[0]. - One
RibbonControlSelectionChangedevent forRemovedItemwithe.RemovedItems[0].
- One
- Only the first added/removed item is used (index
0), ignoring additional items.
- Publishes two events per
RibbonRegionAdapter
- Type:
classinheriting fromRegionAdapterBase<Ribbon>, implementsIDisposable - Constructor:
RibbonRegionAdapter(IRegionBehaviorFactory, IRegionManager, IEventAggregator)- Subscribes to
RibbonControlSelectionChangedevent (note: usesTabControlSelectionChanged, which is a typo—see Gotchas).
- Subscribes to
- Methods:
Adapt(IRegion region, Ribbon regionTarget):- Hooks
region.ActiveViews.CollectionChangedto add/removeRibbonTab/RibbonApplicationMenuitems to/fromregionTarget.ItemsorregionTarget.ApplicationMenu. - Assigns a
Uid(if missing) to new tabs usingGuid.NewGuid().GetHashCode().ToString(...). - Applies
SortDescription("TabIndex", Ascending)toregionTarget.Items.SortDescriptions. - Sets
IsSelectedon a newly added tab if its header matchesAppSettings["DefaultRibbonTab"](case-insensitive).
- Hooks
AddRibbonTabToRegion(RibbonTab, Ribbon): Adds tab toItems, setsUid, sorts, and optionally selects.AddApplicationMenuToRegion(RibbonApplicationMenu, Ribbon): Assigns toregionTarget.ApplicationMenu.RemoveRibbonTabFromRibbonRegion(RibbonTab, Ribbon): Removes tab fromItems.OnTabControlSelectionChanged(TabControlSelectionEventArgs):- Only processes
AddedItemoperations (ignoresRemovedItem). - Attempts to synchronize tab selection based on
IRibbonTabInfoProvider.RibbonTabUidfrom the view’sDataContext. - If the selected tab’s UID does not match the view’s expected tab UID, it programmatically selects the matching tab.
- Only processes
CreateRegion(): Returnsnew AllActiveRegion()(all views remain active).
- IDisposable:
Dispose(bool): Unsubscribes fromRibbonControlSelectionChanged.- Finalizer (
~RibbonRegionAdapter) callsDispose(false).
3. Invariants
- Event publishing:
RibbonControlSelectionChangedis published only for the first item inAddedItemsandRemovedItems(index0), even if multiple items change simultaneously.
- Operation semantics:
RibbonControlOperation.AddedItemcorresponds to items inSelectionChangedEventArgs.AddedItems.RibbonControlOperation.RemovedItemcorresponds to items inSelectionChangedEventArgs.RemovedItems.
- UID requirement:
RibbonTab.Uidmust be set (either manually or auto-generated) forRibbonRegionAdapter.OnTabControlSelectionChangedto function correctly.
- View contract:
- For
OnTabControlSelectionChangedto synchronize selection, the view’sDataContextmust implementIRibbonTabInfoProviderand return a non-emptyRibbonTabUid.
- For
- Thread safety:
AddRibbonTabToRegionuses alock (Lock)aroundUidassignment andItems.Add, butRemoveRibbonTabFromRibbonRegiondoes not. This may lead to race conditions during concurrent add/remove operations.
4. Dependencies
Internal Dependencies (from source):
- Prism libraries:
Prism.Events(PubSubEvent,IEventAggregator)Prism.Regions(RegionAdapterBase,IRegion,IRegionManager)Prism.Ioc(ContainerLocator)
- WPF & Ribbon:
System.Windows(DependencyProperty,SelectionChangedEventArgs)System.Windows.Controls(Ribbon,RibbonTab,RibbonApplicationMenu)Microsoft.Windows.Controls.Ribbon( RibbonControlsLibrary)Microsoft.Xaml.Behaviors(Behavior<T>)
- Common project types:
DTS.Common.Classes.IBaseViewDTS.Common.Enums.IRibbonTabInfoProviderDTS.Common.Events.TabControlSelectionChanged(note: typo in usage—see Gotchas)
External Dependencies:
RibbonControlsLibraryNuGet package (required at runtime).App.configwith optional"DefaultRibbonTab"key.
Dependencies on this module:
RibbonRegionAdapteris used to adaptRibboncontrols in Prism regions (e.g.,RegionNames.RibbonRegion).RibbonControlSelectionChangedevent is consumed byRibbonRegionAdapterand likely by other modules/view models to react to tab changes.
5. Gotchas
-
Typo in event name:
RibbonRegionAdaptersubscribes toTabControlSelectionChanged(line:_eventAggregator.GetEvent<TabControlSelectionChanged>()), but the defined event is namedRibbonControlSelectionChanged. This will cause a runtimeEventNotFoundExceptionunlessTabControlSelectionChangedis defined elsewhere (not present in source).- Likely bug: Should be
RibbonControlSelectionChanged.
-
Event semantics mismatch:
RibbonControlSelectionChangedEventArgs.Operationis namedRibbonControlOperation, butRibbonRegionAdapter.OnTabControlSelectionChangedchecks forTabControlOperation.RemovedItem(again, typo—should beRibbonControlOperation).- The
Operationproperty inRibbonControlSelectionEventArgsis of typeRibbonControlOperation, but the handler inRibbonRegionAdapterreferencesTabControlOperation(undefined in source). This will not compile unlessTabControlOperationexists elsewhere.
-
Only first item processed:
RibbonControlSelectionChangeBehavior.Ribbon_SelectionChangedpublishes events only fore.AddedItems[0]ande.RemovedItems[0]. If multiple tabs are selected/removed in one operation (e.g., viaSelectedItemsmanipulation), only the first is handled.
-
UID auto-generation side effect:
AddRibbonTabToRegionassigns a newUidevery time a tab is added ifUidis null/empty. This may cause issues ifUidis used for persistence or tracking across sessions.
-
Race condition in
RemoveRibbonTabFromRibbonRegion:- Removal is not synchronized (unlike addition), risking
InvalidOperationExceptionif concurrent modifications occur.
- Removal is not synchronized (unlike addition), risking
-
Selection logic assumes single active tab:
OnTabControlSelectionChangedselects a tab only ifcurrentTab == nullorribbonTabInfo.RibbonTabUid != currentTab.Uid, but does not handle cases where multiple tabs might be active (thoughAllActiveRegionis used, selection is still single-tab inRibboncontrol).
-
No validation of
Itemtype:RibbonControlSelectionEventArgs.Itemisobject. Consumers must cast toRibbonTaborRibbonApplicationMenusafely.
-
TargetRibbonControlproperty name mismatch:- The
DependencyPropertyis registered as"TargetRibbonControl", but the backing field isTargetRibbonProperty. This is valid, but the naming is inconsistent (TargetRibbonControlvsTargetRibbonProperty).
- The
-
RibbonRegionAdaptersubscribes to event in constructor:- If the adapter is created before
IEventAggregatoris fully initialized, subscription may fail. Not an issue if DI container ensures ordering, but a risk in complex setups.
- If the adapter is created before
-
RibbonControlSelectionChangeBehaviordoes not validateAssociatedObject:- Assumes
AssociatedObjectis non-null and implementsRibbon(enforced byBehavior<Ribbon>), butSelectionChangedhandler does not checksendertype.
- Assumes
None identified beyond the above.