File: Microsoft\Windows\Controls\Ribbon\RibbonSplitMenuItem.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\System.Windows.Controls.Ribbon\System.Windows.Controls.Ribbon_ztdoihgt_wpftmp.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.
// See the LICENSE file in the project root for more information.
 
#if RIBBON_IN_FRAMEWORK
namespace System.Windows.Controls.Ribbon
#else
namespace Microsoft.Windows.Controls.Ribbon
#endif
{
    #region Using declarations
 
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
 
    #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;
            if (splitMenuItem._partArrowButton != null)
            {
                splitMenuItem._partArrowButton.CoerceValue(FrameworkElement.ToolTipProperty);
            }
        }
 
        #endregion
 
        #region Protected Methods
 
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
 
            if (_headerButton != null)
            {
                _headerButton.Click -= new RoutedEventHandler(OnHeaderClicked);
            }
            _headerButton = GetTemplateChild(HeaderButtonTemplatePart) as ButtonBase;
 
            if (_headerButton != null)
            {
                _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;
            if (toggleButton != null)
            {
                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");
                binding.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()
        {
            if (_highlightLeftBorder != null)
            {
                // Right = 0.0
                _highlightLeftBorder.BorderThickness = new Thickness(BorderThickness.Left, BorderThickness.Top, 0.0, BorderThickness.Bottom);
            }
            if (_highlightRightBorder != null)
            {
                // 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";
 
        ButtonBase _headerButton;
        RibbonToggleButton _partArrowButton;
        ButtonBase _partHeaderButton;
        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
    }
}