Skip to content

Commit

Permalink
fixes #3654 set IsTabStop in to False in the default NumericUpDown co…
Browse files Browse the repository at this point in the history
…ntrol

focus PART_TextBox of NumericUpDown control if it gets focus and enable moving focus with tab (and shift+tab) #3654. Also removed the IsTapStop on the Template because that is not longer needed

renamed variable (copy paste mistake)

Applying code suggestions
31659b
  • Loading branch information
Keboo committed Jan 3, 2025
1 parent d065de9 commit 528695c
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 7 deletions.
56 changes: 51 additions & 5 deletions src/MaterialDesignThemes.Wpf/UpDownBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using System.Globalization;

namespace MaterialDesignThemes.Wpf;
Expand Down Expand Up @@ -191,9 +191,7 @@ public override void OnApplyTemplate()
if (_textBoxField != null)
_textBoxField.TextChanged -= OnTextBoxFocusLost;

_increaseButton = GetTemplateChild(IncreaseButtonPartName) as RepeatButton;
_decreaseButton = GetTemplateChild(DecreaseButtonPartName) as RepeatButton;
_textBoxField = GetTemplateChild(TextBoxPartName) as TextBox;
base.OnApplyTemplate();

if (_increaseButton != null)
_increaseButton.Click += IncreaseButtonOnClick;
Expand All @@ -207,7 +205,6 @@ public override void OnApplyTemplate()
_textBoxField.Text = Value?.ToString();
}

base.OnApplyTemplate();
}

private void OnTextBoxFocusLost(object sender, EventArgs e)
Expand Down Expand Up @@ -279,6 +276,55 @@ public class UpDownBase : Control
protected RepeatButton? _decreaseButton;
protected RepeatButton? _increaseButton;

static UpDownBase()
{
EventManager.RegisterClassHandler(typeof(UpDownBase), GotFocusEvent, new RoutedEventHandler(OnGotFocus));
}

// Based on work in MahApps
// https://github.com/MahApps/MahApps.Metro/blob/f7ba30586e9670f07c2f7b6553d129a9e32fc673/src/MahApps.Metro/Controls/NumericUpDown.cs#L966
private static void OnGotFocus(object sender, RoutedEventArgs e)
{
// When NumericUpDown gets logical focus, select the text inside us.
// If we're an editable NumericUpDown, forward focus to the TextBox element
if (!e.Handled)
{
var numericUpDown = (UpDownBase)sender;
if (numericUpDown.Focusable && e.OriginalSource == numericUpDown)
{
// MoveFocus takes a TraversalRequest as its argument.
var focusDirection = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift)
? FocusNavigationDirection.Previous
: FocusNavigationDirection.Next;

var request = new TraversalRequest(focusDirection);
// Gets the element with keyboard focus.
// And change the keyboard focus.
if (Keyboard.FocusedElement is UIElement elementWithFocus)
{
elementWithFocus.MoveFocus(request);
}
else
{
numericUpDown.Focus();
}

e.Handled = true;
}
}
}

public override void OnApplyTemplate()
{
_increaseButton = GetTemplateChild(IncreaseButtonPartName) as RepeatButton;
_decreaseButton = GetTemplateChild(DecreaseButtonPartName) as RepeatButton;
_textBoxField = GetTemplateChild(TextBoxPartName) as TextBox;

base.OnApplyTemplate();
}

public void SelectAll() => _textBoxField?.SelectAll();

public object? IncreaseContent
{
get => GetValue(IncreaseContentProperty);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace MaterialDesignThemes.UITests.WPF.UpDownControls;
using System.ComponentModel;

namespace MaterialDesignThemes.UITests.WPF.UpDownControls;

public class DecimalUpDownTests(ITestOutputHelper output) : TestBase(output)
{
Expand Down Expand Up @@ -115,4 +117,34 @@ public async Task MaxAndMinAssignments_CoerceValueToBeInRange()
Assert.Equal(3, await numericUpDown.GetMinimum());
Assert.Equal(3, await numericUpDown.GetMaximum());
}

[Fact]
[Description("Issue 3654")]
public async Task InternalTextBoxIsFocused_WhenGettingKeyboardFocus()
{
await using var recorder = new TestRecorder(App);

// Arrange
var stackPanel = await LoadXaml<StackPanel>("""
<StackPanel>
<TextBox />
<materialDesign:DecimalUpDown />
</StackPanel>
""");

var textBox = await stackPanel.GetElement<TextBox>("/TextBox");
var part_textBox = await stackPanel.GetElement<TextBox>("PART_TextBox");

// Act
await textBox.MoveKeyboardFocus();
await Task.Delay(50);
await textBox.SendInput(new KeyboardInput(Key.Tab));
await Task.Delay(50);

// Assert
Assert.False(await textBox.GetIsFocused());
Assert.True(await part_textBox.GetIsFocused());

recorder.Success();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace MaterialDesignThemes.UITests.WPF.UpDownControls;
using System.ComponentModel;

namespace MaterialDesignThemes.UITests.WPF.UpDownControls;


public class NumericUpDownTests(ITestOutputHelper output) : TestBase(output)
Expand Down Expand Up @@ -116,4 +118,34 @@ public async Task MaxAndMinAssignments_CoerceValueToBeInRange()
Assert.Equal(3, await numericUpDown.GetMinimum());
Assert.Equal(3, await numericUpDown.GetMaximum());
}

[Fact]
[Description("Issue 3654")]
public async Task InternalTextBoxIsFocused_WhenGettingKeyboardFocus()
{
await using var recorder = new TestRecorder(App);

// Arrange
var stackPanel = await LoadXaml<StackPanel>("""
<StackPanel>
<TextBox />
<materialDesign:NumericUpDown />
</StackPanel>
""");

var textBox = await stackPanel.GetElement<TextBox>("/TextBox");
var part_textBox = await stackPanel.GetElement<TextBox>("PART_TextBox");

// Act
await textBox.MoveKeyboardFocus();
await Task.Delay(50);
await textBox.SendInput(new KeyboardInput(Key.Tab));
await Task.Delay(50);

// Assert
Assert.False(await textBox.GetIsFocused());
Assert.True(await part_textBox.GetIsFocused());

recorder.Success();
}
}

0 comments on commit 528695c

Please sign in to comment.