Merge pull request #170 from heartacker/acker/und_new_feature_3_20

bug fix and add new NumericUpDownDemo
This commit is contained in:
Dong Bin
2024-03-21 17:29:14 +08:00
committed by GitHub
10 changed files with 941 additions and 651 deletions

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-android</TargetFramework>
<TargetFramework>net8.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ApplicationId>com.irihitech.Ursa</ApplicationId>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<WasmMainJSPath>AppBundle\main.js</WasmMainJSPath>
<OutputType>Exe</OutputType>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0-ios</TargetFramework>
<TargetFramework>net8.0-ios</TargetFramework>
<SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@@ -8,19 +8,170 @@
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<UserControl.Styles>
<Style Selector=":is(u|NumericUpDown)">
<Setter Property="Width" Value="240"></Setter>
<Setter Property="Width" Value="240" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
</UserControl.Styles>
<StackPanel HorizontalAlignment="Left">
<u:NumericIntUpDown Name="input" InnerLeftContent="Age" Step="1" Value="2" Watermark="Input Value" Classes="ClearButton" />
<TextBlock Text="{Binding #input.Value}" ></TextBlock>
<u:NumericDoubleUpDown Name="inputDouble" Step="0.5" Value="3.1" EmptyInputValue="1"></u:NumericDoubleUpDown>
<TextBlock Text="{Binding #inputDouble.Value}"></TextBlock>
<u:NumericByteUpDown Name="inputByte" Step="1" Value="3" EmptyInputValue="1"></u:NumericByteUpDown>
<TextBlock Text="{Binding #inputByte.Value}"></TextBlock>
<TextBlock Text="Drag"></TextBlock>
<u:NumericIntUpDown Step="1" Value="2" Watermark="Input Value" AllowDrag="True" />
<Grid ColumnDefinitions="*,*">
<Grid
Grid.Column="0"
HorizontalAlignment="Left"
RowDefinitions="200,*">
<StackPanel>
<u:Divider Content="Change Right ->" />
<u:NumericUIntUpDown
Name="numd"
HorizontalContentAlignment="{Binding HorizontalContentAlignment}"
AllowDrag="{Binding AllowDrag}"
AllowSpin="{Binding AllowSpin}"
FontFamily="{Binding FontFamily, Mode=OneWay}"
FormatString="{Binding FormatString}"
InnerLeftContent="{Binding InnerLeftContent}"
IsEnabled="{Binding IsEnable}"
IsReadOnly="{Binding IsReadOnly}"
Maximum="{Binding Maximum}"
Minimum="{Binding Minimum}"
ParsingNumberStyle="{Binding ParsingNumberStyle}"
ShowButtonSpinner="{Binding ShowButtonSpinner}"
Step="{Binding Step}"
Watermark="{Binding Watermark}"
Value="{Binding Value}" />
<u:Divider Content="Demo" />
</StackPanel>
<StackPanel Grid.Row="1">
<u:Divider Content="{Binding #input.Value, StringFormat='Int = {0}'}" />
<u:NumericIntUpDown
Name="input"
Classes="ClearButton"
InnerLeftContent="Age"
Step="1"
Watermark="Input Value"
Value="2" />
<u:Divider Content="{Binding #inputDouble.Value, StringFormat='Double = {0}'}" />
<u:NumericDoubleUpDown
Name="inputDouble"
EmptyInputValue="1"
Step="0.5"
Value="3.1" />
<u:Divider Content="{Binding #inputByte.Value, StringFormat='Byte = {0}'}" />
<u:NumericByteUpDown
Name="inputByte"
EmptyInputValue="1"
Step="1"
Value="3" />
<u:Divider Content="{Binding #Drag_Int.Value, StringFormat='Drag Int = {0}'}" />
<u:NumericIntUpDown
Name="Drag_Int"
AllowDrag="True"
InnerLeftContent="Drag"
Step="1"
Watermark="Input Value"
Value="2" />
<!-- hex demo -->
<u:Divider Content="{Binding #uint_HexNumber.Value, StringFormat='Dont Use = {0}, hex={0:X}'}" />
<!-- =================this is error usage -->
<u:NumericUIntUpDown
Name="uint_HexNumber"
AllowDrag="False"
FormatString="{}{0:X8}"
InnerLeftContent="HexNumber"
ParsingNumberStyle="HexNumber"
Step="1"
Watermark="Input Value"
Value="2" />
<!-- =================we should use AllowHexSpecifier -->
<u:Divider Content="{Binding #uint_AllowHexSpecifier.Value, StringFormat='uint = {0}, hex={0:X}'}" />
<u:NumericUIntUpDown
Name="uint_AllowHexSpecifier"
HorizontalContentAlignment="Right"
AllowDrag="False"
FontFamily="Consolas"
FormatString="{}{0:X8}"
InnerLeftContent="AllowHexSpecifier"
ParsingNumberStyle="AllowHexSpecifier"
Step="1"
Watermark="AllowHexSpecifier"
Value="2" />
<u:Divider Content="{Binding #Consolas_uint.Value, StringFormat='Font=Consolas {0}, hex={0:X}'}" />
<u:NumericUIntUpDown
Name="Consolas_uint"
HorizontalContentAlignment="Right"
AllowDrag="False"
FontFamily="Consolas"
FormatString="X8"
InnerLeftContent="0x"
ParsingNumberStyle="AllowHexSpecifier"
Step="1"
Watermark="AllowHexSpecifier"
Value="2" />
</StackPanel>
</Grid>
<StackPanel Grid.Column="1" HorizontalAlignment="Left">
<Label Content="FontFamily" />
<TextBox Text="{Binding FontFamily}" />
<Label Content="AllowDrag" />
<CheckBox IsChecked="{Binding AllowDrag}" />
<Label Content="IsReadOnly" />
<CheckBox IsChecked="{Binding IsReadOnly}" />
<Label Content="HorizontalContentAlignment" />
<ComboBox ItemsSource="{Binding Array_HorizontalContentAlignment}" SelectedItem="{Binding HorizontalContentAlignment}" />
<Label Content="InnerLeftContent" />
<TextBox Text="{Binding InnerLeftContent}" />
<Label Content="Watermark" />
<TextBox Text="{Binding Watermark}" />
<Label Content="FormatString" />
<TextBox
MinWidth="100"
MaxLength="100"
Text="{Binding FormatString}" />
<Label Content="ParsingNumberStyle" />
<ComboBox ItemsSource="{Binding Array_ParsingNumberStyle}" SelectedItem="{Binding ParsingNumberStyle}" />
<Label Content="AllowSpin" />
<CheckBox IsChecked="{Binding AllowSpin}" />
<Label Content="ShowButtonSpinner" />
<CheckBox IsChecked="{Binding ShowButtonSpinner}" />
<u:NumericUIntUpDown
Name="nudV"
AllowSpin="True"
InnerLeftContent="Value"
IsEnabled="True"
IsReadOnly="False"
Value="{Binding Value, Mode=TwoWay}" />
<u:NumericUIntUpDown InnerLeftContent="Max" Value="{Binding Maximum}" />
<u:NumericUIntUpDown InnerLeftContent="Min" Value="{Binding Minimum}" />
<Label Content="Step" />
<Slider Minimum="1" Value="{Binding Step}" />
<Label Content="IsEnable" />
<CheckBox IsChecked="{Binding IsEnable}" />
</StackPanel>
</Grid>
</UserControl>

