Skip to content

Commit 7fa7510

Browse files
committed
add focus redirection
1 parent 8fb3ad6 commit 7fa7510

File tree

3 files changed

+49
-11
lines changed

3 files changed

+49
-11
lines changed

src/Avalonia.Base/Input/FocusChangingEventArgs.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ internal FocusChangingEventArgs(RoutedEvent routedEvent) : base(routedEvent)
1919
/// <summary>
2020
/// Gets or sets the element that focus has moved to.
2121
/// </summary>
22-
public IInputElement? NewFocus { get; init; }
22+
public IInputElement? NewFocusedElement { get; internal set; }
2323

2424
/// <summary>
2525
/// Gets or sets the element that previously had focus.
2626
/// </summary>
27-
public IInputElement? OldFocus { get; init; }
27+
public IInputElement? OldFocusedElement { get; init; }
2828

2929
/// <summary>
3030
/// Gets or sets a value indicating how the change in focus occurred.
@@ -41,17 +41,30 @@ internal FocusChangingEventArgs(RoutedEvent routedEvent) : base(routedEvent)
4141
/// </summary>
4242
public bool Cancelled { get; private set; }
4343

44-
internal bool IsCancellable { get; init; }
44+
internal bool CanCancelOrRedirectFocus { get; init; }
4545

4646
/// <summary>
4747
/// Attempts to cancel the current focus change
4848
/// </summary>
4949
/// <returns>true if focus change was cancelled; otherwise, false</returns>
5050
public bool TryCancel()
5151
{
52-
Cancelled = IsCancellable;
52+
Cancelled = CanCancelOrRedirectFocus;
5353

5454
return Cancelled;
5555
}
56+
57+
/// <summary>
58+
/// Attempts to redirect focus from the targeted element to the specified element.
59+
/// </summary>
60+
public bool TrySetNewFocusedElement(IInputElement? inputElement)
61+
{
62+
if(CanCancelOrRedirectFocus)
63+
{
64+
NewFocusedElement = inputElement;
65+
}
66+
67+
return inputElement == NewFocusedElement;
68+
}
5669
}
5770
}

src/Avalonia.Base/Input/KeyboardDevice.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,11 @@ public void SetFocusedElement(
151151

152152
var losingFocus = new FocusChangingEventArgs(InputElement.LosingFocusEvent)
153153
{
154-
OldFocus = FocusedElement,
155-
NewFocus = element,
154+
OldFocusedElement = FocusedElement,
155+
NewFocusedElement = element,
156156
NavigationMethod = method,
157157
KeyModifiers = keyModifiers,
158-
IsCancellable = isFocusChangeCancellable
158+
CanCancelOrRedirectFocus = isFocusChangeCancellable
159159
};
160160

161161
interactive?.RaiseEvent(losingFocus);
@@ -165,15 +165,15 @@ public void SetFocusedElement(
165165
changeFocus = false;
166166
}
167167

168-
if (changeFocus && element is Interactive newFocus)
168+
if (changeFocus && losingFocus.NewFocusedElement is Interactive newFocus)
169169
{
170170
var gettingFocus = new FocusChangingEventArgs(InputElement.GettingFocusEvent)
171171
{
172-
OldFocus = FocusedElement,
173-
NewFocus = element,
172+
OldFocusedElement = FocusedElement,
173+
NewFocusedElement = losingFocus.NewFocusedElement,
174174
NavigationMethod = method,
175175
KeyModifiers = keyModifiers,
176-
IsCancellable = isFocusChangeCancellable
176+
CanCancelOrRedirectFocus = isFocusChangeCancellable
177177
};
178178

179179
newFocus.RaiseEvent(gettingFocus);
@@ -182,6 +182,8 @@ public void SetFocusedElement(
182182
{
183183
changeFocus = false;
184184
}
185+
186+
element = gettingFocus.NewFocusedElement;
185187
}
186188

187189
if (changeFocus)

tests/Avalonia.Base.UnitTests/Input/KeyboardDeviceTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,5 +185,28 @@ public void Cancelled_Focus_Change_Should_Not_Send_Got_Focus_Event()
185185

186186
Assert.True(focusCancelled);
187187
}
188+
189+
[Fact]
190+
public void Redirected_Focus_Should_Change_Focused_Element()
191+
{
192+
var target = new KeyboardDevice();
193+
var first = new Control();
194+
var second = new Control();
195+
var stack = new StackPanel();
196+
stack.Children.AddRange(new[] { first, second });
197+
var root = new TestRoot(stack);
198+
199+
first.GettingFocus += (s, e) =>
200+
{
201+
e.TrySetNewFocusedElement(second);
202+
};
203+
204+
target.SetFocusedElement(
205+
first,
206+
NavigationMethod.Unspecified,
207+
KeyModifiers.None);
208+
209+
Assert.True(second.IsFocused);
210+
}
188211
}
189212
}

0 commit comments

Comments
 (0)