Invalid behavior of the icon in row header in data grid when record implements INotifyDataErrorInfo
See original GitHub issueDescription
- Add DataGrid
- Set as ItemsSource ObservableCollection with records which implement INotifyDataErrorInfo and INotifyPropertyChanged and with errors after initialization
- Run app
- Textbox has red border but icon is missing (strange but I can live with that)
- Double click on cell (icon in row header is shown)
- fix value and hit enter
- Textbox hasn’t got red border (PASS) but icon with tooltip with original error is still there (FAIL)
Am I implemented it incorrectly? Or it’s an issue in header style?
Environment
- .NET Framework 4.7.2
- Windows 10 1903
Nuget libraries
- MahApps.Metro 1.6.5
- FluentValidation 8.5.1 (for validation)
- Fody 6.0.4
- PropertyChanged.Fody 3.1.3 (for autiomatic notifications)
- Caliburn.Micro 3.2.0 (only base class)
Code
using Caliburn.Micro;
using FluentValidation;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
namespace WpfDataGridValidation
{
public class MainWindowViewModel : Conductor<IScreen>.Collection.AllActive
{
public MainWindowViewModel()
{
var validator = new MyRecordValidator();
var record = new MyRecord(validator);
Records = new ObservableCollection<MyRecord>(Enumerable.Repeat(record, 1));
}
public ObservableCollection<MyRecord> Records { get; set; }
}
public class MyRecord : Caliburn.Micro.PropertyChangedBase, INotifyDataErrorInfo
{
private readonly FluentValidation.AbstractValidator<MyRecord> _validator;
public MyRecord(FluentValidation.AbstractValidator<MyRecord> validator)
{
_validator = validator;
Validate();
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool HasErrors => Errors.Any();
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
return null;
if (Errors.TryGetValue(propertyName, out List<string> value))
return value;
return Enumerable.Empty<string>();
}
private void Validate()
{
if (_validator == null)
return;
var previousKeys = Errors.Select(x => x.Key).ToList();
Errors = _validator.Validate(this)
.Errors
.GroupBy(x => x.PropertyName)
.ToDictionary(x => x.Key, x => x.Select(y => y.ErrorMessage).ToList());
if (ErrorsChanged == null)
return;
foreach (var key in Errors.Keys)
ErrorsChanged.Invoke(this, new DataErrorsChangedEventArgs(key));
foreach (var key in previousKeys.Except(Errors.Select(x => x.Key)))
ErrorsChanged.Invoke(this, new DataErrorsChangedEventArgs(key));
}
public override void NotifyOfPropertyChange([CallerMemberName] string propertyName = null)
{
if (propertyName != null && propertyName != nameof(Errors) && propertyName != nameof(HasErrors))
Validate();
base.NotifyOfPropertyChange(propertyName);
}
public string Name { get; set; }
public Dictionary<string, List<string>> Errors { get; private set; } = new Dictionary<string, List<string>>();
}
public class MyRecordValidator : FluentValidation.AbstractValidator<MyRecord>
{
public MyRecordValidator()
{
RuleFor(x => x.Name).NotEmpty();
}
}
}
MainWindow view
<Window x:Class="WpfDataGridValidation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfDataGridValidation"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<DataGrid
x:Name="dataGrid"
ItemsSource="{Binding Records}"
CanUserAddRows="False"
CanUserSortColumns="False"
CanUserResizeColumns="False"
CanUserResizeRows="False"
CanUserReorderColumns="False"
SelectionMode="Single"
SelectionUnit="Cell"
AutoGenerateColumns="False"
VerticalAlignment="Top"
HorizontalAlignment="Left"
GridLinesVisibility="All"
VirtualizingStackPanel.VirtualizationMode="Standard"
HeadersVisibility="All"
RowHeaderWidth="40"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, NotifyOnValidationError=True,ValidatesOnNotifyDataErrors=True}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow bode behind
using System.Windows;
namespace WpfDataGridValidation
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
}
App.xaml
<Application x:Class="WpfDataGridValidation.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfDataGridValidation"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Green.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Issue Analytics
- State:
- Created 4 years ago
- Comments:16
Top Results From Across the Web
c# - DataGridRow error indicator not working with ...
I'm attempting to update my ViewModel to use INotifyDataErrorInfo instead of IDataErrorInfo and am running into the following problem:.
Read more >How to: Implement Validation with the DataGrid Control
When a user enters an invalid value, a red circle with a white exclamation mark appears in the row header. This occurs for...
Read more >TableView Properties | WPF Controls
Gets or sets whether column headers are automatically scrolled once a user drags a column header to the View's left or right. This...
Read more >WinForms DataGrid | DataGridView in C# | Syncfusion
The high performance WinForms datagrid control displays tabular and hierarchical data. It supports sorting, grouping, filtering, dragand drop the rows, etc.
Read more >ComponentSource News | Grid Components - RSSing.com
INotifyDataErrorInfo Validation Support - The WPF Data Grid and TreeList controls automatically display validation errors within data source objects that ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Hi @timunie I updated my demo with my custom style and everything is working with INotifyDataErrorInfo (second data grid). I used INotifyDataErrorInfo.HasErrors and custom property Error. Probably style should be moved to separate file. Download changes and check it.
I had a problem to use “MahApps.Brushes.Controls.Validation” and “MahApps.Brushes.Text.Validation” styles so I copied it manually. I’m not a fan of this solutions but I don’t see a better way for INotifyDataErrorInfo.
Btw I didn’t tested it with .NET Core - maybe they fixed this interface.
I tested DataGrid with IDataErrorInfo. Everything is working when UpdateSourceTrigger is set to LostFocus. Binding mode can’t be set to TwoWay but we can use Default and control finally use TwoWay as expected. Also I tested it with my implementation of ICustomTypeDescriptor and wverything is correct.
I was not able to get working example for INotifyDataErrorInfo interface. I suspect that something is wrong with this interface ant it can’t work with DataGrid.
For now I think that we can close this thread. @timunie once again thanks for help!