I'd like to implement MVVM Toolkit's validation method using reusable controls. My problem is that the warning highlight appears on the whole control, like this:
If I don't use reusable controls, it works correctly:
The reusable control looks like this:
ValidationTextBox.xaml
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="275" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=HeaderText}" />
<TextBox
Grid.Row="1"
Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=TextBoxContent}" />
</Grid>
</StackPanel>
ValidationTextBox.xaml.cs
public partial class ValidationTextBox : UserControl
{
public static readonly DependencyProperty HeaderTextProperty =
DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(ValidationTextBox), new PropertyMetadata(default(string)));
public string HeaderText
{
get => (string)GetValue(HeaderTextProperty);
set => SetValue(HeaderTextProperty, value);
}
public static readonly DependencyProperty TextBoxContentProperty =
DependencyProperty.Register(nameof(TextBoxContent), typeof(string), typeof(ValidationTextBox), new FrameworkPropertyMetadata(default(string)));
public string TextBoxContent
{
get { return (string)GetValue(TextBoxContentProperty); }
set { SetValue(TextBoxContentProperty, value); }
}
public ValidationTextBox()
{
InitializeComponent();
}
}
And the view and view model I use it:
RegisterView.xaml
...
<controls:ValidationTextBox
Grid.Row="1"
Grid.Column="2"
MaxWidth="300"
Margin="10,10,0,0"
HeaderText="First name"
TextBoxContent="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
...
RegisterViewModel.cs
public partial class RegisterViewModel : ViewModelBase
{
...
[ObservableProperty]
[Required]
[MinLength(2)]
private string? _firstName;
...
}
As you can see, I use MVVM Toolkit's source generator for this property and their validation method. ViewModelBase
inherits from ObservableValidator
which implements INotifyDataErrorInfo
.
Validation is working correctly, meaning whenever I type 2 characters, the error highlight disappears and reappears when I enter less than 2 characters.
For the 2nd example, where the validation highlight is showing correctly, I created a property the same way I did for first name and I simply bound the text box's text property to the UserName
property.
Is it possible to make validation work with reusable controls or a completely different approach is needed in this case?
Since the validating
Binding
is the one that is set from the view model to theUserControl
, the binding engine will set the attached property Validation.HasError to true for the UserControl (the binding target). Hence the error template is adorning theUserControl
and not a particular internal element.You must configure the
UserControl
to instruct the binding engine to adorn a different element instead. You can use the attachedValidation.ValidationAdornerSiteFor
property:I just like to point out that it is technically correct to apply the error template on the complete
UserControl
.To change this behavior, you must explicitly validate the internal bindings (see example below).
Since
Validation.ValidationAdornerSiteFor
only allows to set a single alternative element, you would have to manually delegate the validation error, in case theUserControl
has multiple validated inputs.The following example shows how to route the external binding validation error to the corresponding internal input element:
MyUserControl.xaml.cs
MyUserControl.xaml