Is it possible to have BindingGroup.CommitEdit/ValidateWithoutUpdate always run all Binding validation rules?
Here’s a (somewhat) pared-down example of some code I have that’s attempting to make use of a BindingGroup:
XAML:
<Window x:Class="BindingGroupQuandary.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BindingGroupQuandary"
Title="Binding Group Test" Width="400" Height="400" MinWidth="400" MinHeight="400">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<GroupBox Header="Items">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView Name="dataList">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="First Property" DisplayMemberBinding="{Binding FirstProperty}" />
<GridViewColumn Header="Second Property" DisplayMemberBinding="{Binding SecondProperty}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="1" Content="Add Item" Click="add_Click" HorizontalAlignment="Left" Margin="0,5,0,5" />
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Name="editControls" Header="Edit Item">
<GroupBox.BindingGroup>
<BindingGroup Name="editItemBindings"/>
</GroupBox.BindingGroup>
<StackPanel>
<Label Content="First Property (Required)"/>
<TextBox>
<TextBox.Text>
<Binding Path="FirstProperty">
<Binding.ValidationRules>
<local:NotEmptyValidationRule ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Label Content="Second Property (Required)"/>
<TextBox>
<TextBox.Text>
<Binding Path="SecondProperty">
<Binding.ValidationRules>
<local:NotEmptyValidationRule ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Button Content="Commit" Click="commit_Click" HorizontalAlignment="Left" Margin="0,10,0,0"/>
</StackPanel>
</GroupBox>
</Grid>
</Window>
Code-behind:
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
namespace BindingGroupQuandary
{
class SomeData
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
}
class NotEmptyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
string textValue = (value as string);
ValidationResult result;
if (string.IsNullOrWhiteSpace(textValue))
{
result = new ValidationResult(false, "The field must contain a text value and cannot be empty.");
}
else
{
result = new ValidationResult(true, null);
}
return result;
}
}
public partial class MainWindow : Window
{
private ObservableCollection<SomeData> _items = new ObservableCollection<SomeData>();
public MainWindow()
{
InitializeComponent();
dataList.ItemsSource = _items;
}
private void add_Click(object sender, RoutedEventArgs e)
{
editControls.DataContext = (new SomeData() { FirstProperty = "This property has an initial value." });
editControls.BindingGroup.BeginEdit();
}
private void commit_Click(object sender, RoutedEventArgs e)
{
SomeData current = editControls.DataContext as SomeData;
if (current != null)
开发者_StackOverflow中文版 {
if (editControls.BindingGroup.CommitEdit())
{
_items.Add(current);
editControls.DataContext = null;
}
}
}
}
}
The effect I’m looking for is that:
- I click “Add Item” to bind an object to the editing controls in the lower half of the window (which normally aren’t visible until the data context is supplied in the actual application).
- I intentionally don’t set ValidatesOnTargetUpdated on either property binding because I don’t necessarily want to show any error adorners yet; the field text already hints that the fields are required.
- When I do click Commit, I want the BindingGroup to re-check all of the validation rules to catch any fields that are still empty and show the error adorners at that point.
Unfortunately, using the sample code above, if I click “Add” and then click “Commit” immediately without filling in the “Second Property” field or changing anything, the binding group doesn’t call my validation rules at all; CommitEdit returns “true” and the object is passed through to the underlying collection. Calling ValidateWithoutUpdate also just returns “true.” My tests with the application seem to suggest that CommitEdit and ValidateWithoutUpdate actually only call validation rules where:
- The rule is currently false/invalid.
- The rule is currently valid but the value has changed.
The methods don’t seem to reevaluate valid rules for which the value hasn’t changed. I suppose this behavior makes sense (and perhaps this is just a general binding behavior?), but it seems to contradict the documentation which states, for CommitEdit:
Runs all the ValidationRule objects and updates the binding sources if all validation rules succeed.
I imagine the validation rules mentioned in that statement could refer only to the top-level rules in the BindingGroup itself and not the validation rules in the individual bindings. At any rate, my actual question is: is it possible to get the BindingGroup to re-check all of the validation rules in this example; if not, could I do that directly by using the BindingExpressions collection? Or, should I just give up and rely on ValidatesOnTargetUpdated (perhaps paired with a less glaring adorner template) to set the initial rule states correctly when the data context is established?
精彩评论