From c41bc4b9a40df23a937e44b05c80c1e7e5765ff2 Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Tue, 6 Dec 2016 18:26:38 -0500 Subject: [PATCH 1/7] Added more TextBox ContextMenu configuration -Allow for disabling cut/copy/paste in a TextBox -Allow for custom context menu items in a TextBox -Added IsCutCopyPasteInContextMenu property (defaults to true) -Added ExtraContextMenuItems property (defaults to null) --- .../ExampleViews/TextExamples.xaml | 4 + .../MainWindowViewModel.cs | 17 +++ .../Controls/Helper/TextBoxHelper.cs | 128 ++++++++++++++++-- 3 files changed, 135 insertions(+), 14 deletions(-) diff --git a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml index 0ea4ecd1fc..3143c7ddf1 100644 --- a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml +++ b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml @@ -98,6 +98,10 @@ + diff --git a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs index 033ab1426b..b1f65af850 100644 --- a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs +++ b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs @@ -220,6 +220,23 @@ public ICommand TextBoxButtonCmdWithParameter } } + private List extraMenuItems; + + public List ExtraMenuItems + { + get + { + if (extraMenuItems != null) + return extraMenuItems; + extraMenuItems = new List() + { + new MenuItem() { Header = "Sample Custom Menu Item" }, + new MenuItem() { Header = "Another Sample Item" }, + }; + return extraMenuItems; + } + } + public event PropertyChangedEventHandler PropertyChanged; /// diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs index fd9eab8905..97cbbc7005 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs @@ -15,6 +15,9 @@ namespace MahApps.Metro.Controls { + using System.Collections.Generic; + using System.ComponentModel; + /// /// A helper class that provides various attached properties for the TextBox control. /// @@ -53,6 +56,8 @@ public class TextBoxHelper public static readonly DependencyProperty HasTextProperty = DependencyProperty.RegisterAttached("HasText", typeof (bool), typeof (TextBoxHelper), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender)); public static readonly DependencyProperty IsSpellCheckContextMenuEnabledProperty = DependencyProperty.RegisterAttached("IsSpellCheckContextMenuEnabled", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(false, UseSpellCheckContextMenuChanged)); + public static readonly DependencyProperty IsCutCopyPasteInContextMenuProperty = DependencyProperty.RegisterAttached("IsCutCopyPasteInContextMenu", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(true, IsCutCopyPasteInContextMenuChanged)); + public static readonly DependencyProperty ExtraContextMenuItemsProperty = DependencyProperty.RegisterAttached("ExtraContextMenuItems", typeof(List), typeof(TextBoxHelper), new FrameworkPropertyMetadata(null, ExtraContextMenuItemsChanged)); /// /// This property can be used to retrieve the watermark using the of bound property. @@ -247,24 +252,60 @@ private static void UseSpellCheckContextMenuChanged(DependencyObject d, Dependen // set the spell check to true tb.SetValue(SpellCheck.IsEnabledProperty, true); // override pre defined context menu - tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(); + tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); tb.ContextMenuOpening += TextBoxBaseContextMenuOpening; } else { tb.SetValue(SpellCheck.IsEnabledProperty, false); - tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(); + tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); tb.ContextMenuOpening -= TextBoxBaseContextMenuOpening; } } + private static void IsCutCopyPasteInContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var tb = d as TextBoxBase; + if (null == tb) + { + throw new InvalidOperationException("The property 'IsCutCopyPasteInContextMenuChanged' may only be set on TextBoxBase elements."); + } + + tb.SetValue(IsCutCopyPasteInContextMenuProperty, e.NewValue); + tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); + AddExtraItemsToContextMenu(tb, tb.ContextMenu.Items.Count > 0); + if (!(bool)e.NewValue && tb.ContextMenu.Items.Count == 0) + { + AddNoItemsAvailToContextMenu(tb); + } + } + + private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var tb = d as TextBoxBase; + if (null == tb) + { + throw new InvalidOperationException("The property 'ExtraContextMenuItemsChanged' may only be set on TextBoxBase elements."); + } + else + { + tb.SetValue(ExtraContextMenuItemsProperty, e.NewValue); + tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); + AddExtraItemsToContextMenu(tb, tb.ContextMenu.Items.Count > 0); + if (tb.ContextMenu.Items.Count == 0) + { + AddNoItemsAvailToContextMenu(tb); + } + } + } + private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEventArgs e) { var tbBase = (TextBoxBase)sender; var textBox = tbBase as TextBox; var richTextBox = tbBase as RichTextBox; - tbBase.ContextMenu = GetDefaultTextBoxBaseContextMenu(); + tbBase.ContextMenu = GetDefaultTextBoxBaseContextMenu(tbBase); var cmdIndex = 0; var spellingError = textBox != null @@ -301,23 +342,60 @@ private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEven var separatorMenuItem2 = new Separator(); tbBase.ContextMenu.Items.Insert(cmdIndex, separatorMenuItem2); } + AddExtraItemsToContextMenu(tbBase, true); + if (tbBase.ContextMenu.Items.Count == 0) + { + AddNoItemsAvailToContextMenu(tbBase); + } + } + + private static void AddExtraItemsToContextMenu(TextBoxBase tbBase, bool shouldAddSeparator = false) + { + List extraMenuItems = (List)tbBase.GetValue(ExtraContextMenuItemsProperty); + if (extraMenuItems != null && extraMenuItems.Count > 0) + { + // Add separator if necessary, then extra items to menu + if (shouldAddSeparator) + { + var separatorMenuItem = new Separator(); + tbBase.ContextMenu.Items.Add(separatorMenuItem); + } + foreach (MenuItem item in extraMenuItems) + { + item.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + tbBase.ContextMenu.Items.Add(item); + } + } + } + + private static void AddNoItemsAvailToContextMenu(TextBoxBase tbBase) + { + var mi = new MenuItem(); + mi.Header = "No menu items available"; + mi.FontStyle = FontStyles.Italic; + mi.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + tbBase.ContextMenu.Items.Add(mi); } // Gets a fresh context menu. - private static ContextMenu GetDefaultTextBoxBaseContextMenu() + private static ContextMenu GetDefaultTextBoxBaseContextMenu(TextBoxBase textBox) { var defaultMenu = new ContextMenu(); - var m1 = new MenuItem { Command = ApplicationCommands.Cut }; - m1.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); - var m2 = new MenuItem { Command = ApplicationCommands.Copy }; - m2.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); - var m3 = new MenuItem { Command = ApplicationCommands.Paste }; - m3.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); - - defaultMenu.Items.Add(m1); - defaultMenu.Items.Add(m2); - defaultMenu.Items.Add(m3); + bool shouldAddCutCopyPaste = (bool)textBox.GetValue(IsCutCopyPasteInContextMenuProperty); + if (shouldAddCutCopyPaste) + { + var m1 = new MenuItem { Command = ApplicationCommands.Cut }; + m1.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + var m2 = new MenuItem { Command = ApplicationCommands.Copy }; + m2.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + var m3 = new MenuItem { Command = ApplicationCommands.Paste }; + m3.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + + defaultMenu.Items.Add(m1); + defaultMenu.Items.Add(m2); + defaultMenu.Items.Add(m3); + } return defaultMenu; } @@ -702,6 +780,28 @@ public static void SetButtonFontSize(DependencyObject obj, double value) obj.SetValue(ButtonFontSizeProperty, value); } + [Category(AppName.MahApps)] + public static bool GetIsCutCopyPasteInContextMenu(DependencyObject d) + { + return (bool)d.GetValue(IsCutCopyPasteInContextMenuProperty); + } + + public static void SetIsCutCopyPasteInContextMenu(DependencyObject obj, bool value) + { + obj.SetValue(IsCutCopyPasteInContextMenuProperty, value); + } + + [Category(AppName.MahApps)] + public static List GetExtraContextMenuItems(DependencyObject d) + { + return (List)d.GetValue(ExtraContextMenuItemsProperty); + } + + public static void SetExtraContextMenuItems(DependencyObject obj, List value) + { + obj.SetValue(ExtraContextMenuItemsProperty, value); + } + private static void IsClearTextButtonBehaviorEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var button = d as Button; From 85daeaea5e74dc6b59ec43d9622a55a0b2fd2e5b Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Wed, 7 Dec 2016 09:54:38 -0500 Subject: [PATCH 2/7] Remove menu that showed up when no items were available --- .../Controls/Helper/TextBoxHelper.cs | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs index 97cbbc7005..2d66577964 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs @@ -274,10 +274,7 @@ private static void IsCutCopyPasteInContextMenuChanged(DependencyObject d, Depen tb.SetValue(IsCutCopyPasteInContextMenuProperty, e.NewValue); tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); AddExtraItemsToContextMenu(tb, tb.ContextMenu.Items.Count > 0); - if (!(bool)e.NewValue && tb.ContextMenu.Items.Count == 0) - { - AddNoItemsAvailToContextMenu(tb); - } + tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) @@ -292,10 +289,7 @@ private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyP tb.SetValue(ExtraContextMenuItemsProperty, e.NewValue); tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); AddExtraItemsToContextMenu(tb, tb.ContextMenu.Items.Count > 0); - if (tb.ContextMenu.Items.Count == 0) - { - AddNoItemsAvailToContextMenu(tb); - } + tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } } @@ -343,10 +337,7 @@ private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEven tbBase.ContextMenu.Items.Insert(cmdIndex, separatorMenuItem2); } AddExtraItemsToContextMenu(tbBase, true); - if (tbBase.ContextMenu.Items.Count == 0) - { - AddNoItemsAvailToContextMenu(tbBase); - } + tbBase.ContextMenu.Visibility = tbBase.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } private static void AddExtraItemsToContextMenu(TextBoxBase tbBase, bool shouldAddSeparator = false) @@ -368,15 +359,6 @@ private static void AddExtraItemsToContextMenu(TextBoxBase tbBase, bool shouldAd } } - private static void AddNoItemsAvailToContextMenu(TextBoxBase tbBase) - { - var mi = new MenuItem(); - mi.Header = "No menu items available"; - mi.FontStyle = FontStyles.Italic; - mi.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); - tbBase.ContextMenu.Items.Add(mi); - } - // Gets a fresh context menu. private static ContextMenu GetDefaultTextBoxBaseContextMenu(TextBoxBase textBox) { From 7f51bff5bba186dc8aad79d6eb99a8329af96cfb Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Wed, 7 Dec 2016 11:14:25 -0500 Subject: [PATCH 3/7] Don't force separator usage in context menu --- .../MainWindowViewModel.cs | 7 +++--- .../Controls/Helper/TextBoxHelper.cs | 25 ++++++++----------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs index b1f65af850..a6f15dc96c 100644 --- a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs +++ b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs @@ -220,17 +220,18 @@ public ICommand TextBoxButtonCmdWithParameter } } - private List extraMenuItems; + private List extraMenuItems; - public List ExtraMenuItems + public List ExtraMenuItems { get { if (extraMenuItems != null) return extraMenuItems; - extraMenuItems = new List() + extraMenuItems = new List() { new MenuItem() { Header = "Sample Custom Menu Item" }, + new Separator(), new MenuItem() { Header = "Another Sample Item" }, }; return extraMenuItems; diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs index 2d66577964..bf183539fa 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs @@ -57,7 +57,7 @@ public class TextBoxHelper public static readonly DependencyProperty IsSpellCheckContextMenuEnabledProperty = DependencyProperty.RegisterAttached("IsSpellCheckContextMenuEnabled", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(false, UseSpellCheckContextMenuChanged)); public static readonly DependencyProperty IsCutCopyPasteInContextMenuProperty = DependencyProperty.RegisterAttached("IsCutCopyPasteInContextMenu", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(true, IsCutCopyPasteInContextMenuChanged)); - public static readonly DependencyProperty ExtraContextMenuItemsProperty = DependencyProperty.RegisterAttached("ExtraContextMenuItems", typeof(List), typeof(TextBoxHelper), new FrameworkPropertyMetadata(null, ExtraContextMenuItemsChanged)); + public static readonly DependencyProperty ExtraContextMenuItemsProperty = DependencyProperty.RegisterAttached("ExtraContextMenuItems", typeof(List), typeof(TextBoxHelper), new FrameworkPropertyMetadata(null, ExtraContextMenuItemsChanged)); /// /// This property can be used to retrieve the watermark using the of bound property. @@ -273,7 +273,7 @@ private static void IsCutCopyPasteInContextMenuChanged(DependencyObject d, Depen tb.SetValue(IsCutCopyPasteInContextMenuProperty, e.NewValue); tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); - AddExtraItemsToContextMenu(tb, tb.ContextMenu.Items.Count > 0); + AddExtraItemsToContextMenu(tb); tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } @@ -288,7 +288,7 @@ private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyP { tb.SetValue(ExtraContextMenuItemsProperty, e.NewValue); tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); - AddExtraItemsToContextMenu(tb, tb.ContextMenu.Items.Count > 0); + AddExtraItemsToContextMenu(tb); tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } } @@ -336,24 +336,21 @@ private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEven var separatorMenuItem2 = new Separator(); tbBase.ContextMenu.Items.Insert(cmdIndex, separatorMenuItem2); } - AddExtraItemsToContextMenu(tbBase, true); + AddExtraItemsToContextMenu(tbBase); tbBase.ContextMenu.Visibility = tbBase.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } - private static void AddExtraItemsToContextMenu(TextBoxBase tbBase, bool shouldAddSeparator = false) + private static void AddExtraItemsToContextMenu(TextBoxBase tbBase) { - List extraMenuItems = (List)tbBase.GetValue(ExtraContextMenuItemsProperty); + var extraMenuItems = (List)tbBase.GetValue(ExtraContextMenuItemsProperty); if (extraMenuItems != null && extraMenuItems.Count > 0) { - // Add separator if necessary, then extra items to menu - if (shouldAddSeparator) + foreach (FrameworkElement item in extraMenuItems) { - var separatorMenuItem = new Separator(); - tbBase.ContextMenu.Items.Add(separatorMenuItem); - } - foreach (MenuItem item in extraMenuItems) - { - item.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + if (item is MenuItem) + { + item.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); + } tbBase.ContextMenu.Items.Add(item); } } From d72c609159307dee4afebb2c89ee9928412f70ec Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Wed, 7 Dec 2016 11:59:41 -0500 Subject: [PATCH 4/7] Fix bug where spellcheck + extra menu items caused crash due to items existing in old menu --- .../MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml | 1 + .../MahApps.Metro.Demo.Shared/MainWindowViewModel.cs | 3 +++ .../MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml index 3143c7ddf1..596e367c30 100644 --- a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml +++ b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml @@ -100,6 +100,7 @@ Text="Select all on focus" /> ExtraMenuItems { if (extraMenuItems != null) return extraMenuItems; + var submenu = new MenuItem() { Header = "Submenu" }; + submenu.Items.Add(new MenuItem() { Header = "Sample inside submenu" }); extraMenuItems = new List() { new MenuItem() { Header = "Sample Custom Menu Item" }, new Separator(), new MenuItem() { Header = "Another Sample Item" }, + submenu }; return extraMenuItems; } diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs index bf183539fa..00f9b0da75 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs @@ -351,6 +351,11 @@ private static void AddExtraItemsToContextMenu(TextBoxBase tbBase) { item.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); } + if (item.Parent != null && item.Parent is ContextMenu && item.Parent != tbBase.ContextMenu) + { + var parent = item.Parent as ContextMenu; + parent.Items.Remove(item); + } tbBase.ContextMenu.Items.Add(item); } } From f455008212aaf83857bb39910d33cdbbf8dde69f Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Wed, 7 Dec 2016 13:31:24 -0500 Subject: [PATCH 5/7] Make Get & Set for ExtraMenuItems use right List type --- .../MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs index 00f9b0da75..fd5b79b1d2 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs @@ -776,12 +776,12 @@ public static void SetIsCutCopyPasteInContextMenu(DependencyObject obj, bool val } [Category(AppName.MahApps)] - public static List GetExtraContextMenuItems(DependencyObject d) + public static List GetExtraContextMenuItems(DependencyObject d) { - return (List)d.GetValue(ExtraContextMenuItemsProperty); + return (List)d.GetValue(ExtraContextMenuItemsProperty); } - public static void SetExtraContextMenuItems(DependencyObject obj, List value) + public static void SetExtraContextMenuItems(DependencyObject obj, List value) { obj.SetValue(ExtraContextMenuItemsProperty, value); } From 616dd7f79c077fce8ca0025fbfc0a3686136985c Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Thu, 8 Dec 2016 09:33:50 -0500 Subject: [PATCH 6/7] Remove unnecessary property setting and rename property --- .../ExampleViews/TextExamples.xaml | 2 +- .../Controls/Helper/TextBoxHelper.cs | 22 ++++++------ .../Styles/Controls.DataGrid.xaml | 35 ++++++++----------- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml index 596e367c30..323d6f894e 100644 --- a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml +++ b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml @@ -101,7 +101,7 @@ ), typeof(TextBoxHelper), new FrameworkPropertyMetadata(null, ExtraContextMenuItemsChanged)); /// @@ -263,15 +263,14 @@ private static void UseSpellCheckContextMenuChanged(DependencyObject d, Dependen } } - private static void IsCutCopyPasteInContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void ExcludeDefaultContextMenuItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var tb = d as TextBoxBase; if (null == tb) { - throw new InvalidOperationException("The property 'IsCutCopyPasteInContextMenuChanged' may only be set on TextBoxBase elements."); + throw new InvalidOperationException("The property 'ExcludeDefaultContextMenuItems' may only be set on TextBoxBase elements."); } - tb.SetValue(IsCutCopyPasteInContextMenuProperty, e.NewValue); tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); AddExtraItemsToContextMenu(tb); tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; @@ -282,11 +281,10 @@ private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyP var tb = d as TextBoxBase; if (null == tb) { - throw new InvalidOperationException("The property 'ExtraContextMenuItemsChanged' may only be set on TextBoxBase elements."); + throw new InvalidOperationException("The property 'ExtraContextMenuItems' may only be set on TextBoxBase elements."); } else { - tb.SetValue(ExtraContextMenuItemsProperty, e.NewValue); tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); AddExtraItemsToContextMenu(tb); tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; @@ -366,8 +364,8 @@ private static ContextMenu GetDefaultTextBoxBaseContextMenu(TextBoxBase textBox) { var defaultMenu = new ContextMenu(); - bool shouldAddCutCopyPaste = (bool)textBox.GetValue(IsCutCopyPasteInContextMenuProperty); - if (shouldAddCutCopyPaste) + bool shouldExcludeDefaultItems = (bool)textBox.GetValue(ExcludeDefaultContextMenuItemsProperty); + if (!shouldExcludeDefaultItems) { var m1 = new MenuItem { Command = ApplicationCommands.Cut }; m1.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem"); @@ -765,14 +763,14 @@ public static void SetButtonFontSize(DependencyObject obj, double value) } [Category(AppName.MahApps)] - public static bool GetIsCutCopyPasteInContextMenu(DependencyObject d) + public static bool GetExcludeDefaultContextMenuItems(DependencyObject d) { - return (bool)d.GetValue(IsCutCopyPasteInContextMenuProperty); + return (bool)d.GetValue(ExcludeDefaultContextMenuItemsProperty); } - public static void SetIsCutCopyPasteInContextMenu(DependencyObject obj, bool value) + public static void SetExcludeDefaultContextMenuItems(DependencyObject obj, bool value) { - obj.SetValue(IsCutCopyPasteInContextMenuProperty, value); + obj.SetValue(ExcludeDefaultContextMenuItemsProperty, value); } [Category(AppName.MahApps)] diff --git a/src/MahApps.Metro/MahApps.Metro/Styles/Controls.DataGrid.xaml b/src/MahApps.Metro/MahApps.Metro/Styles/Controls.DataGrid.xaml index 2869ffb3b0..9a2e5602fc 100644 --- a/src/MahApps.Metro/MahApps.Metro/Styles/Controls.DataGrid.xaml +++ b/src/MahApps.Metro/MahApps.Metro/Styles/Controls.DataGrid.xaml @@ -26,13 +26,8 @@ - - - - - + + - - - + @@ -76,14 +72,15 @@ + - - - + @@ -143,14 +140,12 @@ @@ -212,12 +207,10 @@ From 10da6bdafc8f0ae38bc58d961b74a2d2058cbcbd Mon Sep 17 00:00:00 2001 From: Deadpikle Date: Tue, 13 Dec 2016 12:52:09 -0500 Subject: [PATCH 7/7] Refactor all ContextMenu code to 1 func Only add ContextMenuOpening event if not already added --- docs/release-notes/1.4.0.md | 1 + .../MahApps.Metro.Shared/Controls/FlipView.cs | 6 -- .../Controls/Helper/TextBoxHelper.cs | 67 +++++++++++-------- .../Styles/Controls.DatePicker.xaml | 1 + .../MahApps.Metro/Themes/DateTimePicker.xaml | 1 + 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/docs/release-notes/1.4.0.md b/docs/release-notes/1.4.0.md index 8d3b96a2db..f0dacfe387 100644 --- a/docs/release-notes/1.4.0.md +++ b/docs/release-notes/1.4.0.md @@ -70,3 +70,4 @@ - [#2687](https://github.com/MahApps/MahApps.Metro/issues/2687) Implement SecureStrng into LoginDialogData and ShowLoginDialog - [#2756](https://github.com/MahApps/MahApps.Metro/issues/2756) Flyout Position top element focus inhibited by title bar - [#2755](https://github.com/MahApps/MahApps.Metro/issues/2755) MetroAnimatedTabControl first tab font not changing +- [#2760](https://github.com/MahApps/MahApps.Metro/issues/2760) DatePicker SelectionBackground doesn't match accent color diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/FlipView.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/FlipView.cs index becbf28caa..353c201feb 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/FlipView.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/FlipView.cs @@ -349,12 +349,6 @@ public override void OnApplyTemplate() this.bannerLabel.Opacity = this.IsBannerEnabled ? 1.0 : 0.0; } - protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue) - { - base.OnItemsSourceChanged(oldValue, newValue); - this.SelectedIndex = 0; - } - protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { base.OnItemsChanged(e); diff --git a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs index 8dd2ca9c7f..68f70a4d15 100644 --- a/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs +++ b/src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs @@ -58,6 +58,7 @@ public class TextBoxHelper public static readonly DependencyProperty IsSpellCheckContextMenuEnabledProperty = DependencyProperty.RegisterAttached("IsSpellCheckContextMenuEnabled", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(false, UseSpellCheckContextMenuChanged)); public static readonly DependencyProperty ExcludeDefaultContextMenuItemsProperty = DependencyProperty.RegisterAttached("ExcludeDefaultContextMenuItems", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(false, ExcludeDefaultContextMenuItemsChanged)); public static readonly DependencyProperty ExtraContextMenuItemsProperty = DependencyProperty.RegisterAttached("ExtraContextMenuItems", typeof(List), typeof(TextBoxHelper), new FrameworkPropertyMetadata(null, ExtraContextMenuItemsChanged)); + private static readonly DependencyProperty IsMonitoringMenuOpenProperty = DependencyProperty.RegisterAttached("IsMonitoringMenuOpen", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(false)); /// /// This property can be used to retrieve the watermark using the of bound property. @@ -247,19 +248,11 @@ private static void UseSpellCheckContextMenuChanged(DependencyObject d, Dependen { throw new InvalidOperationException("The property 'IsSpellCheckContextMenuEnabled' may only be set on TextBoxBase elements."); } - - if ((bool)e.NewValue) { - // set the spell check to true - tb.SetValue(SpellCheck.IsEnabledProperty, true); - // override pre defined context menu - tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); - tb.ContextMenuOpening += TextBoxBaseContextMenuOpening; - } - else + tb.SetValue(SpellCheck.IsEnabledProperty, e.NewValue); + if (!GetIsMonitoringMenuOpen(tb)) { - tb.SetValue(SpellCheck.IsEnabledProperty, false); - tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); - tb.ContextMenuOpening -= TextBoxBaseContextMenuOpening; + tb.ContextMenuOpening += TextBoxBaseContextMenuOpening; + SetIsMonitoringMenuOpen(tb, true); } } @@ -270,10 +263,11 @@ private static void ExcludeDefaultContextMenuItemsChanged(DependencyObject d, De { throw new InvalidOperationException("The property 'ExcludeDefaultContextMenuItems' may only be set on TextBoxBase elements."); } - - tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); - AddExtraItemsToContextMenu(tb); - tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; + if (!GetIsMonitoringMenuOpen(tb)) + { + tb.ContextMenuOpening += TextBoxBaseContextMenuOpening; + SetIsMonitoringMenuOpen(tb, true); + } } private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) @@ -283,17 +277,21 @@ private static void ExtraContextMenuItemsChanged(DependencyObject d, DependencyP { throw new InvalidOperationException("The property 'ExtraContextMenuItems' may only be set on TextBoxBase elements."); } - else + if (!GetIsMonitoringMenuOpen(tb)) { - tb.ContextMenu = GetDefaultTextBoxBaseContextMenu(tb); - AddExtraItemsToContextMenu(tb); - tb.ContextMenu.Visibility = tb.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; + tb.ContextMenuOpening += TextBoxBaseContextMenuOpening; + SetIsMonitoringMenuOpen(tb, true); } } private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEventArgs e) { var tbBase = (TextBoxBase)sender; + SetupContextMenu(tbBase); + } + + private static void SetupContextMenu(TextBoxBase tbBase) + { var textBox = tbBase as TextBox; var richTextBox = tbBase as RichTextBox; @@ -305,10 +303,13 @@ private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEven : (richTextBox != null ? richTextBox.GetSpellingError(richTextBox.CaretPosition) : null); - if (spellingError != null) { + if (spellingError != null) + { var suggestions = spellingError.Suggestions; - if (suggestions.Any()) { - foreach (var suggestion in suggestions) { + if (suggestions.Any()) + { + foreach (var suggestion in suggestions) + { var mi = new MenuItem(); mi.Header = suggestion; mi.FontWeight = FontWeights.Bold; @@ -334,12 +335,7 @@ private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEven var separatorMenuItem2 = new Separator(); tbBase.ContextMenu.Items.Insert(cmdIndex, separatorMenuItem2); } - AddExtraItemsToContextMenu(tbBase); - tbBase.ContextMenu.Visibility = tbBase.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; - } - - private static void AddExtraItemsToContextMenu(TextBoxBase tbBase) - { + // Add extra menu items var extraMenuItems = (List)tbBase.GetValue(ExtraContextMenuItemsProperty); if (extraMenuItems != null && extraMenuItems.Count > 0) { @@ -357,6 +353,8 @@ private static void AddExtraItemsToContextMenu(TextBoxBase tbBase) tbBase.ContextMenu.Items.Add(item); } } + // If nothing was ever added, hide the context menu + tbBase.ContextMenu.Visibility = tbBase.ContextMenu.Items.Count > 0 ? Visibility.Visible : Visibility.Hidden; } // Gets a fresh context menu. @@ -784,6 +782,17 @@ public static void SetExtraContextMenuItems(DependencyObject obj, List diff --git a/src/MahApps.Metro/MahApps.Metro/Themes/DateTimePicker.xaml b/src/MahApps.Metro/MahApps.Metro/Themes/DateTimePicker.xaml index 6fb73d8422..c3e1973c6d 100644 --- a/src/MahApps.Metro/MahApps.Metro/Themes/DateTimePicker.xaml +++ b/src/MahApps.Metro/MahApps.Metro/Themes/DateTimePicker.xaml @@ -154,6 +154,7 @@ FontSize="{TemplateBinding FontSize}" controls:TextBoxHelper.Watermark="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(controls:TextBoxHelper.Watermark), Mode=OneWay}" CaretBrush="{DynamicResource BlackBrush}" + SelectionBrush="{DynamicResource HighlightBrush}" ContextMenu="{DynamicResource TextBoxMetroContextMenu}" Focusable="{TemplateBinding Focusable}">