|
// 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.Globalization;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
#if RIBBON_IN_FRAMEWORK
using System.Windows.Controls.Ribbon.Primitives;
using Microsoft.Windows.Controls;
#else
using Microsoft.Windows.Automation.Peers;
using Microsoft.Windows.Controls.Ribbon.Primitives;
#endif
#endregion
/// <summary>
/// ContextMenu for Ribbon controls.
/// </summary>
[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonMenuItem))]
public class RibbonContextMenu : ContextMenu
{
#region Constructors
/// <summary>
/// Initializes static members of the RibbonContextMenu class.
/// </summary>
static RibbonContextMenu()
{
Type ownerType = typeof(RibbonContextMenu);
DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType));
IsOpenProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsOpenChanged)));
EventManager.RegisterClassHandler(ownerType, Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(OnClickThroughThunk));
ItemsPanelTemplate template = new ItemsPanelTemplate(new FrameworkElementFactory(typeof(RibbonMenuItemsPanel)));
template.Seal();
ItemsPanelProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(template));
}
public RibbonContextMenu()
{
Loaded += new RoutedEventHandler(OnLoaded);
}
#endregion
#region UI Automation
protected override AutomationPeer OnCreateAutomationPeer()
{
return new RibbonContextMenuAutomationPeer(this);
}
#endregion UI Automation
#region Dismiss popup
private static bool CanRaiseDismissPopups(UIElement dismissPopupSource)
{
// Contextmenu raises DismissPopup event on the source only
// if it is in a popup and is in a Ribbon.
if (dismissPopupSource == null ||
RibbonControlService.GetRibbon(dismissPopupSource) == null)
{
return false;
}
Popup ancestorPopup = TreeHelper.FindAncestor(dismissPopupSource, delegate(DependencyObject element) { return (element is Popup); }) as Popup;
if (ancestorPopup == null ||
!ancestorPopup.IsOpen)
{
return false;
}
return true;
}
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RibbonContextMenu contextMenu = (RibbonContextMenu)d;
if (!(bool)(e.NewValue))
{
if (!contextMenu._ignoreDismissPopupsOnNextClose)
{
UIElement dismissPopupSource = contextMenu.GetDismissPopupSource();
if (CanRaiseDismissPopups(dismissPopupSource))
{
// Raise DismissPopup on owner if can raise and if
// was not asked to ignore.
dismissPopupSource.RaiseEvent(new RibbonDismissPopupEventArgs(RibbonDismissPopupMode.Always));
((Ribbon)(RibbonControlService.GetRibbon(dismissPopupSource))).RestoreFocusOnContextMenuClose();
}
}
else
{
contextMenu.RestoreFocusToRibbon();
contextMenu._ignoreDismissPopupsOnNextClose = false;
}
}
else
{
contextMenu._ignoreDismissPopupsOnNextClose = false;
}
}
/// <summary>
/// Tries to restore focus to the first focusable element across
/// the ancestor chain of ContextMenuOriginalSource. Should
/// be called only when Ribbon is supposed to retain the focus.
/// </summary>
private void RestoreFocusToRibbon()
{
DependencyObject current = GetDismissPopupSource();
if (current == null)
{
return;
}
Ribbon ribbon = RibbonControlService.GetRibbon(current);
if (ribbon == null)
{
return;
}
while (current != null)
{
UIElement uie = current as UIElement;
if (uie != null && uie.Focusable)
{
uie.Dispatcher.BeginInvoke(
(Action)delegate()
{
if (!ribbon.IsKeyboardFocusWithin)
{
uie.Focus();
}
},
DispatcherPriority.Input,
null);
break;
}
current = TreeHelper.GetParent(current);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
_ignoreDismissPopupsOnNextClose = true;
try
{
base.OnKeyDown(e);
}
finally
{
// reset the value of _ignoreDismissPopupsOnNextClose because
// the escape might not have been to close the context menu itself.
_ignoreDismissPopupsOnNextClose = false;
}
}
else
{
base.OnKeyDown(e);
}
}
private UIElement GetDismissPopupSource()
{
UIElement placementTarget = PlacementTarget;
if (placementTarget == null)
{
return null;
}
Ribbon ribbon = RibbonControlService.GetRibbon(placementTarget);
if (ribbon == null)
{
return null;
}
// The original source for corresponding ContextMenuOpening will
// be the original source for DismissPopup event.
UIElement returnValue = ribbon.ContextMenuOriginalSource;
if (returnValue == null)
{
returnValue = placementTarget;
}
return returnValue;
}
private static void OnClickThroughThunk(object sender, MouseButtonEventArgs e)
{
((RibbonContextMenu)sender).OnClickThrough();
}
private void OnClickThrough()
{
UIElement dismissPopupSource = GetDismissPopupSource();
if (Mouse.Captured == this &&
CanRaiseDismissPopups(dismissPopupSource))
{
dismissPopupSource.Dispatcher.BeginInvoke(
(Action)delegate()
{
if (CanRaiseDismissPopups(dismissPopupSource))
{
dismissPopupSource.RaiseEvent(new RibbonDismissPopupEventArgs(RibbonDismissPopupMode.MousePhysicallyNotOver));
}
},
DispatcherPriority.Input,
null);
if (IsOpen)
{
_ignoreDismissPopupsOnNextClose = true;
}
}
}
#endregion
#region Instance Generation
[ThreadStatic]
private static RibbonContextMenu _galleryContextMenu;
[ThreadStatic]
private static RibbonContextMenu _ribbonControlContextMenu;
[ThreadStatic]
private static RibbonContextMenu _qatControlContextMenu;
[ThreadStatic]
private static RibbonContextMenu _defaultRibbonClientAreaContextMenu;
internal static RibbonContextMenu ChooseContextMenu(DependencyObject owner)
{
if (owner is Ribbon)
{
return GetDefaultRibbonClientAreaContextMenu();
}
else if (RibbonControlService.GetCanAddToQuickAccessToolBarDirectly(owner))
{
if (owner is RibbonGallery)
{
return GetGalleryContextMenu();
}
else
{
if (RibbonControlService.GetIsInQuickAccessToolBar(owner))
{
return GetQATControlContextMenu();
}
else
{
return GetRibbonControlContextMenu();
}
}
}
return null;
}
private static RibbonContextMenu GetDefaultRibbonClientAreaContextMenu()
{
if (_defaultRibbonClientAreaContextMenu == null)
{
_defaultRibbonClientAreaContextMenu = new RibbonContextMenu();
_defaultRibbonClientAreaContextMenu.Items.Add(GenerateQATPlacementMenuItem(_defaultRibbonClientAreaContextMenu));
_defaultRibbonClientAreaContextMenu.Items.Add(new RibbonSeparator());
_defaultRibbonClientAreaContextMenu.Items.Add(GenerateMinimizeTheRibbonItem(_defaultRibbonClientAreaContextMenu));
}
return _defaultRibbonClientAreaContextMenu;
}
private static RibbonContextMenu GetRibbonControlContextMenu()
{
if (_ribbonControlContextMenu == null)
{
_ribbonControlContextMenu = new RibbonContextMenu();
_ribbonControlContextMenu.Items.Add(GenerateAddToOrRemoveFromQATItem(false, _ribbonControlContextMenu));
_ribbonControlContextMenu.Items.Add(new RibbonSeparator());
_ribbonControlContextMenu.Items.Add(GenerateQATPlacementMenuItem(_ribbonControlContextMenu));
_ribbonControlContextMenu.Items.Add(new RibbonSeparator());
_ribbonControlContextMenu.Items.Add(GenerateMinimizeTheRibbonItem(_ribbonControlContextMenu));
}
return _ribbonControlContextMenu;
}
private static RibbonContextMenu GetQATControlContextMenu()
{
if (_qatControlContextMenu == null)
{
_qatControlContextMenu = new RibbonContextMenu();
_qatControlContextMenu.Items.Add(GenerateAddToOrRemoveFromQATItem(true, _qatControlContextMenu));
_qatControlContextMenu.Items.Add(new RibbonSeparator());
_qatControlContextMenu.Items.Add(GenerateQATPlacementMenuItem(_qatControlContextMenu));
_qatControlContextMenu.Items.Add(new RibbonSeparator());
_qatControlContextMenu.Items.Add(GenerateMinimizeTheRibbonItem(_qatControlContextMenu));
}
return _qatControlContextMenu;
}
#region RibbonGallery
private static RibbonContextMenu GetGalleryContextMenu()
{
if (_galleryContextMenu == null)
{
_galleryContextMenu = new RibbonContextMenu();
RibbonMenuItem addGalleryToQATItem = GenerateAddGalleryToQATItem(_galleryContextMenu);
_galleryContextMenu.Items.Add(addGalleryToQATItem);
}
return _galleryContextMenu;
}
private static RibbonMenuItem GenerateAddGalleryToQATItem(RibbonContextMenu contextMenu)
{
RibbonMenuItem addGalleryToQATItem = new RibbonMenuItem();
addGalleryToQATItem.Header = _addGalleryToQATText;
// Even for galleries in QAT, this menu item always binds the "add to QAT" command.
addGalleryToQATItem.Command = RibbonCommands.AddToQuickAccessToolBarCommand;
Binding placementTargetBinding = new Binding("PlacementTarget") { Source = contextMenu };
addGalleryToQATItem.SetBinding(RibbonMenuItem.CommandTargetProperty, placementTargetBinding);
return addGalleryToQATItem;
}
#endregion
private static RibbonMenuItem GenerateAddToOrRemoveFromQATItem(bool controlIsInQAT, RibbonContextMenu contextMenu)
{
RibbonMenuItem addToOrRemoveFromQATItem = new RibbonMenuItem() { CanAddToQuickAccessToolBarDirectly = false };
if (controlIsInQAT)
{
addToOrRemoveFromQATItem.Header = RemoveFromQATText;
addToOrRemoveFromQATItem.Command = RibbonCommands.RemoveFromQuickAccessToolBarCommand;
}
else
{
addToOrRemoveFromQATItem.Header = AddToQATText;
addToOrRemoveFromQATItem.Command = RibbonCommands.AddToQuickAccessToolBarCommand;
}
Binding placementTargetBinding = new Binding("PlacementTarget") { Source = contextMenu };
addToOrRemoveFromQATItem.SetBinding(RibbonMenuItem.CommandTargetProperty, placementTargetBinding);
return addToOrRemoveFromQATItem;
}
private static RibbonMenuItem GenerateQATPlacementMenuItem(RibbonContextMenu contextMenu)
{
RibbonMenuItem qatPlacementItem = new RibbonMenuItem() { CanAddToQuickAccessToolBarDirectly = false };
Binding headerBinding = new Binding("PlacementTarget") { Source = contextMenu };
headerBinding.Converter = new PlacementTargetToQATPositionConverter(PlacementTargetToQATPositionConverter.ConverterMode.Header);
qatPlacementItem.SetBinding(RibbonMenuItem.HeaderProperty, headerBinding);
Binding commandBinding = new Binding("PlacementTarget") { Source = contextMenu };
commandBinding.Converter = new PlacementTargetToQATPositionConverter(PlacementTargetToQATPositionConverter.ConverterMode.Command);
qatPlacementItem.SetBinding(RibbonMenuItem.CommandProperty, commandBinding);
Binding placementTargetBinding = new Binding("PlacementTarget") { Source = contextMenu };
qatPlacementItem.SetBinding(RibbonMenuItem.CommandTargetProperty, placementTargetBinding);
return qatPlacementItem;
}
// This converter allows us to determine whether a RibbonContextMenu's menu item corresponding
// to QAT placement should correspond to "Show QAT Above the Ribbon" or "Show QAT Below the Ribbon".
// The converter takes the PlacementTarget of the RibbonContextMenu and determines the QAT position,
// which tells us which value to return.
//
// The ConverterMode enum allows us to reuse this Converter to determine both the correct Header
// to display and the correct Command to fire.
private sealed class PlacementTargetToQATPositionConverter : IValueConverter
{
public enum ConverterMode { Header, Command };
private ConverterMode _mode;
public PlacementTargetToQATPositionConverter(ConverterMode mode)
{
_mode = mode;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DependencyObject d = value as DependencyObject;
if (d != null)
{
Ribbon ribbon = RibbonControlService.GetRibbon(d);
if (ribbon != null &&
!ribbon.ShowQuickAccessToolBarOnTop)
{
if (_mode == ConverterMode.Header)
{
return ShowQATAboveText;
}
else
{
return RibbonCommands.ShowQuickAccessToolBarAboveRibbonCommand;
}
}
}
if (_mode == ConverterMode.Header)
{
return ShowQATBelowText;
}
else
{
return RibbonCommands.ShowQuickAccessToolBarBelowRibbonCommand;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
private static RibbonMenuItem GenerateMinimizeTheRibbonItem(RibbonContextMenu contextMenu)
{
RibbonMenuItem minimizeTheRibbonItem = new RibbonMenuItem() { CanAddToQuickAccessToolBarDirectly = false };
minimizeTheRibbonItem.Header = MinimizeTheRibbonText;
PropertyPath path = new PropertyPath("(0).(1).(2)");
path.PathParameters.Add(ContextMenuService.PlacementTargetProperty);
path.PathParameters.Add(RibbonControlService.RibbonProperty);
path.PathParameters.Add(Ribbon.IsMinimizedProperty);
Binding isCheckedBinding = new Binding () { Source = contextMenu, Path = path };
minimizeTheRibbonItem.SetBinding(RibbonMenuItem.IsCheckedProperty, isCheckedBinding);
Binding isMinimizedBinding = new Binding() { Source = contextMenu, Path = path };
isMinimizedBinding.Converter = new IsMinimizedToMinimizeOrMaximizeCommandConverter();
minimizeTheRibbonItem.SetBinding(RibbonMenuItem.CommandProperty, isMinimizedBinding);
Binding placementTargetBinding = new Binding("PlacementTarget") { Source = contextMenu };
minimizeTheRibbonItem.SetBinding(RibbonMenuItem.CommandTargetProperty, placementTargetBinding);
return minimizeTheRibbonItem;
}
private sealed class IsMinimizedToMinimizeOrMaximizeCommandConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool ribbonIsMinimized = (bool)value;
if (ribbonIsMinimized)
{
return RibbonCommands.MaximizeRibbonCommand;
}
return RibbonCommands.MinimizeRibbonCommand;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
#endregion
#region ContainerGeneration
private object _currentItem;
protected override bool IsItemItsOwnContainerOverride(object item)
{
bool ret = (item is RibbonMenuItem) || (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 RibbonMenuItem || itemContainer is RibbonGallery || itemContainer is RibbonSeparator)
{
return itemContainer as DependencyObject;
}
else
{
throw new InvalidOperationException(Microsoft.Windows.Controls.SR.Format(Microsoft.Windows.Controls.SR.InvalidMenuButtonOrItemContainer, this.GetType().Name, itemContainer));
}
}
}
return new RibbonMenuItem();
}
protected override bool ShouldApplyItemContainerStyle(DependencyObject container, object item)
{
if (container is RibbonSeparator ||
container is RibbonGallery)
{
return false;
}
else
{
return base.ShouldApplyItemContainerStyle(container, item);
}
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
if (element is RibbonGallery)
{
HasGallery = (++_galleryCount > 0);
}
else
{
RibbonSeparator separator = element as RibbonSeparator;
if (separator != null)
{
ValueSource vs = DependencyPropertyHelper.GetValueSource(separator, StyleProperty);
if (vs.BaseValueSource <= BaseValueSource.ImplicitStyleReference)
separator.SetResourceReference(StyleProperty, MenuItem.SeparatorStyleKey);
separator.DefaultStyleKeyInternal = MenuItem.SeparatorStyleKey;
}
}
}
protected override void ClearContainerForItemOverride(DependencyObject element, object item)
{
base.ClearContainerForItemOverride(element, item);
if (element is RibbonGallery)
{
HasGallery = (--_galleryCount > 0);
}
}
#if !RIBBON_IN_FRAMEWORK
/// <summary>
/// DependencyProperty for ItemContainerTemplateSelector property.
/// </summary>
public static readonly DependencyProperty ItemContainerTemplateSelectorProperty =
RibbonMenuButton.ItemContainerTemplateSelectorProperty.AddOwner(
typeof(RibbonContextMenu),
new FrameworkPropertyMetadata(new DefaultItemContainerTemplateSelector()));
/// <summary>
/// DataTemplateSelector property which provides the DataTemplate to be used to create an instance of the ItemContainer.
/// </summary>
public ItemContainerTemplateSelector ItemContainerTemplateSelector
{
get { return (ItemContainerTemplateSelector)GetValue(ItemContainerTemplateSelectorProperty); }
set { SetValue(ItemContainerTemplateSelectorProperty, value); }
}
/// <summary>
/// DependencyProperty for UsesItemContainerTemplate property.
/// </summary>
public static readonly DependencyProperty UsesItemContainerTemplateProperty =
RibbonMenuButton.UsesItemContainerTemplateProperty.AddOwner(typeof(RibbonContextMenu));
/// <summary>
/// UsesItemContainerTemplate property which says whether the ItemContainerTemplateSelector property is to be used.
/// </summary>
public bool UsesItemContainerTemplate
{
get { return (bool)GetValue(UsesItemContainerTemplateProperty); }
set { SetValue(UsesItemContainerTemplateProperty, value); }
}
#endif
public static readonly DependencyProperty HasGalleryProperty = RibbonMenuButton.HasGalleryPropertyKey.DependencyProperty.AddOwner(typeof(RibbonContextMenu));
/// <summary>
/// Indicates that there is atleast one RibbonGallery in Items collection.
/// </summary>
public bool HasGallery
{
get { return (bool)GetValue(HasGalleryProperty); }
private set { SetValue(RibbonMenuButton.HasGalleryPropertyKey, value); }
}
#endregion ContainerGeneration
#region Private Methods
private void OnLoaded(object sender, RoutedEventArgs e)
{
RibbonHelper.FindAndHookPopup(this, ref _popup);
}
#endregion Private Methods
#region Private Data
private int _galleryCount;
private Popup _popup;
internal static string AddToQATText = Microsoft.Windows.Controls.SR.RibbonContextMenu_AddToQAT;
private static string _addGalleryToQATText = Microsoft.Windows.Controls.SR.RibbonContextMenu_AddGalleryToQAT;
internal static string RemoveFromQATText = Microsoft.Windows.Controls.SR.RibbonContextMenu_RemoveFromQAT;
internal static string ShowQATAboveText = Microsoft.Windows.Controls.SR.RibbonContextMenu_ShowQATAbove;
internal static string ShowQATBelowText = Microsoft.Windows.Controls.SR.RibbonContextMenu_ShowQATBelow;
internal static string MaximizeTheRibbonText = Microsoft.Windows.Controls.SR.RibbonContextMenu_MaximizeTheRibbon;
internal static string MinimizeTheRibbonText = Microsoft.Windows.Controls.SR.RibbonContextMenu_MinimizeTheRibbon;
private bool _ignoreDismissPopupsOnNextClose = false;
#endregion
}
}
|