From c72195f45b3cb68ac259dba472889827973295ca Mon Sep 17 00:00:00 2001 From: ahopper Date: Mon, 20 May 2019 15:15:30 +0100 Subject: [PATCH 1/4] Fix use of CoerceCaretIndex on Text change --- src/Avalonia.Controls/TextBox.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 04b088e35c..d43957313e 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -214,9 +214,9 @@ namespace Avalonia.Controls if (!_ignoreTextChanges) { var caretIndex = CaretIndex; - SelectionStart = CoerceCaretIndex(SelectionStart, value?.Length ?? 0); - SelectionEnd = CoerceCaretIndex(SelectionEnd, value?.Length ?? 0); - CaretIndex = CoerceCaretIndex(caretIndex, value?.Length ?? 0); + SelectionStart = CoerceCaretIndex(SelectionStart, value); + SelectionEnd = CoerceCaretIndex(SelectionEnd, value); + CaretIndex = CoerceCaretIndex(caretIndex, value); if (SetAndRaise(TextProperty, ref _text, value) && !_isUndoingRedoing) { @@ -677,11 +677,15 @@ namespace Avalonia.Controls } } - private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text?.Length ?? 0); + private int CoerceCaretIndex(int value) => CoerceCaretIndex(value, Text); - private int CoerceCaretIndex(int value, int length) + private int CoerceCaretIndex(int value, string text) { - var text = Text; + if (text == null) + { + return 0; + } + var length = text.Length; if (value < 0) { @@ -691,7 +695,7 @@ namespace Avalonia.Controls { return length; } - else if (value > 0 && text[value - 1] == '\r' && text[value] == '\n') + else if (value > 0 && text[value - 1] == '\r' && value < length && text[value] == '\n') { return value + 1; } From 8a9e997c6c9b4302c22ebee4cfe729453e83e231 Mon Sep 17 00:00:00 2001 From: ahopper Date: Tue, 21 May 2019 07:13:26 +0100 Subject: [PATCH 2/4] unit test added --- tests/Avalonia.Controls.UnitTests/TextBoxTests.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs index 0d87f6d0fe..9b62509138 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests.cs @@ -385,6 +385,21 @@ namespace Avalonia.Controls.UnitTests Assert.True(target.SelectionEnd <= "123".Length); } } + [Fact] + public void CoerceCaretIndex_Doesnt_Cause_Exception_with_malformed_line_ending() + { + using (UnitTestApplication.Start(Services)) + { + var target = new TextBox + { + Template = CreateTemplate(), + Text = "0123456789\r" + }; + target.CaretIndex = 11; + + Assert.True(true); + } + } private static TestServices Services => TestServices.MockThreadingInterface.With( standardCursorFactory: Mock.Of()); From 34358e0a2635258f0531f1c43496ac3b59295ae9 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 May 2019 20:18:24 +0100 Subject: [PATCH 3/4] dont raise gestures if the events were already handled. --- src/Avalonia.Input/Gestures.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Input/Gestures.cs b/src/Avalonia.Input/Gestures.cs index 8a514ca685..23b0ad466e 100644 --- a/src/Avalonia.Input/Gestures.cs +++ b/src/Avalonia.Input/Gestures.cs @@ -38,7 +38,10 @@ namespace Avalonia.Input } else if (s_lastPress?.IsAlive == true && e.ClickCount == 2 && s_lastPress.Target == e.Source) { - e.Source.RaiseEvent(new RoutedEventArgs(DoubleTappedEvent)); + if (!ev.Handled) + { + e.Source.RaiseEvent(new RoutedEventArgs(DoubleTappedEvent)); + } } } } @@ -51,7 +54,10 @@ namespace Avalonia.Input if (s_lastPress?.IsAlive == true && s_lastPress.Target == e.Source) { - ((IInteractive)s_lastPress.Target).RaiseEvent(new RoutedEventArgs(TappedEvent)); + if (!ev.Handled) + { + ((IInteractive)s_lastPress.Target).RaiseEvent(new RoutedEventArgs(TappedEvent)); + } } } } From 1fd30a91c3733c7264f3bb65fc89cf2b307259c8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 May 2019 20:31:54 +0100 Subject: [PATCH 4/4] add a unit test for gestures not being raised when parent handles event. --- .../GestureTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Avalonia.Interactivity.UnitTests/GestureTests.cs b/tests/Avalonia.Interactivity.UnitTests/GestureTests.cs index 931c1b5268..bebf7f9bc9 100644 --- a/tests/Avalonia.Interactivity.UnitTests/GestureTests.cs +++ b/tests/Avalonia.Interactivity.UnitTests/GestureTests.cs @@ -78,5 +78,36 @@ namespace Avalonia.Interactivity.UnitTests Assert.Equal(new[] { "bp", "dp", "br", "dr", "bt", "dt", "bp", "dp", "bdt", "ddt" }, result); } + + [Fact] + public void DoubleTapped_Should_Not_Be_Rasied_if_Pressed_is_Handled() + { + Border border = new Border(); + var decorator = new Decorator + { + Child = border + }; + var result = new List(); + + decorator.AddHandler(Border.PointerPressedEvent, (s, e) => + { + result.Add("dp"); + e.Handled = true; + }); + + decorator.AddHandler(Border.PointerReleasedEvent, (s, e) => result.Add("dr")); + decorator.AddHandler(Gestures.TappedEvent, (s, e) => result.Add("dt")); + decorator.AddHandler(Gestures.DoubleTappedEvent, (s, e) => result.Add("ddt")); + border.AddHandler(Border.PointerPressedEvent, (s, e) => result.Add("bp")); + border.AddHandler(Border.PointerReleasedEvent, (s, e) => result.Add("br")); + border.AddHandler(Gestures.TappedEvent, (s, e) => result.Add("bt")); + border.AddHandler(Gestures.DoubleTappedEvent, (s, e) => result.Add("bdt")); + + border.RaiseEvent(new PointerPressedEventArgs()); + border.RaiseEvent(new PointerReleasedEventArgs()); + border.RaiseEvent(new PointerPressedEventArgs { ClickCount = 2 }); + + Assert.Equal(new[] { "bp", "dp", "br", "dr", "bt", "dt", "bp", "dp" }, result); + } } }