View File

@@ -1,6 +1,9 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using System;
using System.Diagnostics;
using Ursa.Controls;
using Ursa.Demo.ViewModels;
namespace Ursa.Demo.Pages;
@@ -11,5 +14,12 @@ public partial class NumericUpDownDemo : UserControl
{
InitializeComponent();
DataContext = new NumericUpDownDemoViewModel();
numd.ValueChanged += Numd_ValueChanged;
}
private void Numd_ValueChanged(object? sender, ValueChangedEventArgs<uint> e)
{
Trace.WriteLine($"{(sender as NumericUIntUpDown).Name} {e.OldValue} {e.NewValue}");
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
@@ -18,7 +18,7 @@
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageReference Include="Semi.Avalonia" Version="11.0.7" />
</ItemGroup>

View File

@@ -1,8 +1,50 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Avalonia.Controls;
using Avalonia.Layout;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Globalization;
using Ursa.Controls;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Ursa.Demo.ViewModels;
public class NumericUpDownDemoViewModel: ObservableObject
public partial class NumericUpDownDemoViewModel : ObservableObject
{
[ObservableProperty] private uint _Value;
[ObservableProperty] private string _FontFamily = "Consolas";
[ObservableProperty] private bool _AllowDrag = false;
[ObservableProperty] private bool _IsReadOnly = false;
[ObservableProperty] private Array _Array_HorizontalContentAlignment;
[ObservableProperty] private HorizontalAlignment _HorizontalContentAlignment = HorizontalAlignment.Center;
[ObservableProperty] private object? _InnerLeftContent = "obj:0x";
[ObservableProperty] private string _Watermark = "Water mark showed";
[ObservableProperty] private string _FormatString = "X8";
[ObservableProperty] private Array _Array_ParsingNumberStyle;
[ObservableProperty] private NumberStyles _ParsingNumberStyle = NumberStyles.AllowHexSpecifier;
[ObservableProperty] private bool _AllowSpin = true;
[ObservableProperty] private bool _ShowButtonSpinner = true;
[ObservableProperty] private UInt32 _Maximum = UInt32.MaxValue;
[ObservableProperty] private UInt32 _Minimum = UInt32.MinValue;
[ObservableProperty] private UInt32 _Step = 1;
[ObservableProperty] private bool _IsEnable = true;
public NumericUpDownDemoViewModel()
{
Array_HorizontalContentAlignment = Enum.GetValues(typeof(HorizontalAlignment));
Array_ParsingNumberStyle = Enum.GetValues(typeof(NumberStyles));
NumericUIntUpDown numericUIntUpDown;
TextBox textBox;
}
partial void OnValueChanging(uint oldValue, uint newValue)
{
Console.WriteLine(oldValue);
}
}

View File

@@ -35,24 +35,25 @@
MinWidth="0"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}"
AllowSpin="{TemplateBinding AllowSpin}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
BorderThickness="{TemplateBinding BorderThickness}"
ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}">
<Panel>
<TextBox
Name="PART_TextBox"
Height="{TemplateBinding Height}"
MinHeight="{DynamicResource NumericUpDownWrapperDefaultHeight}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
AcceptsReturn="False"
CornerRadius="{TemplateBinding CornerRadius}"
DataValidationErrors.Errors="{ReflectionBinding $parent[NumericUpDown].(DataValidationErrors.Errors)}"
FontSize="{TemplateBinding FontSize}"
Foreground="{TemplateBinding Foreground}"
InnerLeftContent="{TemplateBinding InnerLeftContent}"
IsReadOnly="{TemplateBinding IsReadOnly}"
TextWrapping="NoWrap"
InnerLeftContent="{TemplateBinding InnerLeftContent}"
Theme="{DynamicResource NonErrorTextBox}"
Watermark="{TemplateBinding Watermark}" />
<Panel
@@ -64,11 +65,11 @@
IsVisible="{TemplateBinding AllowDrag}" />
<Button
Name="PART_ClearButton"
Command="{Binding $parent[u:NumericUpDown].Clear}"
Margin="0,0,8,0"
HorizontalAlignment="Right"
Margin="0 0 8 0"
IsVisible="False"
Command="{Binding $parent[u:NumericUpDown].Clear}"
Focusable="False"
IsVisible="False"
Theme="{StaticResource InputClearButton}" />
</Panel>
</ButtonSpinner>

