From 55a0b5b1c633b4e1ea4b4b0aa248ad30691bfcfb Mon Sep 17 00:00:00 2001
From: Tim <47110241+timunie@users.noreply.github.com>
Date: Wed, 26 Nov 2025 18:03:14 +0100
Subject: [PATCH] feat: Handle Datavalidations on base class "Control" (#20067)
* Handle Datavalidations on base class "Control"
this removes the need to override it in any sub-classing control and also allowes developers to add validation support for other properties / controls by overriding Metadata
* Revert changes on Button.
The current behavior is that button gets disabled and until we decide if this is desired, keep this behavior.
---
.../AutoCompleteBox/AutoCompleteBox.cs | 18 ------------------
src/Avalonia.Controls/Button.cs | 3 ++-
.../CalendarDatePicker/CalendarDatePicker.cs | 11 -----------
src/Avalonia.Controls/Control.cs | 8 ++++++++
.../DateTimePickers/DatePicker.cs | 8 --------
.../DateTimePickers/TimePicker.cs | 8 --------
src/Avalonia.Controls/MenuItem.cs | 1 +
.../NumericUpDown/NumericUpDown.cs | 18 ------------------
.../Primitives/SelectingItemsControl.cs | 18 ------------------
src/Avalonia.Controls/Slider.cs | 12 ------------
src/Avalonia.Controls/TextBox.cs | 11 -----------
11 files changed, 11 insertions(+), 105 deletions(-)
diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
index f61f6ff2a1..d2fa2bea2b 100644
--- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
@@ -652,24 +652,6 @@ namespace Avalonia.Controls
base.OnApplyTemplate(e);
}
- ///
- /// Called to update the validation state for properties for which data validation is
- /// enabled.
- ///
- /// The property.
- /// The current data binding state.
- /// The current data binding error, if any.
- protected override void UpdateDataValidation(
- AvaloniaProperty property,
- BindingValueType state,
- Exception? error)
- {
- if (property == TextProperty || property == SelectedItemProperty)
- {
- DataValidationErrors.SetError(this, error);
- }
- }
-
///
/// Provides handling for the
/// event.
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index 12c778bf2e..3652acac45 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Linq;
using System.Windows.Input;
using Avalonia.Automation.Peers;
@@ -571,7 +572,7 @@ namespace Avalonia.Controls
}
}
}
-
+
internal void PerformClick() => OnClick();
private static void OnAccessKeyPressed(Button sender, AccessKeyPressedEventArgs e)
diff --git a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
index eaf632039b..e3ce49ac96 100644
--- a/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
+++ b/src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
@@ -325,17 +325,6 @@ namespace Avalonia.Controls
base.OnPropertyChanged(change);
}
- ///
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
- {
- if (property == SelectedDateProperty)
- {
- DataValidationErrors.SetError(this, error);
- }
-
- base.UpdateDataValidation(property, state, error);
- }
-
///
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index 4f3e76d487..b5f3ba57ce 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -4,6 +4,7 @@ using System.ComponentModel;
using Avalonia.Automation.Peers;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
+using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
@@ -563,6 +564,13 @@ namespace Avalonia.Controls
}
}
}
+
+ ///
+ protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
+ {
+ DataValidationErrors.SetError(this, error);
+ base.UpdateDataValidation(property, state, error);
+ }
// Since we are resetting the dispatcher instance, the callback might never arrive
internal static void ResetLoadedQueueForUnitTests()
diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs
index ac2ca3db8b..2f88e662a2 100644
--- a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs
+++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs
@@ -426,13 +426,5 @@ namespace Avalonia.Controls
{
SetCurrentValue(SelectedDateProperty, null);
}
-
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
- {
- base.UpdateDataValidation(property, state, error);
-
- if (property == SelectedDateProperty)
- DataValidationErrors.SetError(this, error);
- }
}
}
diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs
index c9e62e2cb2..ca5c43463d 100644
--- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs
+++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs
@@ -407,13 +407,5 @@ namespace Avalonia.Controls
{
SetCurrentValue(SelectedTimeProperty, null);
}
-
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
- {
- base.UpdateDataValidation(property, state, error);
-
- if (property == SelectedTimeProperty)
- DataValidationErrors.SetError(this, error);
- }
}
}
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index f250f8da43..54bae5b891 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -554,6 +554,7 @@ namespace Avalonia.Controls
return new MenuItemAutomationPeer(this);
}
+ // TODO: This is confusing for some ppl. Need to think about alternatives here.
protected override void UpdateDataValidation(
AvaloniaProperty property,
BindingValueType state,
diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
index 90cfb41c65..d9cc92f0e6 100644
--- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
+++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
@@ -441,24 +441,6 @@ namespace Avalonia.Controls
}
}
- ///
- /// Called to update the validation state for properties for which data validation is
- /// enabled.
- ///
- /// The property.
- /// The current data binding state.
- /// The current data binding error, if any.
- protected override void UpdateDataValidation(
- AvaloniaProperty property,
- BindingValueType state,
- Exception? error)
- {
- if (property == TextProperty || property == ValueProperty)
- {
- DataValidationErrors.SetError(this, error);
- }
- }
-
///
/// Called when the property value changed.
///
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 59289838bb..b1b7ae7f4e 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -569,24 +569,6 @@ namespace Avalonia.Controls.Primitives
EndUpdating();
}
- ///
- /// Called to update the validation state for properties for which data validation is
- /// enabled.
- ///
- /// The property.
- /// The current data binding state.
- /// The current data binding error, if any.
- protected override void UpdateDataValidation(
- AvaloniaProperty property,
- BindingValueType state,
- Exception? error)
- {
- if (property == SelectedItemProperty)
- {
- DataValidationErrors.SetError(this, error);
- }
- }
-
///
protected override void OnInitialized()
{
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index 4d34bd354e..2984e191b1 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -393,18 +393,6 @@ namespace Avalonia.Controls
SetCurrentValue(ValueProperty, IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue);
}
- ///
- protected override void UpdateDataValidation(
- AvaloniaProperty property,
- BindingValueType state,
- Exception? error)
- {
- if (property == ValueProperty)
- {
- DataValidationErrors.SetError(this, error);
- }
- }
-
protected override AutomationPeer OnCreateAutomationPeer()
{
return new SliderAutomationPeer(this);
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 35f1c34b5e..33cfddc4a1 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -1884,17 +1884,6 @@ namespace Avalonia.Controls
return new TextBoxAutomationPeer(this);
}
- protected override void UpdateDataValidation(
- AvaloniaProperty property,
- BindingValueType state,
- Exception? error)
- {
- if (property == TextProperty)
- {
- DataValidationErrors.SetError(this, error);
- }
- }
-
internal static int CoerceCaretIndex(AvaloniaObject sender, int value)
{
var text = sender.GetValue(TextProperty); // method also used by TextPresenter and SelectableTextBlock