I have a custom TextBox that adds MinMaxValidationRule when both Min and Max properties are set
public class TextBox2 : TextBox
{
public static readonly DependencyProperty MinProperty = DependencyProperty.Register(
nameof(Min), typeof(double?), typeof(TextBox2),
new PropertyMetadata(null, MinMaxChangeCallback));
public double? Min
{
get => (double?)GetValue(MinProperty);
set => SetValue(MinProperty, value);
}
public static readonly DependencyProperty MaxProperty = DependencyProperty.Register(
nameof(Max), typeof(double?), typeof(TextBox2),
new PropertyMetadata(null, MinMaxChangeCallback));
public double? Max
{
get => (double?)GetValue(MaxProperty);
set => SetValue(MaxProperty, value);
}
private static void MinMaxChangeCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox2 = (TextBox2)d;
if (textBox2.Min == null || textBox2.Max == null)
return;
var binding = textBox2.GetBindingExpression(TextProperty);
var validationRules = binding
.ParentBinding
.ValidationRules;
validationRules.Clear();
var minMaxValidationRule = new MinMaxValidationRule((double)textBox2.Min, (double)textBox2.Max)
{
ValidatesOnTargetUpdated = true
};
validationRules.Add(minMaxValidationRule);
binding.UpdateTarget(); // triggers the validation rule
}
}
The validation rule is defined as follows
public class MinMaxValidationRule : ValidationRule
{
public double Min { get; }
public double Max { get; }
public MinMaxValidationRule(double min, double max)
{
Min = min;
Max = max;
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (double.TryParse((string)value, out var d)
&& d <= Max
&& d >= Min)
return ValidationResult.ValidResult;
return new ValidationResult(false, $"Value must be in [{Min},{Max}]");
}
}
I've created a ItemsControl to display a list of ItemInfo objects
<ItemsControl
Margin="8"
ItemsSource="{Binding ItemInfos}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type testApp:ItemInfo}">
<testApp:TextBox2
Style="{StaticResource MaterialDesignOutlinedTextBox}"
Width="400"
Margin="12"
Padding="8"
Min="{Binding Min}"
Max="{Binding Max}"
Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
ItemInfos = new()
{
new()
{
Min = 0,
Max = 100,
Value = 50
},
new()
{
Min = 200,
Max = 300,
Value = 250
},
};
}
public List<ItemInfo> ItemInfos { get; }
}
public class ItemInfo
{
public double Min { get; set; }
public double Max { get; set; }
public double Value { get; set; }
}
When writing "2" in the first TextBox (changing the value from 50 to 502), WPF is using the validation rule of the second textBox, but I expect that each TextBox uses its own ValidationRule.
Any idea on how to fix this?

This seems to be a known limitation when using Templates. There is a workaround to this, by using another override of
Validateof the ValidationRule so that you can access the control and the updated value.You can edit the MinMaxValidationRule class as follow
Now since we read the current value of the Min and Max property, you don't need the
MinMaxChangeCallbackso you can just add the Validation rule on the loaded event.