/// <summary> /// Determines the display title of a menu item /// </summary> /// <param name="category">The category.</param> /// <returns>Title</returns> protected virtual string GetMenuTitle(ViewActionCategory category) { var sb = new StringBuilder(); var titleChars = category.Caption.ToCharArray(); var titleCharsLower = category.Caption.ToLower().ToCharArray(); var foundAccessKey = false; var lowerKey = category.AccessKey.ToString(CultureInfo.CurrentUICulture).ToLower().ToCharArray()[0]; for (var counter = 0; counter < titleChars.Length; counter++) { var character = titleChars[counter]; var characterLower = titleCharsLower[counter]; if (category.AccessKey != ' ' && !foundAccessKey && characterLower == lowerKey) { sb.Append("_"); // This is the hotkey indicator in WPF foundAccessKey = true; } if (character == '_') { sb.Append("_"); // Escaping the underscore so it really shows up in the menu rather than being interpreted special } sb.Append(character); } if (!foundAccessKey && category.AccessKey != ' ') { sb.Append(" (_"); sb.Append(category.AccessKey); sb.Append(")"); } var title = sb.ToString(); if (ForceTopLevelMenuItemsUpperCase) { title = title.ToUpper(); } return(title); }
/// <summary> /// Gets all actions that fall under the specified category /// </summary> /// <param name="actions">The actions.</param> /// <param name="category">The category.</param> /// <param name="indentLevel">The indent level.</param> /// <param name="emptyCategory">The empty category.</param> /// <param name="orderByGroupTitle">If true, then the result set is first ordered by group title.</param> /// <returns>IEnumerable{IViewAction}.</returns> public static IEnumerable<IViewAction> GetAllActionsForCategory(IEnumerable<IViewAction> actions, ViewActionCategory category, int indentLevel = 0, string emptyCategory = "File", bool orderByGroupTitle = true) { var result = new List<IViewAction>(); foreach (var action in actions) { if (indentLevel == 0 && ((category.Id == emptyCategory || string.IsNullOrEmpty(category.Id)) && (action.Categories == null || action.Categories.Count == 0))) // If no other category is assigned, then we consider items to be on the file menu result.Add(action); else if (action.Categories != null && action.Categories.Count > indentLevel && action.Categories[indentLevel].Id == category.Id) result.Add(action); else if (action.Categories != null && action.Categories.Count > indentLevel && action.Categories[indentLevel].Id == emptyCategory && string.IsNullOrEmpty(category.Id)) result.Add(action); } if (orderByGroupTitle) return result.OrderBy(a => a.GroupTitle + ":::" + a.Order.ToString("0000000000")).ToList(); return result.OrderBy(a => a.Order).ToList(); }
/// <summary> /// Gets all actions for the specified category. /// </summary> /// <param name="actions">The actions.</param> /// <param name="category">The category.</param> /// <param name="indentLevel">The indent level.</param> /// <param name="emptyCategory">The empty category.</param> /// <param name="orderByGroupTitle">if set to <c>true</c> [order by group title].</param> /// <param name="viewModel">Optional view model object</param> /// <returns>IEnumerable<IViewAction>.</returns> public virtual IEnumerable <IViewAction> GetAllActionsForCategory(IEnumerable <IViewAction> actions, ViewActionCategory category, int indentLevel = 0, string emptyCategory = "File", bool orderByGroupTitle = true, object viewModel = null) => ViewActionHelper.GetAllActionsForCategory(actions, category, indentLevel, emptyCategory, orderByGroupTitle);
/// <summary> /// Adds sub-items for the specified tab item and category /// </summary> /// <param name="parentPanel">Parent item container</param> /// <param name="category">Category we are interested in</param> /// <param name="actions">Actions to consider</param> /// <param name="indentLevel">Current hierarchical indentation level</param> /// <param name="ribbonPage">The ribbon page.</param> /// <param name="visibilityBinding">The visibility binding.</param> protected virtual void PopulateSubCategories(Panel parentPanel, ViewActionCategory category, IEnumerable<IViewAction> actions, int indentLevel = 0, RibbonPage ribbonPage = null, MultiBinding visibilityBinding = null) { var populatedCategories = new List<string>(); if (actions == null) return; var viewActions = actions as IViewAction[] ?? actions.ToArray(); var matchingActions = ViewActionHelper.GetAllActionsForCategory(viewActions, category, indentLevel, EmptyGlobalCategoryTitle); var addedMenuItems = 0; foreach (var matchingAction in matchingActions) { if (addedMenuItems > 0 && matchingAction.BeginGroup) parentPanel.Children.Add(new RibbonSeparator()); if (matchingAction.Categories != null && matchingAction.Categories.Count > indentLevel + 1 && !populatedCategories.Contains(matchingAction.Categories[indentLevel].Id)) // This is further down in a sub-category even { populatedCategories.Add(matchingAction.Categories[indentLevel].Id); var newRibbonButton = new RibbonButtonLarge {Content = matchingAction.Categories[indentLevel].Caption, Visibility = matchingAction.Visibility}; CreateMenuItemBinding(matchingAction, newRibbonButton); if (visibilityBinding != null) visibilityBinding.Bindings.Add(new Binding("Visibility") {Source = newRibbonButton}); PopulateSubCategories(parentPanel, matchingAction.Categories[indentLevel], viewActions, indentLevel + 1); newRibbonButton.AccessKey = matchingAction.AccessKey.ToString(CultureInfo.CurrentUICulture).Trim().ToUpper(); parentPanel.Children.Add(newRibbonButton); addedMenuItems++; } else { var realAction = matchingAction as ViewAction; Brush iconBrush = Brushes.Transparent; if (realAction != null) iconBrush = realAction.Brush; if (matchingAction.ActionView != null) { if (matchingAction.ActionViewModel != null && matchingAction.ActionView.DataContext == null) matchingAction.ActionView.DataContext = matchingAction.ActionViewModel; var command = GetRibbonItemCommand(matchingAction.ActionView); if (command == null) SetRibbonItemCommand(matchingAction.ActionView, matchingAction); if (visibilityBinding != null) visibilityBinding.Bindings.Add(new Binding("Visibility") {Source = matchingAction.ActionView}); ElementHelper.DetachElementFromParent(matchingAction.ActionView); if (matchingAction.ActionView.Style == null) { var resource = TryFindResource("CODE.Framework-Ribbon-CustomControlContainerStyle"); if (resource != null) { var genericStyle = resource as Style; if (genericStyle != null) matchingAction.ActionView.Style = genericStyle; } } matchingAction.ActionView.IsVisibleChanged += (s, e) => InvalidateAll(); parentPanel.Children.Add(matchingAction.ActionView); } else { RibbonButton newRibbonButton; if (matchingAction.Significance == ViewActionSignificance.AboveNormal || matchingAction.Significance == ViewActionSignificance.Highest) newRibbonButton = new RibbonButtonLarge { Content = matchingAction.Caption, Command = matchingAction, Icon = iconBrush, Visibility = matchingAction.Visibility }; else newRibbonButton = new RibbonButtonSmall { Content = matchingAction.Caption, Command = matchingAction, Icon = iconBrush, Visibility = matchingAction.Visibility }; newRibbonButton.IsVisibleChanged += (s, e) => InvalidateAll(); newRibbonButton.SetBinding(ContentControl.ContentProperty, new Binding("Caption") {Source = matchingAction, Mode = BindingMode.OneWay}); CreateMenuItemBinding(matchingAction, newRibbonButton); if (visibilityBinding != null) visibilityBinding.Bindings.Add(new Binding("Visibility") {Source = newRibbonButton}); if (matchingAction.ViewActionType == ViewActionTypes.Toggle) newRibbonButton.SetBinding(RibbonButton.IsCheckedProperty, new Binding("IsChecked") {Source = matchingAction}); if (matchingAction.AccessKey != ' ') newRibbonButton.AccessKey = matchingAction.AccessKey.ToString(CultureInfo.CurrentUICulture).Trim().ToUpper(); parentPanel.Children.Add(newRibbonButton); HandleRibbonShortcutKey(newRibbonButton, matchingAction, ribbonPage); } addedMenuItems++; } } if (addedMenuItems > 0) parentPanel.Children.Add(new RibbonSeparator()); }
/// <summary> /// Gets all actions that fall under the specified category /// </summary> /// <param name="actions">The actions.</param> /// <param name="category">The category.</param> /// <param name="indentLevel">The indent level.</param> /// <param name="emptyCategory">The empty category.</param> /// <param name="orderByGroupTitle">If true, then the result set is first ordered by group title.</param> /// <returns>IEnumerable{IViewAction}.</returns> public static IEnumerable <IViewAction> GetAllActionsForCategory(IEnumerable <IViewAction> actions, ViewActionCategory category, int indentLevel = 0, string emptyCategory = "File", bool orderByGroupTitle = true) { var result = new List <IViewAction>(); foreach (var action in actions) { if (indentLevel == 0 && ((category.Id == emptyCategory || string.IsNullOrEmpty(category.Id)) && (action.Categories == null || action.Categories.Count == 0))) // If no other category is assigned, then we consider items to be on the file menu { result.Add(action); } else if (action.Categories != null && action.Categories.Count > indentLevel && action.Categories[indentLevel].Id == category.Id) { result.Add(action); } else if (action.Categories != null && action.Categories.Count > indentLevel && action.Categories[indentLevel].Id == emptyCategory && string.IsNullOrEmpty(category.Id)) { result.Add(action); } } if (orderByGroupTitle) { return(result.OrderBy(a => a.GroupTitle + ":::" + a.Order.ToString("0000000000")).ToList()); } return(result.OrderBy(a => a.Order).ToList()); }
/// <summary> /// Retrieves a list of all categories at the root of each action /// </summary> /// <param name="actions">List of actions</param> /// <param name="emptyGlobalCategoryTitle">The empty global category title.</param> /// <param name="emptyLocalCategoryTitle">The empty local category title.</param> /// <returns>IEnumerable{ViewActionCategory}.</returns> public static IEnumerable <ViewActionCategory> GetTopLevelActionCategories(IEnumerable <IViewAction> actions, string emptyGlobalCategoryTitle = "", string emptyLocalCategoryTitle = "") { var result = new List <ViewActionCategory>(); var globalFileCategoryAdded = false; var localFileCategoryAdded = false; foreach (var action in actions) { var viewAction = action as ViewAction; if (viewAction != null && viewAction.IsLocalAction) { if (!localFileCategoryAdded && (action.Categories == null || action.Categories.Count == 0)) { result.Add(new ViewActionCategory(emptyLocalCategoryTitle.Replace(" ", ""), emptyLocalCategoryTitle) { BrushResourceKey = viewAction.CategoryBrushResourceKey }); localFileCategoryAdded = true; } else if (action.Categories != null && action.Categories.Count > 0) { var alreadyAdded = false; foreach (var category in result) { var id = action.Categories[0].Id; if (string.IsNullOrEmpty(id)) { id = emptyLocalCategoryTitle; } var caption = action.Categories[0].Caption; if (string.IsNullOrEmpty(caption)) { caption = emptyLocalCategoryTitle; } if (category.Caption == caption && category.Id == id) { alreadyAdded = true; if (string.IsNullOrEmpty(category.BrushResourceKey)) { category.BrushResourceKey = viewAction.CategoryBrushResourceKey; } break; } } if (!alreadyAdded) { var order = action.CategoryOrder; if (order == 0) { order += 10000; // Local categories are to be put at the end, unless they have a special setting } var id = action.Categories[0].Id; if (string.IsNullOrEmpty(id)) { id = emptyLocalCategoryTitle; } var caption = action.Categories[0].Caption; if (string.IsNullOrEmpty(caption)) { caption = emptyLocalCategoryTitle; } result.Add(new ViewActionCategory(id, caption, action.Categories[0].AccessKey) { IsLocalCategory = true, Order = order, BrushResourceKey = viewAction.CategoryBrushResourceKey }); } if (action.Categories[0].Id == emptyLocalCategoryTitle.Replace(" ", "")) { globalFileCategoryAdded = true; } } } else { if (!globalFileCategoryAdded && (action.Categories == null || action.Categories.Count == 0)) { var newCategory = new ViewActionCategory(emptyGlobalCategoryTitle.Replace(" ", ""), emptyGlobalCategoryTitle); if (viewAction != null) { newCategory.BrushResourceKey = viewAction.CategoryBrushResourceKey; } result.Add(newCategory); globalFileCategoryAdded = true; } else if (action.Categories != null && action.Categories.Count > 0) { var alreadyAdded = false; foreach (var category in result) { var id = action.Categories[0].Id; if (string.IsNullOrEmpty(id)) { id = emptyGlobalCategoryTitle; } var caption = action.Categories[0].Caption; if (string.IsNullOrEmpty(caption)) { caption = emptyGlobalCategoryTitle; } if (category.Caption == caption && category.Id == id) { alreadyAdded = true; if (viewAction != null && string.IsNullOrEmpty(category.BrushResourceKey)) { category.BrushResourceKey = viewAction.CategoryBrushResourceKey; } break; } } if (!alreadyAdded) { var id = action.Categories[0].Id; if (string.IsNullOrEmpty(id)) { id = emptyGlobalCategoryTitle; } var caption = action.Categories[0].Caption; if (string.IsNullOrEmpty(caption)) { caption = emptyGlobalCategoryTitle; } var newCategory = new ViewActionCategory(id, caption, action.Categories[0].AccessKey) { IsLocalCategory = false, Order = action.CategoryOrder }; if (viewAction != null) { newCategory.BrushResourceKey = viewAction.CategoryBrushResourceKey; } result.Add(newCategory); } if (action.Categories[0].Id == emptyGlobalCategoryTitle.Replace(" ", "")) { globalFileCategoryAdded = true; } } } } return(result.OrderBy(c => c.Order)); }
/// <summary> /// Adds sub-items for the specified menu item and category /// </summary> /// <param name="menuItem">Parent menu item</param> /// <param name="category">Category we are interested in</param> /// <param name="actions">Actions to consider</param> /// <param name="indentLevel">Current hierarchical indentation level</param> private void PopulateSubCategories(MenuItem menuItem, ViewActionCategory category, IEnumerable <IViewAction> actions, int indentLevel = 0) { var populatedCategories = new List <string>(); if (actions == null) { return; } var viewActions = actions as IViewAction[] ?? actions.ToArray(); var matchingActions = ViewActionPolicy != null?ViewActionPolicy.GetAllActionsForCategory(viewActions, category, indentLevel, orderByGroupTitle : false, viewModel : this) : ViewActionHelper.GetAllActionsForCategory(viewActions, category, indentLevel, orderByGroupTitle: false); var addedMenuItems = 0; foreach (var matchingAction in matchingActions) { if (addedMenuItems > 0 && matchingAction.BeginGroup) { menuItem.Items.Add(new Separator()); } if (matchingAction.Categories != null && matchingAction.Categories.Count > indentLevel + 1 && !populatedCategories.Contains(matchingAction.Categories[indentLevel].Id)) // This is further down in a sub-category even { populatedCategories.Add(matchingAction.Categories[indentLevel].Id); var newMenuItem = new ViewActionMenuItem { Header = matchingAction.Categories[indentLevel + 1].Caption }; var icon = new ThemeIcon { UseFallbackIcon = false }; icon.SetBinding(ThemeIcon.IconResourceKeyProperty, new Binding("BrushResourceKey")); newMenuItem.Icon = icon; CreateMenuItemBinding(matchingAction, newMenuItem); PopulateSubCategories(newMenuItem, matchingAction.Categories[indentLevel + 1], viewActions, indentLevel + 1); menuItem.Items.Add(newMenuItem); addedMenuItems++; } else { var newMenuItem1 = new ViewActionMenuItem { Header = GetMenuTitle(matchingAction), Command = matchingAction, DataContext = matchingAction }; HandleMenuShortcutKey(newMenuItem1, matchingAction); if (matchingAction.ViewActionType == ViewActionTypes.Toggle) { newMenuItem1.IsCheckable = true; newMenuItem1.SetBinding(MenuItem.IsCheckedProperty, new Binding("IsChecked") { Source = matchingAction, Mode = BindingMode.OneWay }); } var realMatchingAction = matchingAction as ViewAction; if (realMatchingAction != null && !string.IsNullOrEmpty(realMatchingAction.ToolTipText)) { newMenuItem1.ToolTip = realMatchingAction.ToolTipText; } var icon = new ThemeIcon { FallbackIconResourceKey = string.Empty }; icon.SetBinding(ThemeIcon.IconResourceKeyProperty, new Binding("BrushResourceKey")); newMenuItem1.Icon = icon; CreateMenuItemBinding(matchingAction, newMenuItem1); menuItem.Items.Add(newMenuItem1); addedMenuItems++; } } }
/// <summary> /// Detirmines the display title of a menu item /// </summary> /// <param name="category">The category.</param> /// <returns>Title</returns> protected virtual string GetMenuTitle(ViewActionCategory category) { var sb = new StringBuilder(); var titleChars = category.Caption.ToCharArray(); var titleCharsLower = category.Caption.ToLower().ToCharArray(); var foundAccessKey = false; var lowerKey = category.AccessKey.ToString(CultureInfo.CurrentUICulture).ToLower().ToCharArray()[0]; for (var counter = 0; counter < titleChars.Length; counter++) { var character = titleChars[counter]; var characterLower = titleCharsLower[counter]; if (category.AccessKey != ' ' && !foundAccessKey && characterLower == lowerKey) { sb.Append("_"); // This is the hotkey indicator in WPF foundAccessKey = true; } if (character == '_') sb.Append("_"); // Escaping the underscore so it really shows up in the menu rather than being interpreted special sb.Append(character); } if (!foundAccessKey && category.AccessKey != ' ') { sb.Append(" (_"); sb.Append(category.AccessKey); sb.Append(")"); } var title = sb.ToString(); if (ForceTopLevelMenuItemsUpperCase) title = title.ToUpper(); return title; }
/// <summary> /// Adds sub-items for the specified menu item and category /// </summary> /// <param name="menuItem">Parent menu item</param> /// <param name="category">Category we are interested in</param> /// <param name="actions">Actions to consider</param> /// <param name="indentLevel">Current hierarchical indentation level</param> private void PopulateSubCategories(MenuItem menuItem, ViewActionCategory category, IEnumerable<IViewAction> actions, int indentLevel = 0) { var populatedCategories = new List<string>(); if (actions == null) return; var viewActions = actions as IViewAction[] ?? actions.ToArray(); var matchingActions = ViewActionHelper.GetAllActionsForCategory(viewActions, category, indentLevel); var addedMenuItems = 0; foreach (var matchingAction in matchingActions) { if (addedMenuItems > 0 && matchingAction.BeginGroup) menuItem.Items.Add(new Separator()); if (matchingAction.Categories != null && matchingAction.Categories.Count > indentLevel + 1 && !populatedCategories.Contains(matchingAction.Categories[indentLevel].Id)) // This is further down in a sub-category even { populatedCategories.Add(matchingAction.Categories[indentLevel].Id); var newMenuItem = new ViewActionMenuItem {Header = matchingAction.Categories[indentLevel+1].Caption}; var realAction = matchingAction as ViewAction; if (realAction != null && realAction.HasBrush) newMenuItem.Icon = new ViewActionMenuIcon(realAction.PopulatedBrush); CreateMenuItemBinding(matchingAction, newMenuItem); PopulateSubCategories(newMenuItem, matchingAction.Categories[indentLevel+1], viewActions, indentLevel + 1); menuItem.Items.Add(newMenuItem); addedMenuItems++; } else { var newMenuItem1 = new ViewActionMenuItem {Header = GetMenuTitle(matchingAction), Command = matchingAction}; HandleMenuShortcutKey(newMenuItem1, matchingAction); if (matchingAction.ViewActionType == ViewActionTypes.Toggle) { newMenuItem1.IsCheckable = true; newMenuItem1.SetBinding(MenuItem.IsCheckedProperty, new Binding("IsChecked") {Source = matchingAction}); } var realAction = matchingAction as ViewAction; if (realAction != null && realAction.HasBrush) newMenuItem1.Icon = new ViewActionMenuIcon(realAction.PopulatedBrush); CreateMenuItemBinding(matchingAction, newMenuItem1); menuItem.Items.Add(newMenuItem1); addedMenuItems++; } } }