I have a form with a GroupBox, and in it I have a number of controls (Checkboxes, TextBoxes, and Comboboxes).
The form is bound to a view model that implements IDataErrorInfo on its properties, and when the user enters an invalid value into a control, IDataInfo returns an invalid result, and the control is surrounded by the usual red box, and the error message is displayed at the bottom of the form.
The thing is, the GroupBox is intended to indicate a set of mandatory values. The user is required to check at least one of the checkboxes in the group. Failure to do so isn’t a error on an individual control, it’s an error on the group. So I’ve added a BindingGroup to the GroupBox, and added a ValidationRule that returns an error if nothing is selected. And that works fine. If nothing is selected the GroupBox is surrounded by the usual red box, and the error message is displayed at the bottom of the form.
My problem is that if one of the controls in the GroupBox fails validation, I get two red boxes – one around the control and one around the GroupBox. And I get two error messages in the list at the bottom of the form.
How do I keep the BindingGroup from reporting errors on everything that is contained within the group?
EDITED:
A simple example – this doesn’t display Validation.Errors, but you can see that the StackPanel is highlighted as having failed validation, when the contained TextBox does.
The XAML:
<Window
x:Class="BugHunt5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BugHunt5"
Title="MainWindow"
Height="350"
Width="525"
>
<GroupBox
Margin="20"
Header="This is my group"
x:Name="MyGroupBox"
>
<StackPanel>
<StackPanel.BindingGroup>
<BindingGroup NotifyOnValidationError="True">
</BindingGroup>
</StackPanel.BindingGroup>
<TextBox
Height="30"
Width="100"
>
<TextBox.Text>
<Binding
NotifyOnValidationError="True"
ValidatesOnDataErrors="True"
Path="MyString"
UpdateSourceTrigger="PropertyChanged"
>
<Binding.ValidationRules>
<local:NoDecimalsValidationRule ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
</GroupBox>
</Window>
The C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel("This should be an integer");
}
}
public class ViewModel
{
public string MyString
{ get; set; }
public ViewModel(string mystring)
{ this.MyString = mystring; }
}
public class NoDecimalsValidationRule : ValidationRule
{
public override ValidationResult Validate(object value,
System.Globalization.CultureInfo cultureInfo)
{
string myString = value as string;
int result;
if (!Int32.TryParse(myString, out result))
return new ValidationResult(false, "Must enter integer");
return new ValidationResult(true, null);
}
}
ViewModel.cs
MainWindow.xaml
MainWindow.xaml.cs
Key things: