Browse Source

Add data validation error support to NumericUpDown control #3591

pull/5636/head
aguahombre 5 years ago
parent
commit
5d130b5d79
  1. 18
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  2. 95
      tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs

18
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -91,14 +91,14 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public static readonly DirectProperty<NumericUpDown, string> TextProperty = public static readonly DirectProperty<NumericUpDown, string> TextProperty =
AvaloniaProperty.RegisterDirect<NumericUpDown, string>(nameof(Text), o => o.Text, (o, v) => o.Text = v, AvaloniaProperty.RegisterDirect<NumericUpDown, string>(nameof(Text), o => o.Text, (o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay); defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
/// <summary> /// <summary>
/// Defines the <see cref="Value"/> property. /// Defines the <see cref="Value"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<NumericUpDown, double> ValueProperty = public static readonly DirectProperty<NumericUpDown, double> ValueProperty =
AvaloniaProperty.RegisterDirect<NumericUpDown, double>(nameof(Value), updown => updown.Value, AvaloniaProperty.RegisterDirect<NumericUpDown, double>(nameof(Value), updown => updown.Value,
(updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay); (updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
/// <summary> /// <summary>
/// Defines the <see cref="Watermark"/> property. /// Defines the <see cref="Watermark"/> property.
@ -370,6 +370,20 @@ namespace Avalonia.Controls
} }
} }
/// <summary>
/// Called to update the validation state for properties for which data validation is
/// enabled.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The new binding value for the property.</param>
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
{
if (property == TextProperty || property == ValueProperty)
{
DataValidationErrors.SetError(this, value.Error);
}
}
/// <summary> /// <summary>
/// Called when the <see cref="CultureInfo"/> property value changed. /// Called when the <see cref="CultureInfo"/> property value changed.
/// </summary> /// </summary>

95
tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs

@ -0,0 +1,95 @@
using System;
using System.Linq;
using System.Reactive.Subjects;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Threading;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class NumericUpDownTests
{
private static TestServices Services => TestServices.StyledWindow;
[Fact]
public void Text_Validation()
{
RunTest((control, textbox) =>
{
var exception = new InvalidCastException("failed validation");
var textObservable = new BehaviorSubject<BindingNotification>(new BindingNotification(exception, BindingErrorType.DataValidationError));
control.Bind(NumericUpDown.TextProperty, textObservable);
Dispatcher.UIThread.RunJobs();
Assert.True(DataValidationErrors.GetHasErrors(control));
Assert.True(DataValidationErrors.GetErrors(control).SequenceEqual(new[] { exception }));
});
}
[Fact]
public void Value_Validation()
{
RunTest((control, textbox) =>
{
var exception = new InvalidCastException("failed validation");
var valueObservable = new BehaviorSubject<BindingNotification>(new BindingNotification(exception, BindingErrorType.DataValidationError));
control.Bind(NumericUpDown.ValueProperty, valueObservable);
Dispatcher.UIThread.RunJobs();
Assert.True(DataValidationErrors.GetHasErrors(control));
Assert.True(DataValidationErrors.GetErrors(control).SequenceEqual(new[] { exception }));
});
}
private void RunTest(Action<NumericUpDown, TextBox> test)
{
using (UnitTestApplication.Start(Services))
{
var control = CreateControl();
TextBox textBox = GetTextBox(control);
var window = new Window { Content = control };
window.ApplyTemplate();
window.Presenter.ApplyTemplate();
Dispatcher.UIThread.RunJobs();
test.Invoke(control, textBox);
}
}
private NumericUpDown CreateControl()
{
var control = new NumericUpDown
{
Template = CreateTemplate()
};
control.ApplyTemplate();
return control;
}
private TextBox GetTextBox(NumericUpDown control)
{
return control.GetTemplateChildren()
.OfType<ButtonSpinner>()
.Select(b => b.Content)
.OfType<TextBox>()
.First();
}
private IControlTemplate CreateTemplate()
{
return new FuncControlTemplate<NumericUpDown>((control, scope) =>
{
var textBox =
new TextBox
{
Name = "PART_TextBox"
}.RegisterInNameScope(scope);
return new ButtonSpinner
{
Name = "PART_Spinner",
Content = textBox,
}.RegisterInNameScope(scope);
});
}
}
}
Loading…
Cancel
Save