如果出现错误并在DataGridCell上获取错误模板,请阻止DataGridCell失去焦点?

时间:2015-09-17 16:39:46

标签: c# wpf validation datagrid idataerrorinfo

是否可以在编辑模式下停止DataGridCell,其中包含由绑定对象的属性设置器中的异常引起的验证错误 - 从失去焦点到用户a)更正该错误,或​​b )按'Esc'恢复他们的更改?

此外,虽然我可以显示该行的验证模板,但我似乎无法为DataGridCell本身启动它。

这是我们的测试风格。这有效......

<Style TargetType="{x:Type DataGridRow}">

    <Style.Triggers>

        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
            <Setter Property="Background" Value="Yellow"/>
        </Trigger>

    </Style.Triggers>

</Style>

这不......

<Style TargetType="{x:Type DataGridCell}">

    <Style.Triggers>

        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
            <Setter Property="Background" Value="Green"/>
        </Trigger>

    </Style.Triggers>

</Style>

以下是我们的专栏:

<DataGrid.Columns>

    <DataGridTextColumn x:Name="NameColumn"
        Header="Name"
        Binding="{Binding Name, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}"
        Width="*" />

    <DataGridTextColumn x:Name="ValueColumn"
        Header="Value"
        Binding="{Binding Value, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}"
        Width="*" />

</DataGrid.Columns>

1 个答案:

答案 0 :(得分:1)

  1. 是否可以在编辑模式下停止DataGridCell,并且验证错误 - 由绑定对象的属性设置器中的异常引起 - 从失去焦点到用户a)纠正该错误,或者b)按'Esc'来恢复他们的更改?
  2. 是的,有可能。我们必须检查ViewModel的HasErrors属性,其中可以生成错误并相应地设置其值。

    这个答案使用了我在这里发布的解决方案中提出的概念:

    WPF MVVM Validation DataGrid and disable CommandButton

    DataGridCellTemplate xaml代码:

        <DataGridTemplateColumn.CellTemplate>                        
                <DataTemplate>                            
                        <TextBox VerticalAlignment="Stretch" VerticalContentAlignment="Center"  Loaded="TextBox_Loaded" PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus" PreviewKeyUp="TextBox_PreviewKeyUp">
                                <TextBox.Triggers>
                                </TextBox.Triggers>
                                    <TextBox.Text>
                                    <Binding Path="ID" UpdateSourceExceptionFilter="ReturnExceptionHandler" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" >
                                        <Binding.ValidationRules>
                                            <v:CustomValidRule ValidationStep="ConvertedProposedValue"></v:CustomValidRule>
                                        </Binding.ValidationRules>
                                    </Binding>
                            </TextBox.Text>
                        </TextBox>
                    </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
    

    MainWindow.cs

            ViewModel vm = new ViewModel();
    
            public MainWindow()
            {        
              InitializeComponent();
              DataContext = vm; 
            }
    
        // This is wrong and will result in StackOverflow exception
        private void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
                 if (vm.HasErrors)
                {
                   TextBox b = (TextBox)sender;
                   b.Focus();
                 }
        }
    
            private void TextBox_PreviewLostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
            {    
                TextBox b = (TextBox)sender;
    
                if (vm.HasErrors)
                {
                    e.Handled = true;
    
                    b.Focus();
                    b.CaptureMouse();
                }
                else {
                    e.Handled = false;
                    b.ReleaseMouseCapture();
                }
            }               
    
            private void TextBox_PreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
            {
                if (e.Key == System.Windows.Input.Key.Escape)
                {
                    TextBox b = (TextBox)sender;
                    b.Undo();
                }
            }
    

    现在,我们需要检查错误并在这些位置设置ViewModel的HasErrors属性。

    错误可以按此顺序在3个级别生成;

    一个。更新值时绑定引擎抛出的异常

    湾值到达ViewModel之前的自定义验证。

    ℃。在ViewModel中针对DataBase或其他方式进行验证。

    一个。当输入需要数字的字符时,通常会遇到这种情况。这是使用UpdateSourceExceptionFilter处理的。 输出窗口显示如下:

    System.Windows.Data Error: 7 : ConvertBack cannot convert value 'a' (type 'String'). BindingExpression:Path=ID; DataItem='Class1' (HashCode=66068479); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String') FormatException:'System.FormatException: Input string was not in a correct format.
       at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
    

    我们的UpdateSourceExceptionFilterCallback:我们在TextBox中设置了这个。

          object ReturnExceptionHandler(object bindingExpression, Exception exception)
            {
                vm.HasErrors = true;
    
                return "This is from the UpdateSourceExceptionFilterCallBack.";
            }
    

    湾我们使用我们插入的验证规则。但是我们的ViewModel将如何了解这些规则?我们将维护这些规则的可观察集合并将事件处理程序附加到这些规则,因此它们可以通知它们的ViewModel,就像我们实现INotifyPropertyChanged以通知Binding引擎一样。 我们将规则添加到vm中, MainWindow.cs

            private void TextBox_Loaded(object sender, RoutedEventArgs e)
            {
                Collection<ValidationRule> rules= ((TextBox)sender).GetBindingExpression(TextBox.TextProperty).ParentBinding.ValidationRules;
    
                foreach (ValidationRule rule in rules)
                    vm.Rules.Add(rule);
            }
    

    ViewModel.cs

    void Rules_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                foreach (var v in e.NewItems)
                    ((IViewModelUIRule)v).ValidationDone += ViewModel_ValidationDone;
            }
    
    
    
    void ViewModel_ValidationDone(object sender, ViewModelUIValidationEventArgs e)
            {
                HasErrors = e.IsValid;
            }
    

    ℃。在最后一级检查错误。我们处理集合中所有绑定对象的PropertyChanged事件。这个集合我们绑定到DataGrid。

    void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (((Class1)sender).ID > 7)
                    HasErrors = true;
                else
                    HasErrors = false;
            }
    

    <强> 2。此外,虽然我可以显示该行的验证模板,但我似乎无法为DataGridCell本身启动它。

    DataGridRow具有ValidationErrorTemplate,而DataGridCell则没有。

相关问题