Merge pull request #752 from yangjieshao/main

修复了NumPad对NumericUpDown和IPv4Box的支持
This commit is contained in:
Dong Bin
2025-08-29 17:07:03 +08:00
committed by GitHub
6 changed files with 164 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
<ResourceDictionary
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa">
@@ -92,7 +92,7 @@
</u:NumPadButton>
<u:NumPadButton
Grid.Row="1"
Grid.RowSpan="2"
Grid.RowSpan="1"
Grid.Column="3"
Height="{x:Static x:Double.NaN}"
VerticalAlignment="Stretch"
@@ -100,6 +100,16 @@
FunctionKey="Add"
NumContent="+"
NumKey="Add" />
<u:NumPadButton
Grid.Row="2"
Grid.RowSpan="1"
Grid.Column="3"
Height="{x:Static x:Double.NaN}"
VerticalAlignment="Stretch"
FunctionContent="←"
FunctionKey="Back"
NumContent="←"
NumKey="Back" />
<u:NumPadButton
Grid.Row="2"
Grid.Column="0"

View File

@@ -1,4 +1,4 @@
using System.Net;
using System.Net;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
@@ -107,7 +107,25 @@ public class IPv4Box: TemplatedControl
e.Client = tb._imClient;
});
}
/// <summary>
/// 是否使用小键盘输入
/// </summary>
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;

View File

@@ -1,6 +1,9 @@
using Avalonia;
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);
}
/// <summary>
/// Target 目标内部的 TextBox 控件
/// </summary>
private TextBox? _targetInnerText;
public static readonly StyledProperty<bool> NumModeProperty = AvaloniaProperty.Register<NumPad, bool>(
nameof(NumMode), defaultValue: true);
@@ -54,10 +62,24 @@ public class NumPad: TemplatedControl
var existing = OverlayDialog.Recall<NumPad>(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
});
}
}
/// <summary>
/// 在目标控件中查找 TextBox 控件
/// </summary>
/// <param name="target">目标控件</param>
/// <returns>找到的 TextBox如果没有找到则返回 null</returns>
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<TextBox>();
return textBoxes.FirstOrDefault();
}
return null;
}
}

View File

@@ -32,6 +32,10 @@ public class NumericIntUpDown : NumericUpDownBase<int>
var result = a - b;
return result > Value ? Minimum : result;
}
public override void Clear()
{
base.Clear();
}
}
public class NumericUIntUpDown : NumericUpDownBase<uint>
@@ -68,6 +72,10 @@ public class NumericUIntUpDown : NumericUpDownBase<uint>
var result = a - b;
return result > Value ? Minimum : result;
}
public override void Clear()
{
base.Clear();
}
}
public class NumericDoubleUpDown : NumericUpDownBase<double>
@@ -91,6 +99,10 @@ public class NumericDoubleUpDown : NumericUpDownBase<double>
protected override double? Add(double? a, double? b) => a + b;
protected override double? Minus(double? a, double? b) => a - b;
public override void Clear()
{
base.Clear();
}
}
public class NumericByteUpDown : NumericUpDownBase<byte>
@@ -122,6 +134,10 @@ public class NumericByteUpDown : NumericUpDownBase<byte>
var result = a - b;
return (byte?)(result > Value ? Minimum : result);
}
public override void Clear()
{
base.Clear();
}
}
public class NumericSByteUpDown : NumericUpDownBase<sbyte>
@@ -153,6 +169,10 @@ public class NumericSByteUpDown : NumericUpDownBase<sbyte>
var result = a - b;
return (sbyte?)(result > Value ? Minimum : result);
}
public override void Clear()
{
base.Clear();
}
}
public class NumericShortUpDown : NumericUpDownBase<short>
@@ -184,6 +204,10 @@ public class NumericShortUpDown : NumericUpDownBase<short>
var result = a - b;
return (short?)(result > Value ? Minimum : result);
}
public override void Clear()
{
base.Clear();
}
}
public class NumericUShortUpDown : NumericUpDownBase<ushort>
@@ -215,6 +239,10 @@ public class NumericUShortUpDown : NumericUpDownBase<ushort>
var result = a - b;
return (ushort?)(result > Value ? Minimum : result);
}
public override void Clear()
{
base.Clear();
}
}
public class NumericLongUpDown : NumericUpDownBase<long>
@@ -246,6 +274,10 @@ public class NumericLongUpDown : NumericUpDownBase<long>
var result = a - b;
return result > Value ? Minimum : result;
}
public override void Clear()
{
base.Clear();
}
}
public class NumericULongUpDown : NumericUpDownBase<ulong>
@@ -269,6 +301,10 @@ public class NumericULongUpDown : NumericUpDownBase<ulong>
protected override ulong? Add(ulong? a, ulong? b) => a + b;
protected override ulong? Minus(ulong? a, ulong? b) => a - b;
public override void Clear()
{
base.Clear();
}
}
public class NumericFloatUpDown : NumericUpDownBase<float>
@@ -292,6 +328,10 @@ public class NumericFloatUpDown : NumericUpDownBase<float>
protected override float? Add(float? a, float? b) => a + b;
protected override float? Minus(float? a, float? b) => a - b;
public override void Clear()
{
base.Clear();
}
}
public class NumericDecimalUpDown : NumericUpDownBase<decimal>
@@ -315,4 +355,9 @@ public class NumericDecimalUpDown : NumericUpDownBase<decimal>
protected override decimal? Add(decimal? a, decimal? b) => a + b;
protected override decimal? Minus(decimal? a, decimal? b) => a - b;
public override void Clear()
{
base.Clear();
}
}