View File

@@ -18,7 +18,10 @@ public class NumericIntUpDown : NumericUpDownBase<int>
protected override bool ParseText(string? text, out int number) =>
int.TryParse(text, ParsingNumberStyle, NumberFormat, out number);
protected override string? ValueToString(int? value) => value?.ToString(FormatString, NumberFormat);
protected override string? ValueToString(int? value)
{
return value?.ToString(FormatString, NumberFormat);
}
protected override int Zero => 0;
@@ -27,6 +30,34 @@ public class NumericIntUpDown : NumericUpDownBase<int>
protected override int? Minus(int? a, int? b) => a - b;
}
public class NumericUIntUpDown : NumericUpDownBase<uint>
{
protected override Type StyleKeyOverride { get; } = typeof(NumericUpDown);
static NumericUIntUpDown()
{
MaximumProperty.OverrideDefaultValue<NumericUIntUpDown>(uint.MaxValue);
MinimumProperty.OverrideDefaultValue<NumericUIntUpDown>(uint.MinValue);
StepProperty.OverrideDefaultValue<NumericUIntUpDown>(1);
}
protected override bool ParseText(string? text, out uint number)
{
return uint.TryParse(text, ParsingNumberStyle, NumberFormat, out number);
}
protected override string? ValueToString(uint? value)
{
return value?.ToString(FormatString, NumberFormat);
}
protected override uint Zero => 0;
protected override uint? Add(uint? a, uint? b) => a + b;
protected override uint? Minus(uint? a, uint? b) => a - b;
}
public class NumericDoubleUpDown : NumericUpDownBase<double>
{
protected override Type StyleKeyOverride { get; } = typeof(NumericUpDown);
@@ -233,4 +264,3 @@ public class NumericDecimalUpDown : NumericUpDownBase<decimal>
protected override decimal? Minus(decimal? a, decimal? b) => a - b;
}

