From d5f87a5a0efaff2baee18619ecdeea0512a8f1ad Mon Sep 17 00:00:00 2001 From: Brian Lagunas Date: Mon, 10 Apr 2023 18:05:53 -0600 Subject: [PATCH 1/2] fixed #107 --- Test/UnitTests/EventTriggerTests.cs | 6 +- Test/UnitTests/KeyTriggerTest.cs | 181 ++++++++++++++++++ Test/UnitTests/UnitTests.csproj | 1 + .../EventTriggerBase.cs | 6 +- .../Input/KeyTrigger.cs | 4 + 5 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 Test/UnitTests/KeyTriggerTest.cs diff --git a/Test/UnitTests/EventTriggerTests.cs b/Test/UnitTests/EventTriggerTests.cs index 369e6ec..c021233 100644 --- a/Test/UnitTests/EventTriggerTests.cs +++ b/Test/UnitTests/EventTriggerTests.cs @@ -16,9 +16,9 @@ public class EventTriggerTest [TestInitialize] public void Setup() - { - Interaction.ShouldRunInDesignMode = true; - } + { + Interaction.ShouldRunInDesignMode = true; + } [TestCleanup] public void Teardown() diff --git a/Test/UnitTests/KeyTriggerTest.cs b/Test/UnitTests/KeyTriggerTest.cs new file mode 100644 index 0000000..d754912 --- /dev/null +++ b/Test/UnitTests/KeyTriggerTest.cs @@ -0,0 +1,181 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.Xaml.Behaviors; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows; +using Microsoft.Xaml.Behaviors.Input; +using System.Windows.Interop; +using System; + +namespace Microsoft.Xaml.Interactions.UnitTests +{ + [TestClass] + public class KeyTriggerTest + { + #region Setup/teardown + + [TestInitialize] + public void Setup() + { + Interaction.ShouldRunInDesignMode = true; + } + + [TestCleanup] + public void Teardown() + { + Interaction.ShouldRunInDesignMode = false; + } + + #endregion + + #region Test methods + + [TestMethod] + [DataRow(Key.A)] + [DataRow(Key.B)] + [DataRow(Key.C)] + [DataRow(Key.D)] + [DataRow(Key.E)] + [DataRow(Key.F)] + [DataRow(Key.G)] + [DataRow(Key.H)] + [DataRow(Key.I)] + [DataRow(Key.J)] + [DataRow(Key.K)] + [DataRow(Key.L)] + [DataRow(Key.M)] + [DataRow(Key.N)] + [DataRow(Key.O)] + [DataRow(Key.P)] + [DataRow(Key.Q)] + [DataRow(Key.R)] + [DataRow(Key.S)] + [DataRow(Key.T)] + [DataRow(Key.U)] + [DataRow(Key.V)] + [DataRow(Key.W)] + [DataRow(Key.X)] + [DataRow(Key.Y)] + [DataRow(Key.Z)] + [DataRow(Key.NumPad1)] + [DataRow(Key.NumPad2)] + [DataRow(Key.NumPad3)] + [DataRow(Key.NumPad4)] + [DataRow(Key.NumPad5)] + [DataRow(Key.NumPad6)] + [DataRow(Key.NumPad7)] + [DataRow(Key.NumPad8)] + [DataRow(Key.NumPad9)] + [DataRow(Key.Enter)] + [DataRow(Key.Tab)] + public void KeyTrigger_InvokesActions_WhenKeyIsPressed(Key key) + { + var textBox = new TextBox(); + var keyTrigger = new KeyTrigger { Key = key }; + var action = new StubAction(); + keyTrigger.Actions.Add(action); + keyTrigger.Attach(textBox); + + Grid grid = new Grid(); + grid.Children.Add(textBox); + using (StubWindow window = new StubWindow(grid)) + { + var inputSource = PresentationSource.FromVisual(textBox) ?? new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero); + var keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, inputSource, 0, key); + keyEventArgs.RoutedEvent = Keyboard.KeyDownEvent; + textBox.RaiseEvent(keyEventArgs); + + Assert.AreEqual(1, action.InvokeCount); + } + } + + [TestMethod] + [DataRow(Key.A)] + [DataRow(Key.B)] + [DataRow(Key.C)] + [DataRow(Key.D)] + [DataRow(Key.E)] + [DataRow(Key.F)] + [DataRow(Key.G)] + [DataRow(Key.H)] + [DataRow(Key.I)] + [DataRow(Key.J)] + [DataRow(Key.K)] + [DataRow(Key.L)] + [DataRow(Key.M)] + [DataRow(Key.N)] + [DataRow(Key.O)] + [DataRow(Key.P)] + [DataRow(Key.Q)] + [DataRow(Key.R)] + [DataRow(Key.S)] + [DataRow(Key.T)] + [DataRow(Key.U)] + [DataRow(Key.V)] + [DataRow(Key.W)] + [DataRow(Key.X)] + [DataRow(Key.Y)] + [DataRow(Key.Z)] + [DataRow(Key.NumPad1)] + [DataRow(Key.NumPad2)] + [DataRow(Key.NumPad3)] + [DataRow(Key.NumPad4)] + [DataRow(Key.NumPad5)] + [DataRow(Key.NumPad6)] + [DataRow(Key.NumPad7)] + [DataRow(Key.NumPad8)] + [DataRow(Key.NumPad9)] + [DataRow(Key.Enter)] + [DataRow(Key.Tab)] + public void KeyTrigger_InvokesActions_WhenKeyIsReleased(Key key) + { + var textBox = new TextBox(); + var keyTrigger = new KeyTrigger { Key = key, FiredOn = KeyTriggerFiredOn.KeyUp }; + var action = new StubAction(); + keyTrigger.Actions.Add(action); + keyTrigger.Attach(textBox); + + Grid grid = new Grid(); + grid.Children.Add(textBox); + using (StubWindow window = new StubWindow(grid)) + { + var inputSource = PresentationSource.FromVisual(textBox) ?? new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero); + var keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, inputSource, 0, key); + keyEventArgs.RoutedEvent = Keyboard.KeyUpEvent; + textBox.RaiseEvent(keyEventArgs); + + Assert.AreEqual(1, action.InvokeCount); + } + } + + + [TestMethod] + [DataRow(true)] + [DataRow(false)] + public void KeyTrigger_InvokesActionsOnce_WhenLoadedEventFiredMultipleTimes(bool activeOnFocus) + { + var textBox = new TextBox(); + var keyTrigger = new KeyTrigger { ActiveOnFocus = activeOnFocus, Key = Key.Enter }; + var action = new StubAction(); + keyTrigger.Actions.Add(action); + keyTrigger.Attach(textBox); + + Grid grid = new Grid(); + grid.Children.Add(textBox); + using (StubWindow window = new StubWindow(grid)) + { + //simulate the loaded event being invoked multiple times; for example, when using an element in a tab control + textBox.RaiseEvent(new RoutedEventArgs(FrameworkElement.LoadedEvent)); + + var inputSource = PresentationSource.FromVisual(textBox) ?? new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero); + var keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, inputSource, 0, Key.Enter); + keyEventArgs.RoutedEvent = Keyboard.KeyDownEvent; + textBox.RaiseEvent(keyEventArgs); + + Assert.AreEqual(1, action.InvokeCount); + } + } + + #endregion + } +} diff --git a/Test/UnitTests/UnitTests.csproj b/Test/UnitTests/UnitTests.csproj index 5fadbaa..d7a5861 100644 --- a/Test/UnitTests/UnitTests.csproj +++ b/Test/UnitTests/UnitTests.csproj @@ -9,6 +9,7 @@ + 3.0.2 diff --git a/src/Microsoft.Xaml.Behaviors/EventTriggerBase.cs b/src/Microsoft.Xaml.Behaviors/EventTriggerBase.cs index d62cad0..bfeff3a 100644 --- a/src/Microsoft.Xaml.Behaviors/EventTriggerBase.cs +++ b/src/Microsoft.Xaml.Behaviors/EventTriggerBase.cs @@ -408,7 +408,11 @@ private void RegisterLoaded(FrameworkElement associatedElement) } } - private void UnregisterLoaded(FrameworkElement associatedElement) + /// + /// Removes the event handler from the Loaded event of the associated object. + /// + /// The associated object + protected void UnregisterLoaded(FrameworkElement associatedElement) { Debug.Assert(this.eventHandlerMethodInfo == null); if (this.IsLoadedRegistered && associatedElement != null) diff --git a/src/Microsoft.Xaml.Behaviors/Input/KeyTrigger.cs b/src/Microsoft.Xaml.Behaviors/Input/KeyTrigger.cs index 1ddf228..aece7b3 100644 --- a/src/Microsoft.Xaml.Behaviors/Input/KeyTrigger.cs +++ b/src/Microsoft.Xaml.Behaviors/Input/KeyTrigger.cs @@ -117,6 +117,10 @@ protected override void OnEvent(EventArgs eventArgs) { this.targetElement.KeyUp += this.OnKeyPress; } + + // Unregister the Loaded event of the Source object to prevent the KeyUp or KeyDown events from being registered multiple times. + // this is especially important when the KeyTrigger is used in a TabControl/TabItem. + UnregisterLoaded(Source as FrameworkElement); } protected override void OnDetaching() From c587370c3eb78f2994291d7ae25d01c1fcfc9527 Mon Sep 17 00:00:00 2001 From: Brian Lagunas Date: Mon, 10 Apr 2023 18:12:18 -0600 Subject: [PATCH 2/2] removed unused Moq nuget package --- Test/UnitTests/UnitTests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/Test/UnitTests/UnitTests.csproj b/Test/UnitTests/UnitTests.csproj index d7a5861..5fadbaa 100644 --- a/Test/UnitTests/UnitTests.csproj +++ b/Test/UnitTests/UnitTests.csproj @@ -9,7 +9,6 @@ - 3.0.2