gpt4 book ai didi

WPF DataGrid 验证错误未清除

转载 作者:行者123 更新时间:2023-12-03 07:50:54 24 4
gpt4 key购买 nike

所以我有一个 WPF DataGrid ,绑定(bind)到 ObservableCollection .该集合通过 IDataErrorInfo 对其成员进行了验证.如果我以一种无效的方式编辑一个单元格,然后在按 Enter 之前将其移开,然后返回并使其有效,则该单元格将停止显示无效,但是,“!”行首仍然存在,ToolTip将引用先前的无效值。

最佳答案

最初的问题来自 2011 年,Datagrids Validation-System 仍然存在问题,无法使用。我花了 2 天时间试图找到一个解决方案来完成以下工作:

  • 我的模型项实现 INotifyDataErrorInfo 和 INotifyPropertyChanged
  • 它们位于绑定(bind)到 DataGrid
  • 的 BindingList 中
  • DataGrid 应该显示来自用户输入的验证错误以及来自不同来源的模型更改
  • RowValidation-Error-mark 应该显示任何单元格是否有验证错误,否则隐藏,无论用户当前是否正在编辑、提交或对行不做任何事情
  • 无效单元格应显示带有错误文本的工具提示
  • 没有错误或故障

  • 实现此行为的唯一方法是放弃 RowValidation 和 CellValidation,而使用 RowHeader 和 Styles。我从网络上的各种来源复制了以下代码。我还不能对此进行广泛的测试,但乍一看它看起来很有希望。
    在 DataGrids XAML 中:
    <DataGrid ... local:DataGridProps.ShowCellErrorBorder="False">
    <DataGrid.Resources>
    <local:DataGridValidationConverter x:Key="DataGridValidationConverter" />
    <Style TargetType="TextBlock" x:Key="errTemplate">
    <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
    <Setter Property="ToolTip"
    Value="{Binding Path=(Validation.Errors)[0].ErrorContent}
    RelativeSource={x:Static RelativeSource.Self}, "/>
    <Setter Property="Background" Value="LightSalmon"/>
    </Trigger>
    </Style.Triggers>
    </Style>
    </DataGrid.Resources>

    <DataGrid.RowValidationErrorTemplate>
    <ControlTemplate>

    </ControlTemplate>
    </DataGrid.RowValidationErrorTemplate>

    <DataGrid.RowHeaderTemplate>
    <DataTemplate>
    <Grid Margin="0,-2,0,-2"
    Visibility="{Binding Path=DataContext.HasErrors,
    RelativeSource={RelativeSource Mode=FindAncestor,
    AncestorType={x:Type DataGridRow}},
    Converter={StaticResource DataGridValidationConverter},
    FallbackValue=Hidden}">
    <Ellipse StrokeThickness="0" Fill="Red"
    Width="{Binding Path=FontSize,
    RelativeSource={RelativeSource Mode=FindAncestor,
    AncestorType={x:Type DataGridRow}}}"
    Height="{Binding Path=FontSize,
    RelativeSource={RelativeSource Mode=FindAncestor,
    AncestorType={x:Type DataGridRow}}}" />
    <TextBlock Text="!" FontWeight="Bold" Foreground="White" HorizontalAlignment="Center"
    FontSize="{Binding Path=FontSize,
    RelativeSource={RelativeSource Mode=FindAncestor,
    AncestorType={x:Type DataGridRow}}}" />
    </Grid>
    </DataTemplate>
    </DataGrid.RowHeaderTemplate>

    <DataGrid.Columns>
    <DataGridTextColumn Header="Vorname" ElementStyle="{StaticResource errTemplate}"
    Binding="{Binding Path=Vorname,
    ValidatesOnNotifyDataErrors=True,
    NotifyOnValidationError=True}" />
    ...
    </DataGrid.Columns>
    </DataGrid>
    数据网格验证转换器:
    public class DataGridValidationConverter : IValueConverter
    {

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
    if ((bool)value)
    return Visibility.Visible;
    else
    return Visibility.Hidden;
    }


    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
    throw new NotImplementedException();
    }
    }
    数据网格 Prop :
    public class DataGridProps
    {
    public static readonly DependencyProperty ShowCellErrorBorderProperty = DependencyProperty.RegisterAttached(
    "ShowCellErrorBorder", typeof(bool), typeof(DataGridProps), new PropertyMetadata(true, ShowCellErrorBorderPropertyChangedCallback));

    public static bool GetShowCellErrorBorder(DependencyObject element)
    {
    return (bool)element.GetValue(ShowCellErrorBorderProperty);
    }

    public static void SetShowCellErrorBorder(DependencyObject element, bool value)
    {
    element.SetValue(ShowCellErrorBorderProperty, value);
    }

    private static void ShowCellErrorBorderPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
    if (GetShowCellErrorBorder(dependencyObject)) return;
    var dg = dependencyObject as DataGrid;
    if (null != dg)
    {
    dg.Loaded += (sender, args) =>
    {
    var scrollView = dg.Template.FindName("DG_ScrollViewer", dg) as ScrollViewer;
    if (null == scrollView) return;
    var scrollContent = scrollView.Template.FindName("PART_ScrollContentPresenter", scrollView) as ScrollContentPresenter;
    if (null == scrollContent) return;
    scrollContent.AdornerLayer.Visibility = Visibility.Hidden;
    };
    }
    }
    }
    模型的实现:
    public Model()
    {
    if (Vorname == null)
    Vorname = "";
    ...

    errorsByPropertyName = new Dictionary<string, List<string>>();
    this.PropertyChanged += Model_PropertyChanged;
    ForceRevalidation(null);
    }

    private string _vorname;
    public string Vorname { get => _vorname; set => SetField(ref _vorname, value); }
    ...

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(propertyName);
    return true;
    }

    private Dictionary<string, List<string>> errorsByPropertyName;

    public void ForceRevalidation(string propertyName)
    {
    if (string.IsNullOrEmpty(propertyName))
    {
    foreach (PropertyInfo property in GetType().GetProperties())
    {
    ValidateProperty(property.Name);
    }
    }
    else
    {
    ValidateProperty(propertyName);
    }
    }

    protected virtual void OnErrorsChanged(string propertyName)
    {
    ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
    OnPropertyChanged(nameof(HasErrors));
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public bool HasErrors => errorsByPropertyName.Any();

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
    if (propertyName == null)
    propertyName = "";
    return errorsByPropertyName.ContainsKey(propertyName) ? errorsByPropertyName[propertyName] : null;
    }

    private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
    ValidateProperty(e.PropertyName);
    }

    protected virtual void ValidateProperty(string propertyName)
    {
    if (propertyName == null)
    propertyName = "";

    ClearErrors(propertyName);

    switch (propertyName)
    {
    case nameof(Vorname):
    if (string.IsNullOrWhiteSpace(Vorname))
    AddError(propertyName, propertyName + " is empty");
    break;
    ...
    default:
    break;

    }
    }

    protected void AddError(string propertyName, string error)
    {
    if (!errorsByPropertyName.ContainsKey(propertyName))
    errorsByPropertyName[propertyName] = new List<string>();

    if (!errorsByPropertyName[propertyName].Contains(error))
    {
    errorsByPropertyName[propertyName].Add(error);
    OnErrorsChanged(propertyName);
    }
    }

    protected void ClearErrors(string propertyName)
    {
    if (errorsByPropertyName.ContainsKey(propertyName))
    {
    errorsByPropertyName.Remove(propertyName);
    OnErrorsChanged(propertyName);
    }
    }

    我从我更大的 Model-Base-Class 中创建了这个最小的例子,希望我在这里得到了这方面的所有重要信息。

    关于WPF DataGrid 验证错误未清除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5099039/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com