private void TransferPseudoInheritedProperties() { if (_templateRoot != null) { // Ribbon is an inherited property. In non-MVVM scenarios where // controls are directly added under RibbonGroup in XAML, RibbonGroup // is the logical parent of those controls and they get the value // of RibbonParent set from their logical parent. When a RibbonGroup // get collapsed and its template changes, due to a bug in framework // the inheritance value of those controls is lost during visual tree // change and never again gets updated. The workaround is to set the // local value on those controls from RibbonContentPresenter which // would be their visual parent. This works because Ribbon property is // readonly. RibbonControlService.SetRibbon(_templateRoot, RibbonControlService.GetRibbon(this)); RibbonHelper.TransferPseudoInheritedProperties(this, _templateRoot); } }
/// <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); } }
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; } }
protected override Size MeasureOverride(Size availableSize) { Size desiredSize = new Size(); IContainsStarLayoutManager iContainsStarLayoutManager = (IContainsStarLayoutManager)this; RibbonHelper.InitializeStarLayoutManager(this); bool isStarLayoutPass = (iContainsStarLayoutManager.StarLayoutManager == null ? false : iContainsStarLayoutManager.StarLayoutManager.IsStarLayoutPass); if (!isStarLayoutPass) { desiredSize = NonStarPassMeasure(availableSize); } else { desiredSize = StarMeasurePass(availableSize); } return(desiredSize); }
protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (!e.Handled) { DependencyObject focusedElement = Keyboard.FocusedElement as DependencyObject; RibbonTabHeader tabHeader = RibbonTabHeader; if (e.Key == Key.Up && focusedElement != null && tabHeader != null) { // On arrow up key press if the focus goes out of the tab, // then force it to move to the corresponding TabHeader. DependencyObject upObj = RibbonHelper.PredictFocus(focusedElement, FocusNavigationDirection.Up); if (!RibbonHelper.IsAncestorOf(this, upObj)) { if (tabHeader.Focus()) { e.Handled = true; } } } } }
protected override void ClearContainerForItemOverride(DependencyObject element, object item) { base.ClearContainerForItemOverride(element, item); RibbonHelper.ClearPseudoInheritedProperties(element); }
private void OnClickThrough(MouseButtonEventArgs e) { UIElement popupChild = _overflowPopup.TryGetChild(); RibbonHelper.HandleClickThrough(this, e, popupChild); }
protected override void OnPreviewKeyDown(KeyEventArgs e) { if (e.Handled) { return; } if (e.Key == Key.Down) { DependencyObject element = e.OriginalSource as DependencyObject; if (element != null) { UIElement footerPaneHost = FooterPaneHost; if (footerPaneHost != null && footerPaneHost.IsKeyboardFocusWithin && TreeHelper.IsVisualAncestorOf(footerPaneHost, element)) { DependencyObject nextFocus = RibbonHelper.PredictFocus(element, FocusNavigationDirection.Down); if (nextFocus == null || nextFocus == element) { // If the focus is on the last element of footer pane, // then try moving focus into items pane and then into // auxiliary pane if needed. if (ItemsPaneMoveFocus(FocusNavigationDirection.First) || AuxiliaryPaneMoveFocus(FocusNavigationDirection.First)) { e.Handled = true; } } } } } else if (e.Key == Key.Up) { UIElement popupChild = _popup.TryGetChild(); if (popupChild != null && !popupChild.IsKeyboardFocusWithin) { // If the popup does not have focus with in then try moving focus to // last element of FooterPane and then to the last element of // auxiliary pane if needed. if (FooterPaneMoveFocus(FocusNavigationDirection.Last) || AuxiliaryPaneMoveFocus(FocusNavigationDirection.Last)) { e.Handled = true; } } else { DependencyObject element = e.OriginalSource as DependencyObject; if (element != null) { UIElement auxilaryPaneHost = AuxiliaryPaneHost; if (auxilaryPaneHost != null && auxilaryPaneHost.IsKeyboardFocusWithin && TreeHelper.IsVisualAncestorOf(auxilaryPaneHost, element)) { DependencyObject nextFocus = RibbonHelper.PredictFocus(element, FocusNavigationDirection.Up); if (nextFocus == null || nextFocus == element) { // If the focus is on last first element of auxiliary pane, // then try moving focus to last element of Items Pane and // then to last element of FooterPane if needed. if (ItemsPaneMoveFocus(FocusNavigationDirection.Last) || FooterPaneMoveFocus(FocusNavigationDirection.Last)) { e.Handled = true; } } } } } } else if (e.Key == Key.Left || e.Key == Key.Right) { DependencyObject element = e.OriginalSource as DependencyObject; if (element != null) { if ((e.Key == Key.Left) == (FlowDirection == FlowDirection.LeftToRight)) { UIElement auxilaryPaneHost = AuxiliaryPaneHost; if (auxilaryPaneHost != null && auxilaryPaneHost.IsKeyboardFocusWithin && TreeHelper.IsVisualAncestorOf(auxilaryPaneHost, element)) { // If the effective key is left and the focus is on left most element // of auxiliary pane, then move focus to nearest element to the left of // auxiliarypane. DependencyObject nextFocus = RibbonHelper.PredictFocus(element, FocusNavigationDirection.Last); if (nextFocus != null && !TreeHelper.IsVisualAncestorOf(auxilaryPaneHost, nextFocus)) { if (RibbonHelper.Focus(nextFocus)) { e.Handled = true; } } } } else if (e.Key == Key.Left) { ScrollViewer subMenuScrollViewer = SubMenuScrollViewer; if (subMenuScrollViewer != null && subMenuScrollViewer.IsKeyboardFocusWithin && TreeHelper.IsVisualAncestorOf(subMenuScrollViewer, element)) { // If the flow direction is RightToLeft and the key is Left, // and the focus is in items pane, move the the focus outside teh // items pane if needed. RibbonMenuItem menuItem = element as RibbonMenuItem; if (menuItem == null) { menuItem = TreeHelper.FindVisualAncestor <RibbonMenuItem>(element); } if (menuItem != null && !menuItem.CanOpenSubMenu) { DependencyObject nextFocus = menuItem.PredictFocus(FocusNavigationDirection.Right); if (nextFocus != null) { if (RibbonHelper.Focus(nextFocus)) { e.Handled = true; } } } } } } } base.OnPreviewKeyDown(e); }
/// <summary> /// Called by consumers of TextSearchInternal when a TextInput event is received /// to kick off the algorithm. /// </summary> /// <param name="nextChar"></param> /// <returns></returns> internal bool DoSearch(string nextChar) { bool repeatedChar = false; int startItemIndex = 0; ItemCollection itemCollection = _attachedTo.Items as ItemCollection; // If TextSearchInternal is not active, then we should start // the search from the beginning. If it is active, we should // start the search from the currently-matched item. if (IsActive) { // ISSUE: This falls victim to duplicate elements being in the view. // To mitigate this, we could remember ItemUI ourselves. startItemIndex = MatchedItemIndex; } // If they pressed the same character as last time, we will do the fallback search. // Fallback search is if they type "bob" and then press "b" // we'll look for "bobb" and when we don't find it we should // find the next item starting with "bob". if (_charsEntered.Count > 0 && (String.Compare(_charsEntered[_charsEntered.Count - 1], nextChar, true, GetCulture(_attachedTo)) == 0)) { repeatedChar = true; } // Get the primary TextPath from the ItemsControl to which we are attached. string primaryTextPath = GetPrimaryTextPath(_attachedTo, false); bool wasNewCharUsed = false; int matchedItemIndex = FindMatchingPrefix(_attachedTo, primaryTextPath, Prefix, nextChar, startItemIndex, repeatedChar, ref wasNewCharUsed); // If there was an item that matched, move to that item in the collection if (matchedItemIndex != -1) { // Don't have to move currency if it didn't actually move. // startItemIndex is the index of the current item only if IsActive is true, // So, we have to move currency when IsActive is false. if (!IsActive || matchedItemIndex != startItemIndex) { object matchedItem = itemCollection[matchedItemIndex]; // Let the control decide what to do with matched-item RibbonHelper.NavigateToItem(_attachedTo, matchedItemIndex, null); // Store current match MatchedItemIndex = matchedItemIndex; } // Update the prefix if it changed if (wasNewCharUsed) { AddCharToPrefix(nextChar); } // User has started typing (successfully), so we're active now. if (!IsActive) { IsActive = true; } } // Reset the timeout and remember this character, but only if we're // active -- this is because if we got called but the match failed // we don't need to set up a timeout -- no state needs to be reset. if (IsActive) { ResetTimeout(); } return(matchedItemIndex != -1); }
private void OnRibbonGalleryCategoriesPanelLoaded(object sender, RoutedEventArgs e) { RibbonHelper.InitializeStarLayoutManager(this); }
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) { base.OnLostKeyboardFocus(e); RibbonHelper.DisableFocusVisual(this); }
/// <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); }
/// <summary> /// In normal(Star) pass this panel behaves like a StackPanel but during Auto(non Star) pass /// It returns minimum Width and Height required to represent the children. There is another /// mode wherein it provides laying out mechanism for InRibbonGallery in INRibbon mode. /// </summary> /// <param name="availableSize"></param> /// <returns></returns> protected override Size MeasureOverride(Size availableSize) { RibbonGallery gallery = this.Gallery; #if IN_RIBBON_GALLERY InRibbonGallery parentInRibbonGallery = gallery != null ? gallery.ParentInRibbonGallery : null; bool isInInRibbonMode = parentInRibbonGallery != null ? parentInRibbonGallery.IsInInRibbonMode : false; // For an InRibbonGallery rendering with IsDropDownOpen==true, we force gallery.ItemsPresenter's // MinWidth to be at least the value of IRG.ContentPresenter.ActualWidth. This way, the IRG's popup // totally eclipses the IRG, which is required by the Office Fluent UI guidelines. if (gallery != null && gallery.ItemsPresenter != null && parentInRibbonGallery != null) { if (isInInRibbonMode && _irgIsConstrainingWidth) { gallery.ItemsPresenter.MinWidth = _originalGalleryItemsPresenterMinWidth; _irgIsConstrainingWidth = false; } else if (parentInRibbonGallery.IsDropDownOpen && !_irgIsConstrainingWidth) { _originalGalleryItemsPresenterMinWidth = gallery.ItemsPresenter.MinWidth; double minWidthFromParent = parentInRibbonGallery.CalculateGalleryItemsPresenterMinWidth(); gallery.ItemsPresenter.MinWidth = Math.Max(minWidthFromParent, _originalGalleryItemsPresenterMinWidth); _irgIsConstrainingWidth = true; } } if (!isInInRibbonMode) { #endif RibbonHelper.InitializeStarLayoutManager(this); #if IN_RIBBON_GALLERY } #endif IContainsStarLayoutManager iContainsStarLayoutManager = (IContainsStarLayoutManager)this; bool isStarLayoutPass = (iContainsStarLayoutManager.StarLayoutManager == null ? true : iContainsStarLayoutManager.StarLayoutManager.IsStarLayoutPass); #if IN_RIBBON_GALLERY if (isInInRibbonMode) { PreComputeMaxRibbonGalleryItemWidthAndHeight(); return(InRibbonGalleryModeMeasureOverride(availableSize)); } else { #endif if (isStarLayoutPass) { return(RealMeasureOverride(availableSize)); } else { return(AutoPassMeasureOverride()); } #if IN_RIBBON_GALLERY } #endif }
private void OnLoaded(object sender, RoutedEventArgs e) { RibbonHelper.FindAndHookPopup(this, ref _popup); }
/// <summary> /// RibbonToolTip custom placement logic /// </summary> /// <param name="popupSize">The size of the popup.</param> /// <param name="targetSize">The size of the placement target.</param> /// <param name="offset">The Point computed from the HorizontalOffset and VerticalOffset property values.</param> /// <returns>An array of possible tooltip placements.</returns> private CustomPopupPlacement[] PlaceRibbonToolTip(Size popupSize, Size targetSize, Point offset) { UIElement placementTarget = this.PlacementTarget; double belowOffsetY = 0.0; double aboveOffsetY = 0.0; double offsetX = FlowDirection == FlowDirection.LeftToRight ? 0.0 : -popupSize.Width; if (IsPlacementTargetInRibbonGroup) { // If the PlacementTarget is within a RibbonGroup we proceed // with the custom placement policy. // Walk up the visual tree from PlacementTarget to find the Ribbon // if exists or the root element which is likely a PopupRoot. Ribbon ribbon = null; DependencyObject rootElement = null; DependencyObject element = placementTarget; while (element != null) { ribbon = element as Ribbon; if (ribbon != null) { break; } rootElement = element; element = VisualTreeHelper.GetParent(element); } double additionalOffset = 1.0; FrameworkElement referenceFE = null; if (ribbon != null) { additionalOffset = 0.0; referenceFE = ribbon; } else { if (rootElement != null) { referenceFE = rootElement as FrameworkElement; } } if (referenceFE != null) { // When RibbonControl (PlacementTarget) is within a collapsed group RibbonToolTip is // placed just below the Popup or just above the Popup (in case there is not enough // screen space left below the Popup). MatrixTransform transform = referenceFE.TransformToDescendant(placementTarget) as MatrixTransform; if (transform != null) { MatrixTransform deviceTransform = new MatrixTransform(RibbonHelper.GetTransformToDevice(referenceFE)); GeneralTransformGroup transformGroup = new GeneralTransformGroup(); transformGroup.Children.Add(transform); transformGroup.Children.Add(deviceTransform); Point leftTop, rightBottom; transformGroup.TryTransform(new Point(0, 0), out leftTop); transformGroup.TryTransform(new Point(referenceFE.ActualWidth, referenceFE.ActualHeight), out rightBottom); belowOffsetY = rightBottom.Y + additionalOffset; aboveOffsetY = leftTop.Y - popupSize.Height - additionalOffset; } } } else { // If PlacementTarget isn't within a RibbonGroup we shouldn't have // gotten here in the first place. But now that we are we will make // the best attempt at emulating PlacementMode.Bottom. FrameworkElement placementTargetAsFE = placementTarget as FrameworkElement; if (placementTargetAsFE != null) { belowOffsetY = targetSize.Height; aboveOffsetY = -popupSize.Height; } } // This is the prefered placement, below the ribbon for controls within Ribbon or below the Popup for controls within Popup. CustomPopupPlacement placementPreffered = new CustomPopupPlacement(new Point(offsetX, belowOffsetY), PopupPrimaryAxis.Horizontal); // This is a fallback placement, if the tooltip will not fit below the ribbon or Popup, place it above the ribbon or Popup. CustomPopupPlacement placementFallback = new CustomPopupPlacement(new Point(offsetX, aboveOffsetY), PopupPrimaryAxis.Horizontal); return(new CustomPopupPlacement[] { placementPreffered, placementFallback }); }
public static void RemoveCloneHandler(DependencyObject element, RibbonQuickAccessToolBarCloneEventHandler handler) { RibbonHelper.RemoveHandler(element, CloneEvent, handler); }
public static void RemoveDismissPopupHandler(DependencyObject element, RibbonDismissPopupEventHandler handler) { RibbonHelper.RemoveHandler(element, DismissPopupEvent, handler); }
protected override void OnKeyDown(KeyEventArgs e) { RibbonHelper.OnApplicationMenuItemUpDownKeyDown(e, this); base.OnKeyDown(e); }
/// <summary> /// TextSearchInternal in an ItemsControl containing ItemsControls as children (i.e. RibbonGallery) /// performs TextSearchInternal on the second level Items. /// </summary> /// <param name="nextChar"></param> /// <returns></returns> internal bool DoHierarchicalSearch(string nextChar) { bool repeatedChar = false; // If they pressed the same character as last time, we will do the fallback search. // Fallback search is if they type "bob" and then press "b" // we'll look for "bobb" and when we don't find it we should // find the next item starting with "bob". if (_charsEntered.Count > 0 && (String.Compare(_charsEntered[_charsEntered.Count - 1], nextChar, true, GetCulture(_attachedTo)) == 0)) { repeatedChar = true; } bool wasNewCharUsed = false; int matchedItemIndex = -1; int startItemsControlIndex = 0; // If TextSearchInternal is not active, then we should start // the search from the beginning. If it is active, we should // start the search from the ItemsControl containing the currently-matched item. if (IsActive) { startItemsControlIndex = MatchedItemsControlIndex; } int itemCount = _attachedTo.Items.Count; for (int currentIndex = startItemsControlIndex; currentIndex < itemCount;) { // Skip over filtered categories ItemsControl childItemsControl = _attachedTo.ItemContainerGenerator.ContainerFromIndex(currentIndex) as ItemsControl; if (childItemsControl != null && childItemsControl.Visibility == Visibility.Visible) { int startItemIndex = 0; // If TextSearchInternal is not active, then we should start // the search from the beginning. If it is active, we should // start the search from the currently-matched item. if (IsActive) { startItemIndex = MatchedItemIndex; } ItemCollection itemCollection = childItemsControl.Items as ItemCollection; // Get the primary TextPath from the child ItemsControl string primaryTextPath = GetPrimaryTextPath(childItemsControl, true); matchedItemIndex = FindMatchingPrefix(childItemsControl, primaryTextPath, Prefix, nextChar, startItemIndex, repeatedChar, ref wasNewCharUsed, /* hierarchicalSearch */ true, /* fallbackFirstItem */ currentIndex != startItemsControlIndex); // If there was an item that matched, move to that item in the collection if (matchedItemIndex != -1) { // Don't have to move currency if it didn't actually move. // startItemIndex is the index of the current item only if IsActive is true, // So, we have to move currency when IsActive is false. if (!IsActive || matchedItemIndex != startItemIndex || currentIndex != startItemsControlIndex) { object matchedItem = itemCollection[matchedItemIndex]; // Let the control decide what to do with matched-item RibbonHelper.NavigateToItem(childItemsControl, matchedItemIndex, null); // Store current match MatchedItemIndex = matchedItemIndex; MatchedItemsControlIndex = currentIndex; } // Update the prefix if it changed if (wasNewCharUsed) { AddCharToPrefix(nextChar); } // User has started typing (successfully), so we're active now. if (!IsActive) { IsActive = true; } } // Reset the timeout and remember this character, but only if we're // active -- this is because if we got called but the match failed // we don't need to set up a timeout -- no state needs to be reset. if (IsActive) { ResetTimeout(); } // Found a match so exit the loop. if (matchedItemIndex != -1) { return(true); } // Reset matchedItemIndex because we are moving to the next childItemsControl MatchedItemIndex = 0; } // Move next and wrap-around if we pass the end of the container. currentIndex++; if (currentIndex >= itemCount) { currentIndex = 0; } // Stop where we started but only after the first pass // through the loop -- we should process the startItem. if (currentIndex == startItemsControlIndex) { break; } } return(false); }
private static void AddToQATCanExecute(object sender, CanExecuteRoutedEventArgs args) { DependencyObject thatCanBeAddedToQat = MyRibbon.FindElementThatCanBeAddedToQAT(args.OriginalSource as DependencyObject); if (thatCanBeAddedToQat == null || RibbonControlService.GetQuickAccessToolBarId(thatCanBeAddedToQat) == null || RibbonHelper.ExistsInQAT(thatCanBeAddedToQat)) { return; } args.CanExecute = true; }