Skip to content

Commit 94f2177

Browse files
futuresBoyKeboo
andauthored
NumericUpDown control support decimals value, and the value for each increase or decrease can be set. (#3661)
* Support decimals value, and the size of value for each increase or decrease can be set. * UpDown control support decimals, and the value for each increase or decrease can be set. * Updates to UpDownBase to support generic math on NET8 TODO: Need to fix XAMLTest to support the common generic base class so the generator stops choking * Updating UI tests Updated new XAMLTest library Added DeciamlUpDown tests --------- Co-authored-by: Kevin Bost <[email protected]> Co-authored-by: Kevin Bost <[email protected]>
1 parent 4a4c0e2 commit 94f2177

13 files changed

+617
-290
lines changed

Directory.packages.props

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
2727
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
2828
<PackageVersion Include="VirtualizingWrapPanel" Version="1.5.8" />
29-
<PackageVersion Include="XAMLTest" Version="1.2.1" />
29+
<PackageVersion Include="XAMLTest" Version="1.2.2" />
3030
<PackageVersion Include="xunit" Version="2.6.2" />
3131
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" />
3232
<PackageVersion Include="Xunit.StaFact" Version="1.1.11" />
3333
</ItemGroup>
34-
</Project>
34+
</Project>

src/MainDemo.Wpf/Domain/MainWindowViewModel.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,9 @@ private static IEnumerable<DemoItem> GenerateDemoItems(ISnackbarMessageQueue sna
475475
{
476476
DocumentationLink.DemoPageLink<NumericUpDown>(),
477477
DocumentationLink.StyleLink(nameof(NumericUpDown)),
478-
DocumentationLink.ApiLink<NumericUpDown>()
478+
DocumentationLink.ApiLink<NumericUpDown>(),
479+
DocumentationLink.ApiLink<DecimalUpDown>(),
480+
DocumentationLink.ApiLink<UpDownBase>()
479481
});
480482
}
481483

src/MainDemo.Wpf/NumericUpDown.xaml

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<UserControl x:Class="MaterialDesignDemo.NumericUpDown"
1+
<UserControl x:Class="MaterialDesignDemo.NumericUpDown"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -25,12 +25,19 @@
2525
<StackPanel Margin="0,16,0,0"
2626
DockPanel.Dock="Top"
2727
Orientation="Horizontal">
28+
2829
<smtx:XamlDisplay Margin="10,5"
2930
VerticalAlignment="Top"
3031
UniqueKey="numericUpDown_default">
3132
<materialDesign:NumericUpDown />
3233
</smtx:XamlDisplay>
3334

35+
<smtx:XamlDisplay Margin="10,5"
36+
VerticalAlignment="Top"
37+
UniqueKey="decimalUpDown_default">
38+
<materialDesign:DecimalUpDown ValueStep="0.5" Minimum="-2.5" Maximum="2.5" />
39+
</smtx:XamlDisplay>
40+
3441
<smtx:XamlDisplay Margin="10,5"
3542
VerticalAlignment="Top"
3643
UniqueKey="numericUpDown_customButtonContent">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#if !NET8_0_OR_GREATER
2+
using System.Globalization;
3+
#endif
4+
5+
namespace MaterialDesignThemes.Wpf;
6+
7+
public class DecimalUpDown
8+
#if NET8_0_OR_GREATER
9+
: UpDownBase<decimal>
10+
#else
11+
: UpDownBase<decimal, DecimalArithmetic>
12+
#endif
13+
{
14+
static DecimalUpDown()
15+
{
16+
DefaultStyleKeyProperty.OverrideMetadata(typeof(DecimalUpDown), new FrameworkPropertyMetadata(typeof(DecimalUpDown)));
17+
}
18+
}
19+
20+
#if !NET8_0_OR_GREATER
21+
public class DecimalArithmetic : IArithmetic<decimal>
22+
{
23+
public decimal Add(decimal value1, decimal value2) => value1 + value2;
24+
25+
public decimal Subtract(decimal value1, decimal value2) => value1 - value2;
26+
27+
public int Compare(decimal value1, decimal value2) => value1.CompareTo(value2);
28+
29+
public decimal MinValue() => decimal.MinValue;
30+
31+
public decimal MaxValue() => decimal.MaxValue;
32+
33+
public decimal One() => 1m;
34+
35+
public decimal Max(decimal value1, decimal value2) => Math.Max(value1, value2);
36+
37+
public decimal Min(decimal value1, decimal value2) => Math.Min(value1, value2);
38+
39+
public bool TryParse(string text, IFormatProvider? formatProvider, out decimal value)
40+
=> decimal.TryParse(text, NumberStyles.Number, formatProvider, out value);
41+
}
42+
#endif
+23-241
Original file line numberDiff line numberDiff line change
@@ -1,259 +1,41 @@
1-
using System.ComponentModel;
1+
#if !NET8_0_OR_GREATER
22
using System.Globalization;
3+
#endif
34