View File

@@ -9,6 +9,7 @@ using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Irihi.Avalonia.Shared.Contracts;
namespace Ursa.Controls;
@@ -29,6 +30,12 @@ public abstract class NumericUpDown : TemplatedControl, IClearControl
private Point? _point;
protected internal bool _updateFromTextInput;
protected internal bool _canIncrease = true;
protected internal bool _canDecrease = true;
public static readonly StyledProperty<bool> AllowDragProperty = AvaloniaProperty.Register<NumericUpDown, bool>(
nameof(AllowDrag), defaultValue: false);
@@ -47,6 +54,14 @@ public abstract class NumericUpDown : TemplatedControl, IClearControl
set => SetValue(IsReadOnlyProperty, value);
}
public static readonly StyledProperty<HorizontalAlignment> HorizontalContentAlignmentProperty =
ContentControl.HorizontalContentAlignmentProperty.AddOwner<NumericUpDown>();
public HorizontalAlignment HorizontalContentAlignment
{
get => GetValue(HorizontalContentAlignmentProperty);
set => SetValue(HorizontalContentAlignmentProperty, value);
}
public static readonly StyledProperty<object?> InnerLeftContentProperty = AvaloniaProperty.Register<NumericUpDown, object?>(
nameof(InnerLeftContent));
@@ -247,10 +262,12 @@ public abstract class NumericUpDown : TemplatedControl, IClearControl
int d = GetDelta(delta.Value);
if (d > 0)
{
if (_canIncrease)
Increase();
}
else if (d < 0)
{
if (_canDecrease)
Decrease();
}
_point = point;
@@ -309,6 +326,33 @@ public abstract class NumericUpDown : TemplatedControl, IClearControl
public abstract class NumericUpDownBase<T> : NumericUpDown where T : struct, IComparable<T>
{
protected static string TrimString(string? text, NumberStyles numberStyles)
{
text = text!.Trim();
if (text.Contains("_")) // support _ like 0x1024_1024(hex), 10_24 (normal)
{
text = text.Replace("_", "");
}
if ((numberStyles & NumberStyles.AllowHexSpecifier) != 0)
{
if (text.StartsWith("0X") || text.StartsWith("0x")) // support 0x hex while user input
{
text = text.Substring(2);
}
else if (text.StartsWith("h") || text.StartsWith("H")) // support hex while user input
{
text = text.Substring(1);
}
else if (text.StartsWith("h'") || text.StartsWith("H'")) // support hex while user input
{
text = text.Substring(2);
}
}
return text;
}
public static readonly StyledProperty<T?> ValueProperty = AvaloniaProperty.Register<NumericUpDownBase<T>, T?>(
nameof(Value), defaultBindingMode: BindingMode.TwoWay);
@@ -474,6 +518,8 @@ public abstract class NumericUpDownBase<T>: NumericUpDown where T: struct, IComp
protected override void SetValidSpinDirection()
{
var validDirection = ValidSpinDirections.None;
_canIncrease = false;
_canDecrease = false;
if (!IsReadOnly)
{
if (Value is null)
@@ -483,11 +529,13 @@ public abstract class NumericUpDownBase<T>: NumericUpDown where T: struct, IComp
if (Value.HasValue && Value.Value.CompareTo(Maximum) < 0)
{
validDirection |= ValidSpinDirections.Increase;
_canIncrease = true;
}
if (Value.HasValue && Value.Value.CompareTo(Minimum) > 0)
{
validDirection |= ValidSpinDirections.Decrease;
_canDecrease = true;
}
}
if (_spinner != null)
@@ -515,9 +563,16 @@ public abstract class NumericUpDownBase<T>: NumericUpDown where T: struct, IComp
newValue = EmptyInputValue;
}
if (!Equals(newValue, Value))
{
if (Equals(Clamp(newValue, Maximum, Minimum), newValue))
{
SetCurrentValue(ValueProperty, newValue);
}
else
{
parsedTextIsValid = false;
}
}
}
catch
{
@@ -568,6 +623,7 @@ public abstract class NumericUpDownBase<T>: NumericUpDown where T: struct, IComp
}
else
{
text = TrimString(text, ParsingNumberStyle);
if (!ParseText(text, out var outputValue))
{
throw new InvalidDataException("Input string was not in a correct format.");