| File: Microsoft\Windows\Controls\Ribbon\RibbonSplitMenuItem.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.Controls.Primitives; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; #if RIBBON_IN_FRAMEWORK namespace System.Windows.Controls.Ribbon #else namespace Microsoft.Windows.Controls.Ribbon #endif { #endregion /// <summary> /// A variation of RibbonMenuItem which shows Checked state differently. /// Its Submenu can be opened or closed independent of IsCheckable. /// </summary> [TemplatePart(Name = RibbonSplitMenuItem.ArrowButtonTemplatePart, Type = typeof(RibbonToggleButton))] [TemplatePart(Name = RibbonSplitMenuItem.HeaderButtonTemplatePart, Type = typeof(RibbonButton))] [TemplatePart(Name = RibbonMenuItem.SideBarBorderTemplatePartName, Type = typeof(Border))] public class RibbonSplitMenuItem : RibbonMenuItem { #region Constructor static RibbonSplitMenuItem() { Type ownerType = typeof(RibbonSplitMenuItem); DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType)); BorderThicknessProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new Thickness(), new PropertyChangedCallback(OnBorderThicknessChanged))); IsCheckedProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsCheckedChanged))); } #endregion #region ToolTip Properties /// <summary> /// DependencyProperty for DropDownToolTipTitle property. /// </summary> public static readonly DependencyProperty DropDownToolTipTitleProperty = RibbonSplitButton.DropDownToolTipTitleProperty.AddOwner( typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropDownToolTipPropertyChanged))); /// <summary> /// Title text for the tooltip on the DropDown portion of the RibbonSplitMenuItem /// </summary> public string DropDownToolTipTitle { get { return (string)GetValue(DropDownToolTipTitleProperty); } set { SetValue(DropDownToolTipTitleProperty, value); } } /// <summary> /// DependencyProperty for DropDownToolTipDescription property. /// </summary> public static readonly DependencyProperty DropDownToolTipDescriptionProperty = RibbonSplitButton.DropDownToolTipDescriptionProperty.AddOwner( typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropDownToolTipPropertyChanged))); /// <summary> /// Description text for the tooltip on the DropDown portion of the RibbonSplitMenuItem /// </summary> public string DropDownToolTipDescription { get { return (string)GetValue(DropDownToolTipDescriptionProperty); } set { SetValue(DropDownToolTipDescriptionProperty, value); } } /// <summary> /// DependencyProperty for DropDownToolTipImageSource property. /// </summary> public static readonly DependencyProperty DropDownToolTipImageSourceProperty = RibbonSplitButton.DropDownToolTipImageSourceProperty.AddOwner( typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropDownToolTipPropertyChanged))); /// <summary> /// Image source for the tooltip on the DropDown portion of the RibbonSplitMenuItem /// </summary> public ImageSource DropDownToolTipImageSource { get { return (ImageSource)GetValue(DropDownToolTipImageSourceProperty); } set { SetValue(DropDownToolTipImageSourceProperty, value); } } /// <summary> /// DependencyProperty for DropDownToolTipFooterTitle property. /// </summary> public static readonly DependencyProperty DropDownToolTipFooterTitleProperty = RibbonSplitButton.DropDownToolTipFooterTitleProperty.AddOwner( typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropDownToolTipPropertyChanged))); /// <summary> /// Title text for the footer of tooltip on the DropDown portion of the RibbonSplitMenuItem /// </summary> public string DropDownToolTipFooterTitle { get { return (string)GetValue(DropDownToolTipFooterTitleProperty); } set { SetValue(DropDownToolTipFooterTitleProperty, value); } } /// <summary> /// DependencyProperty for DropDownToolTipFooterDescription property. /// </summary> public static readonly DependencyProperty DropDownToolTipFooterDescriptionProperty = RibbonSplitButton.DropDownToolTipFooterDescriptionProperty.AddOwner( typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropDownToolTipPropertyChanged))); /// <summary> /// Description text for the footer of the tooltip on the DropDown portion of the RibbonSplitMenuItem /// </summary> public string DropDownToolTipFooterDescription { get { return (string)GetValue(DropDownToolTipFooterDescriptionProperty); } set { SetValue(DropDownToolTipFooterDescriptionProperty, value); } } /// <summary> /// DependencyProperty for DropDownToolTipFooterImageSource property. /// </summary> public static readonly DependencyProperty DropDownToolTipFooterImageSourceProperty = RibbonSplitButton.DropDownToolTipFooterImageSourceProperty.AddOwner( typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnDropDownToolTipPropertyChanged))); /// <summary> /// Image source for the footer of the tooltip on the DropDown portion of the RibbonSplitMenuItem /// </summary> public ImageSource DropDownToolTipFooterImageSource { get { return (ImageSource)GetValue(DropDownToolTipFooterImageSourceProperty); } set { SetValue(DropDownToolTipFooterImageSourceProperty, value); } } private static void OnDropDownToolTipPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { RibbonSplitMenuItem splitMenuItem = (RibbonSplitMenuItem)d; splitMenuItem._partArrowButton?.CoerceValue(FrameworkElement.ToolTipProperty); } #endregion #region Protected Methods public override void OnApplyTemplate() { base.OnApplyTemplate(); _headerButton?.Click -= new RoutedEventHandler(OnHeaderClicked); _headerButton = GetTemplateChild(HeaderButtonTemplatePart) as ButtonBase; _headerButton?.Click += new RoutedEventHandler(OnHeaderClicked); _partArrowButton = GetTemplateChild(ArrowButtonTemplatePart) as RibbonToggleButton; _highlightLeftBorder = GetTemplateChild("HighlightLeftBorder") as Border; _highlightRightBorder = GetTemplateChild("HighlightRightBorder") as Border; SetIsPressedBinding(); SetBorderThickness(); } protected override void OnKeyDown(KeyEventArgs e) { if (HasItems && e.Key == Key.Enter) { // Fire Command on Enter, not open Submenu OnClick(); e.Handled = true; return; } base.OnKeyDown(e); } private void OnHeaderClicked(object sender, RoutedEventArgs e) { OnClick(); } private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { RibbonSplitMenuItem splitMenuItem = (RibbonSplitMenuItem)d; RibbonToggleButton toggleButton = splitMenuItem._headerButton as RibbonToggleButton; toggleButton?.IsChecked = splitMenuItem.IsChecked; } // UIElement.IsEnabledCore's getter simply returns true (e.g. RibbonSplitButton follows this path), but MenuItem // overrides that and returns the value of the Command's CanExecute. For RibbonSplitMenuItem, however, we don't // want the Command's CanExecute state to affect the IsEnabled state of the entire control. PART_HeaderButton // handles the Command and reflects its own enabled/disabled state accordingly. protected override bool IsEnabledCore { get { return true; } } #endregion #region QAT /// <summary> /// The DependencyProperty for the HeaderQuickAccessToolBarId property. /// Flags: None /// Default Value: null /// </summary> public static readonly DependencyProperty HeaderQuickAccessToolBarIdProperty = RibbonSplitButton.HeaderQuickAccessToolBarIdProperty.AddOwner(typeof(RibbonSplitMenuItem)); /// <summary> /// Identifier for the Header part of the RibbonSplitButton when in QuickAccessToolBar. /// Set this property to allow Header to be added to QuickAccessToolBar by itself. /// </summary> public object HeaderQuickAccessToolBarId { get { return GetValue(HeaderQuickAccessToolBarIdProperty); } set { SetValue(HeaderQuickAccessToolBarIdProperty, value); } } #endregion QAT #region Private Methods internal override void OnDismissPopup(RibbonDismissPopupEventArgs e) { if (e.OriginalSource == _partArrowButton) { // Clicking on Arrow should not dismiss the parent popup e.Handled = true; return; } base.OnDismissPopup(e); } private void SetIsPressedBinding() { if (_partHeaderButton != null) { // Clear any existing Binding BindingOperations.ClearBinding(this, IsPressedInternalProperty); } _partHeaderButton = GetTemplateChild(HeaderButtonTemplatePart) as ButtonBase; // Clicking on HeaderToggleButton eats up MouseDown input, hence MenuItem.IsPressed doesnt get updated. // Bind to Button.IsPressed and set MenuItem.IsPressed manually. if (_partHeaderButton != null) { Binding binding = new Binding("IsPressed") { Source = _partHeaderButton }; this.SetBinding(IsPressedInternalProperty, binding); } } private static void OnIsPressedInternalChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { RibbonSplitMenuItem splitMenuItem = (RibbonSplitMenuItem)sender; splitMenuItem.IsPressed = splitMenuItem.IsPressedInternal; } private static void OnBorderThicknessChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { RibbonSplitMenuItem splitMenuItem = (RibbonSplitMenuItem)sender; splitMenuItem.SetBorderThickness(); } private void SetBorderThickness() { // Right = 0.0 _highlightLeftBorder?.BorderThickness = new Thickness(BorderThickness.Left, BorderThickness.Top, 0.0, BorderThickness.Bottom); // Left = 0.0 _highlightRightBorder?.BorderThickness = new Thickness(0.0, BorderThickness.Top, BorderThickness.Right, BorderThickness.Bottom); } #endregion #region Internal Properties internal override bool CanOpenSubMenu { get { return HasItems; } } /// <summary> /// A private read/write property which can bind to ToggleButton's IsPressedProperty. /// </summary> private static readonly DependencyProperty IsPressedInternalProperty = DependencyProperty.Register("IsPressedInternal", typeof(bool), typeof(RibbonSplitMenuItem), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsPressedInternalChanged))); private bool IsPressedInternal { get { return (bool)GetValue(IsPressedInternalProperty); } set { SetValue(IsPressedInternalProperty, value); } } internal RibbonToggleButton ArrowToggleButton { get { return _partArrowButton; } } internal ButtonBase HeaderButton { get { return _partHeaderButton; } } #endregion #region Private Data private const string HeaderButtonTemplatePart = "PART_HeaderButton"; private const string ArrowButtonTemplatePart = "PART_ArrowToggleButton"; private ButtonBase _headerButton; private RibbonToggleButton _partArrowButton; private ButtonBase _partHeaderButton; private Border _highlightLeftBorder, _highlightRightBorder; #endregion #region KeyTips public string HeaderKeyTip { get { return (string)GetValue(HeaderKeyTipProperty); } set { SetValue(HeaderKeyTipProperty, value); } } // Using a DependencyProperty as the backing store for HeaderKeyTip. This enables animation, styling, binding, etc... public static readonly DependencyProperty HeaderKeyTipProperty = RibbonSplitButton.HeaderKeyTipProperty.AddOwner(typeof(RibbonSplitMenuItem)); 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.KeyTipLeftAtTargetCenter; e.KeyTipVerticalPlacement = KeyTipVerticalPlacement.KeyTipTopAtTargetCenter; e.KeyTipHorizontalOffset = e.KeyTipVerticalOffset = 0; e.PlacementTarget = SideBarBorder; } } protected override void OnKeyTipAccessed(KeyTipAccessedEventArgs e) { if (e.OriginalSource == this) { if (CanOpenSubMenu) { FocusOrSelect(); IsSubmenuOpen = true; RibbonHelper.NavigateToNextMenuItemOrGallery(this, -1, BringIndexIntoView); UIElement popupChild = Popup.TryGetChild(); if (popupChild != null) { KeyTipService.SetIsKeyTipScope(popupChild, true); e.TargetKeyTipScope = popupChild; } } e.Handled = true; } } #endregion } }