45
namespace MaterialDesignThemes.Wpf;
56

6-
[TemplatePart(Name = IncreaseButtonPartName, Type = typeof(RepeatButton))]
7-
[TemplatePart(Name = DecreaseButtonPartName, Type = typeof(RepeatButton))]
8-
[TemplatePart(Name = TextBoxPartName, Type = typeof(TextBox))]
9-
public class NumericUpDown : Control
7+
public class NumericUpDown
8+
#if NET8_0_OR_GREATER
9+
: UpDownBase<int>
10+
#else
11+
: UpDownBase<int, IntArithmetic>
12+
#endif
1013
{
11-
public const string IncreaseButtonPartName = "PART_IncreaseButton";
12-
public const string DecreaseButtonPartName = "PART_DecreaseButton";
13-
public const string TextBoxPartName = "PART_TextBox";
14-
15-
private TextBox? _textBoxField;
16-
private RepeatButton? _decreaseButton;
17-
private RepeatButton? _increaseButton;
18-
1914
static NumericUpDown()
2015
{
2116
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown)));
2217
}
18+
}
2319

24-
#region DependencyProperties
25-
26-
27-
28-
public object? IncreaseContent
29-
{
30-
get => GetValue(IncreaseContentProperty);
31-
set => SetValue(IncreaseContentProperty, value);
32-
}
33-
34-
// Using a DependencyProperty as the backing store for IncreaseContent. This enables animation, styling, binding, etc...
35-
public static readonly DependencyProperty IncreaseContentProperty =
36-
DependencyProperty.Register(nameof(IncreaseContent), typeof(object), typeof(NumericUpDown), new PropertyMetadata(null));
37-
38-
public object? DecreaseContent
39-
{
40-
get => GetValue(DecreaseContentProperty);
41-
set => SetValue(DecreaseContentProperty, value);
42-
}
43-
44-
// Using a DependencyProperty as the backing store for DecreaseContent. This enables animation, styling, binding, etc...
45-
public static readonly DependencyProperty DecreaseContentProperty =
46-
DependencyProperty.Register(nameof(DecreaseContent), typeof(object), typeof(NumericUpDown), new PropertyMetadata(null));
47-
48-
#region DependencyProperty : MinimumProperty
49-
public int Minimum
50-
{
51-
get => (int)GetValue(MinimumProperty);
52-
set => SetValue(MinimumProperty, value);
53-
}
54-
public static readonly DependencyProperty MinimumProperty =
55-
DependencyProperty.Register(nameof(Minimum), typeof(int), typeof(NumericUpDown), new PropertyMetadata(int.MinValue, OnMinimumChanged));
56-
57-
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
58-
{
59-
NumericUpDown ctrl = (NumericUpDown)d;
60-
ctrl.CoerceValue(ValueProperty);
61-
ctrl.CoerceValue(MaximumProperty);
62-
}
63-
64-
#endregion DependencyProperty : MinimumProperty
65-
66-
#region DependencyProperty : MaximumProperty
67-
68-
public int Maximum
69-
{
70-
get => (int)GetValue(MaximumProperty);
71-
set => SetValue(MaximumProperty, value);
72-
}
73-
74-
public static readonly DependencyProperty MaximumProperty =
75-
DependencyProperty.Register(nameof(Maximum), typeof(int), typeof(NumericUpDown), new PropertyMetadata(int.MaxValue, OnMaximumChanged, CoerceMaximum));
76-
77-
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
78-
{
79-
NumericUpDown ctrl = (NumericUpDown)d;
80-
ctrl.CoerceValue(ValueProperty);
81-
}
82-
83-
private static object? CoerceMaximum(DependencyObject d, object? value)
84-
{
85-
if (d is NumericUpDown numericUpDown &&
86-
value is int numericValue)
87-
{
88-
return Math.Max(numericUpDown.Minimum, numericValue);
89-
}
90-
return value;
91-
}
92-
93-
#endregion DependencyProperty : MaximumProperty
94-
95-
#region DependencyProperty : ValueProperty
96-
public int Value
97-
{
98-
get => (int)GetValue(ValueProperty);
99-
set => SetValue(ValueProperty, value);
100-
}
101-
102-
public static readonly DependencyProperty ValueProperty =
103-
DependencyProperty.Register(nameof(Value), typeof(int), typeof(NumericUpDown), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnNumericValueChanged, CoerceNumericValue));
104-
105-
private static void OnNumericValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
106-
{
107-
if (d is NumericUpDown numericUpDown)
108-
{
109-
var args = new RoutedPropertyChangedEventArgs<int>((int)e.OldValue, (int)e.NewValue)
110-
{
111-
RoutedEvent = ValueChangedEvent
112-
};
113-
numericUpDown.RaiseEvent(args);
114-
if (numericUpDown._textBoxField is { } textBox)
115-
{
116-
textBox.Text = ((int)e.NewValue).ToString(CultureInfo.CurrentUICulture);
117-
}
118-
119-
if (numericUpDown._increaseButton is { } increaseButton)
120-
{
121-
increaseButton.IsEnabled = numericUpDown.Value != numericUpDown.Maximum;
122-
}
123-
124-
if (numericUpDown._decreaseButton is { } decreaseButton)
125-
{
126-
decreaseButton.IsEnabled = numericUpDown.Value != numericUpDown.Minimum;
127-
}
128-
}
129-
}
130-
131-
private static object? CoerceNumericValue(DependencyObject d, object? value)
132-
{
133-
if (d is NumericUpDown numericUpDown &&
134-
value is int numericValue)
135-
{
136-
numericValue = Math.Min(numericUpDown.Maximum, numericValue);
137-
numericValue = Math.Max(numericUpDown.Minimum, numericValue);
138-
return numericValue;
139-
}
140-
return value;
141-
}
142-
#endregion ValueProperty
143-
144-
#region DependencyProperty : AllowChangeOnScroll
145-
146-
public bool AllowChangeOnScroll
147-
{
148-
get => (bool)GetValue(AllowChangeOnScrollProperty);
149-
set => SetValue(AllowChangeOnScrollProperty, value);
150-
}
151-
152-
public static readonly DependencyProperty AllowChangeOnScrollProperty =
153-
DependencyProperty.Register(nameof(AllowChangeOnScroll), typeof(bool), typeof(NumericUpDown), new PropertyMetadata(false));
154-
155-
#endregion
156-
157-
#endregion DependencyProperties
158-
159-
#region Event : ValueChangedEvent
160-
[Category("Behavior")]
161-
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(nameof(ValueChanged), RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<int>), typeof(NumericUpDown));
162-
163-
public event RoutedPropertyChangedEventHandler<int> ValueChanged
164-
{
165-
add => AddHandler(ValueChangedEvent, value);
166-
remove => RemoveHandler(ValueChangedEvent, value);
167-
}
168-
#endregion Event : ValueChangedEvent
169-
170-
public override void OnApplyTemplate()
171-
{
172-
if (_increaseButton != null)
173-
_increaseButton.Click -= IncreaseButtonOnClick;
174-
175-
if (_decreaseButton != null)
176-
_decreaseButton.Click -= DecreaseButtonOnClick;
177-
if (_textBoxField != null)
178-
_textBoxField.TextChanged -= OnTextBoxFocusLost;
179-
180-
_increaseButton = GetTemplateChild(IncreaseButtonPartName) as RepeatButton;
181-
_decreaseButton = GetTemplateChild(DecreaseButtonPartName) as RepeatButton;
182-
_textBoxField = GetTemplateChild(TextBoxPartName) as TextBox;
183-
184-
if (_increaseButton != null)
185-
_increaseButton.Click += IncreaseButtonOnClick;
186-
187-
if (_decreaseButton != null)
188-
_decreaseButton.Click += DecreaseButtonOnClick;
189-
190-
if (_textBoxField != null)
191-
{
192-
_textBoxField.LostFocus += OnTextBoxFocusLost;
193-
_textBoxField.Text = Value.ToString(CultureInfo.CurrentUICulture);
194-
}
195-
196-
base.OnApplyTemplate();
197-
}
20+
#if !NET8_0_OR_GREATER
21+
public class IntArithmetic : IArithmetic<int>
22+
{
23+
public int Add(int value1, int value2) => value1 + value2;
19824

199-
private void OnTextBoxFocusLost(object sender, EventArgs e)
200-
{
201-
if (_textBoxField is { } textBoxField)
202-
{
203-
if (int.TryParse(textBoxField.Text, NumberStyles.Integer, CultureInfo.CurrentUICulture, out int numericValue))
204-
{
205-
SetCurrentValue(ValueProperty, numericValue);
206-
}
207-
else
208-
{
209-
textBoxField.Text = Value.ToString(CultureInfo.CurrentUICulture);
210-
}
211-
}
212-
}
25+
public int Subtract(int value1, int value2) => value1 - value2;
21326

214-
private void IncreaseButtonOnClick(object sender, RoutedEventArgs e) => OnIncrease();
27+
public int Compare(int value1, int value2) => value1.CompareTo(value2);
21528

216-
private void DecreaseButtonOnClick(object sender, RoutedEventArgs e) => OnDecrease();
29+
public int MinValue() => int.MinValue;
21730

218-
private void OnIncrease()
219-
{
220-
SetCurrentValue(ValueProperty, Value + 1);
221-
}
31+
public int MaxValue() => int.MaxValue;
32+
public int One() => 1;
22233

223-
private void OnDecrease()
224-
{
225-
SetCurrentValue(ValueProperty, Value - 1);
226-
}
34+
public int Max(int value1, int value2) => Math.Max(value1, value2);
22735

228-
protected override void OnPreviewKeyDown(KeyEventArgs e)
229-
{
230-
if (e.Key == Key.Up)
231-
{
232-
OnIncrease();
233-
e.Handled = true;
234-
}
235-
else if (e.Key == Key.Down)
236-
{
237-
OnDecrease();
238-
e.Handled = true;
239-
}
240-
base.OnPreviewKeyDown(e);
241-
}
36+
public int Min(int value1, int value2) => Math.Min(value1, value2);
24237

243-
protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
244-
{
245-
if (IsKeyboardFocusWithin && AllowChangeOnScroll)
246-
{
247-
if (e.Delta > 0)
248-
{
249-
OnIncrease();
250-
}
251-
else if (e.Delta < 0)
252-
{
253-
OnDecrease();
254-
}
255-
e.Handled = true;
256-
}
257-
base.OnPreviewMouseWheel(e);
258-
}
38+
public bool TryParse(string text, IFormatProvider? formatProvider, out int value)
39+
=> int.TryParse(text, NumberStyles.Integer, formatProvider, out value);
25940
}
41+
#endif

src/MaterialDesignThemes.Wpf/Themes/Generic.xaml

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
<Style TargetType="{x:Type local:AutoSuggestBox}" BasedOn="{StaticResource MaterialDesignAutoSuggestBox}" />
4444
<Style TargetType="{x:Type local:SplitButton}" BasedOn="{StaticResource MaterialDesignRaisedSplitButton}" />
4545
<Style TargetType="{x:Type local:NumericUpDown}" BasedOn="{StaticResource MaterialDesignNumericUpDown}" />
46+
<Style TargetType="{x:Type local:DecimalUpDown}" BasedOn="{StaticResource MaterialDesignNumericUpDown}" />
4647

4748
<converters:BrushToRadialGradientBrushConverter x:Key="BrushToRadialGradientBrushConverter" />
4849
<converters:DrawerOffsetConverter x:Key="DrawerOffsetConverter" />

0 commit comments

Comments
 (0)