From f9fb8cb8ae6c73987178f0d9adc07ad561622814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=8A=BC?= Date: Wed, 20 Aug 2025 12:19:03 +0800 Subject: [PATCH] =?UTF-8?q?NumPad=20=E4=BF=AE=E5=A4=8D=E4=BA=86=20?= =?UTF-8?q?=E5=AE=98=E6=96=B9NumericUpDown=E5=AF=B9NumPad=E4=B8=8D?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E7=9A=84=E9=97=AE=E9=A2=98=20NumPad=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=20=E5=BD=93Target=E4=B8=8D=E6=98=AF?= =?UTF-8?q?TextBox=E7=9A=84=E6=97=B6=E5=80=99=EF=BC=8CNumPad=E4=B8=8A?= =?UTF-8?q?=E7=9A=84Delete=E5=92=8CBack=E4=B8=8D=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=20IPv4Box=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BA=86=20=E7=94=B1=E4=BA=8E=E5=A4=B1=E5=8E=BB=E7=84=A6?= =?UTF-8?q?=E7=82=B9=E6=89=80=E4=BB=A5=E5=AF=B9=20NumPad=20=E4=B8=8D?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/Ursa.Demo/Pages/NumPadDemo.axaml | 14 ++++- src/Ursa.Themes.Semi/Controls/NumPad.axaml | 12 ++++- src/Ursa/Controls/IPv4Box/IPv4Box.cs | 32 +++++++++++- src/Ursa/Controls/NumPad/NumPad.cs | 60 ++++++++++++++++++++-- 4 files changed, 110 insertions(+), 8 deletions(-) diff --git a/demo/Ursa.Demo/Pages/NumPadDemo.axaml b/demo/Ursa.Demo/Pages/NumPadDemo.axaml index dbd997a..2e657ec 100644 --- a/demo/Ursa.Demo/Pages/NumPadDemo.axaml +++ b/demo/Ursa.Demo/Pages/NumPadDemo.axaml @@ -21,11 +21,21 @@ HorizontalAlignment="Stretch" u:NumPad.Attach="True" Watermark="Invoke NumPad" /> - + + Watermark="Invoke u:NumericIntUpDown" /> + + + diff --git a/src/Ursa.Themes.Semi/Controls/NumPad.axaml b/src/Ursa.Themes.Semi/Controls/NumPad.axaml index e2aed73..372f7d3 100644 --- a/src/Ursa.Themes.Semi/Controls/NumPad.axaml +++ b/src/Ursa.Themes.Semi/Controls/NumPad.axaml @@ -92,7 +92,7 @@ + + /// ǷʹС + /// + internal bool IsTargetByNumPad + { + set + { + if(_isTargetByNumPad + &&!value) + { + SetLostFocus(); + } + _isTargetByNumPad =value; + } + get => _isTargetByNumPad; + } + private bool _isTargetByNumPad; + #region Overrides protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { @@ -308,6 +326,15 @@ public class IPv4Box: TemplatedControl protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); + if (IsTargetByNumPad) + { + return; + } + SetLostFocus(); + } + + private void SetLostFocus() + { foreach (var pre in _presenters) { pre?.HideCaret(); @@ -317,7 +344,8 @@ public class IPv4Box: TemplatedControl ParseBytes(ShowLeadingZero); SetIPAddressInternal(); } - + + protected override void OnGotFocus(GotFocusEventArgs e) { _currentActivePresenter = _firstText; diff --git a/src/Ursa/Controls/NumPad/NumPad.cs b/src/Ursa/Controls/NumPad/NumPad.cs index 3777dab..6f81bb7 100644 --- a/src/Ursa/Controls/NumPad/NumPad.cs +++ b/src/Ursa/Controls/NumPad/NumPad.cs @@ -1,6 +1,9 @@ using Avalonia; +using Avalonia.Controls; using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; using Avalonia.Input; +using Avalonia.LogicalTree; using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; @@ -16,6 +19,11 @@ public class NumPad: TemplatedControl set => SetValue(TargetProperty, value); } + /// + /// Target Ŀڲ TextBox TextPresenter ؼ + /// + private TextBox? _targetInnerText; + public static readonly StyledProperty NumModeProperty = AvaloniaProperty.Register( nameof(NumMode), defaultValue: true); @@ -54,10 +62,24 @@ public class NumPad: TemplatedControl var existing = OverlayDialog.Recall(null); if (existing is not null) { + if(existing.Target is IPv4Box pv4Box) + { + pv4Box.IsTargetByNumPad = false; // ȡ IPv4Box NumPad ģʽ + } existing.Target = sender as InputElement; + existing._targetInnerText = FindTextBoxInTarget((sender as InputElement)!); + + if (existing.Target is IPv4Box pv4Box2) + { + pv4Box2.IsTargetByNumPad = true; + } return; } - var numPad = new NumPad() { Target = sender as InputElement }; + var numPad = new NumPad() + { + Target = sender as InputElement , + _targetInnerText = FindTextBoxInTarget((sender as InputElement)!) + }; OverlayDialog.Show(numPad, new object(), options: new OverlayDialogOptions() { Buttons = DialogButton.None }); } @@ -84,9 +106,12 @@ public class NumPad: TemplatedControl { if (Target is null || o is not NumPadButton b) return; var key = (b.NumMode ? b.NumKey : b.FunctionKey)?? Key.None; + + // ڲΪ TextBox Ŀؼʹø TextBox ΪĿ + var realTarget = _targetInnerText ?? Target; if (KeyInputMapping.TryGetValue(key, out var s)) { - Target.RaiseEvent(new TextInputEventArgs() + realTarget.RaiseEvent(new TextInputEventArgs() { Source = this, RoutedEvent = TextInputEvent, @@ -95,7 +120,7 @@ public class NumPad: TemplatedControl } else { - Target.RaiseEvent(new KeyEventArgs() + realTarget.RaiseEvent(new KeyEventArgs() { Source = this, RoutedEvent = KeyDownEvent, @@ -103,4 +128,33 @@ public class NumPad: TemplatedControl }); } } + /// + /// Ŀؼв TextBox ؼ + /// + /// Ŀؼ + /// ҵ TextBoxûҵ򷵻 null + private static TextBox? FindTextBoxInTarget(InputElement target) + { + // Ŀ걾 TextBox + if (target is TextBox textBox) + return textBox; + + // Ŀ TemplatedControlѾӦģ + if (target is TemplatedControl templatedControl && templatedControl.IsInitialized) + { + // ͨģ PART_TextBox + if (templatedControl.GetTemplateChildren().FirstOrDefault(c => c is TextBox) is TextBox partTextBox) + return partTextBox; + } + + // Ŀ ILogicalʹ LogicalTree չ + if (target is ILogical logical) + { + // ʹ GetLogicalDescendants ߼ӿؼ + var textBoxes = logical.GetLogicalDescendants().OfType(); + return textBoxes.FirstOrDefault(); + } + + return null; + } } \ No newline at end of file