| File: Microsoft\Windows\Controls\Ribbon\RibbonApplicationSplitMenuItem.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\System.Windows.Controls.Ribbon\System.Windows.Controls.Ribbon.csproj (System.Windows.Controls.Ribbon) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #region Using declarations using System.Windows.Input; #if RIBBON_IN_FRAMEWORK namespace System.Windows.Controls.Ribbon #else namespace Microsoft.Windows.Controls.Ribbon #endif { #if RIBBON_IN_FRAMEWORK #endif #endregion /// <summary> /// Implements a SplitMenuItem in the Ribbon's ApplicationMenu. /// </summary> [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonApplicationMenuItem))] public class RibbonApplicationSplitMenuItem : RibbonSplitMenuItem { #region Constructors /// <summary> /// Initializes static members of the RibbonApplicationSplitMenuItem class. /// </summary> static RibbonApplicationSplitMenuItem() { Type ownerType = typeof(RibbonApplicationSplitMenuItem); DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType)); IsSubmenuOpenProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(CoerceIsSubmenuOpen))); } #endregion #region ContainerGeneration private object _currentItem; protected override bool IsItemItsOwnContainerOverride(object item) { bool ret = (item is RibbonApplicationMenuItem) || (item is RibbonApplicationSplitMenuItem) || (item is RibbonSeparator) || (item is RibbonGallery); if (!ret) { _currentItem = item; } return ret; } protected override DependencyObject GetContainerForItemOverride() { object currentItem = _currentItem; _currentItem = null; if (UsesItemContainerTemplate) { DataTemplate itemContainerTemplate = ItemContainerTemplateSelector.SelectTemplate(currentItem, this); if (itemContainerTemplate != null) { object itemContainer = itemContainerTemplate.LoadContent(); if (itemContainer is RibbonApplicationMenuItem || itemContainer is RibbonApplicationSplitMenuItem || itemContainer is RibbonSeparator || itemContainer is RibbonGallery) { return itemContainer as DependencyObject; } else { throw new InvalidOperationException(Microsoft.Windows.Controls.SR.Format(Microsoft.Windows.Controls.SR.InvalidApplicationMenuOrItemContainer, this.GetType().Name, itemContainer)); } } } return new RibbonApplicationMenuItem(); } protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item) { if (container is RibbonApplicationSplitMenuItem || container is RibbonSeparator || container is RibbonGallery) { return false; } else { return base.ShouldApplyItemContainerStyle(container, item); } } /// <summary> /// Called when the container is being attached to the parent ItemsControl /// </summary> /// <param name="element"></param> /// <param name="item"></param> protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { base.PrepareContainerForItemOverride(element, item); RibbonHelper.SetApplicationMenuLevel(this.Level == RibbonApplicationMenuItemLevel.Top, element); } #endregion ContainerGeneration #region Popup Placement /// <summary> /// Gets the parent ItemsControl for this MenuItem. /// </summary> private ItemsControl ParentItemsControl { get { return ItemsControl.ItemsControlFromItemContainer(this); } } /// <summary> /// Invoked whenever the control's template is applied. /// </summary> public override void OnApplyTemplate() { if (Level == RibbonApplicationMenuItemLevel.Top) { RibbonHelper.UnhookPopupForTopLevelMenuItem(this); } base.OnApplyTemplate(); if (Level == RibbonApplicationMenuItemLevel.Top) { // Bind properties such as PlacementTarget, Height and // Width for the submenu Popup to the parent // RibbonApplicationMenu's SubmenuPlaceholder element. RibbonHelper.HookPopupForTopLevelMenuItem(this, ParentItemsControl); } } // This is a fix for Dev10 bug# 908460. The issue there is that auxiliary pane shows momentarily // when switching between two top level MenuItems within the RibbonApplicationMenu. This gives // the perception of a flicker. The solution to this is to delay the close of the old Popup until // after the new Popup has been shown. This property yeilds the buffer time component for the // CloseSubmenuTimer's interval. This component is a non-zero value only for a top level // RibbonApplicationMenuItem or RibbonApplicationSplitMenuItem. internal override int CloseSubmenuTimerDelayBuffer { get { if (Level == RibbonApplicationMenuItemLevel.Top && CanOpenSubMenu) { return RibbonApplicationMenuItem.CloseSubmenuTimerDelay; } return base.CloseSubmenuTimerDelayBuffer; } } // The above mentioned solution for Dev10 bug# 908460 needed another supporting change. // The base class for RibbonApplicationMenu viz. MenuBase woudn't wait for the // CloseSubmenuTimer to elapse but instead forcibly closed the first Popup as soon as // the second one was about to show. And this happened when the IsSubmenuOpen property // on the first Popup was being turned off. So in order to counter this behavior, we // now coerce the IsSubenuOpen property for top level RibbonApplicationMenuItems and // RibbonApplicationSplitMenuItems whenever the timer is running and the current // selection has moved to another MenuItem with a submenu. private static object CoerceIsSubmenuOpen(DependencyObject d, object baseValue) { RibbonApplicationSplitMenuItem menuItem = (RibbonApplicationSplitMenuItem)d; if (menuItem.Level == RibbonApplicationMenuItemLevel.Top) { return RibbonHelper.CoerceIsSubmenuOpenForTopLevelItem(menuItem, menuItem.ParentItemsControl, (bool)baseValue); } return baseValue; } /// <summary> /// Gets/Sets RibbonApplicationMenuItemLevel property which indicates on which level this item is displayed. /// This property will define visual appearance of the menu item. /// </summary> public RibbonApplicationMenuItemLevel Level { get { return (RibbonApplicationMenuItemLevel)GetValue(LevelProperty); } internal set { SetValue(LevelPropertyKey, value); } } /// <summary> /// DependencyPropertyKey for read only DependencyProperty Level. /// </summary> private static readonly DependencyPropertyKey LevelPropertyKey = DependencyProperty.RegisterReadOnly("Level", typeof(RibbonApplicationMenuItemLevel), typeof(RibbonApplicationSplitMenuItem), new FrameworkPropertyMetadata(RibbonApplicationMenuItemLevel.Top)); /// <summary> /// Using a DependencyProperty as the backing store for Level to enable binding. /// </summary> public static readonly DependencyProperty LevelProperty = LevelPropertyKey.DependencyProperty; #endregion #region KeyTips protected override void OnActivatingKeyTip(ActivatingKeyTipEventArgs e) { if (e.OriginalSource == this) { if (!CanOpenSubMenu) { e.KeyTipVisibility = Visibility.Collapsed; } else { e.KeyTipHorizontalPlacement = KeyTipHorizontalPlacement.KeyTipCenterAtTargetCenter; e.KeyTipVerticalPlacement = KeyTipVerticalPlacement.KeyTipTopAtTargetCenter; e.KeyTipHorizontalOffset = e.KeyTipVerticalOffset = 0; e.PlacementTarget = ArrowToggleButton; } } else if (e.OriginalSource == HeaderButton) { e.KeyTipHorizontalPlacement = KeyTipHorizontalPlacement.KeyTipLeftAtTargetLeft; e.KeyTipVerticalPlacement = KeyTipVerticalPlacement.KeyTipTopAtTargetCenter; e.KeyTipHorizontalOffset = RibbonApplicationMenuItem.KeyTipHorizontalOffet; e.KeyTipVerticalOffset = 0; e.PlacementTarget = this; } } #endregion #region Input protected override void OnKeyDown(KeyEventArgs e) { RibbonHelper.OnApplicationMenuItemUpDownKeyDown(e, this); base.OnKeyDown(e); } #endregion } }