Quantcast
Channel: Windows Presentation Foundation (WPF) forum
Viewing all articles
Browse latest Browse all 18858

Issue When Using INotifyDataErrorInfo with DataGrid

$
0
0

Hello,

I am using INotifyDataErrorInfo with a DataGrid to enforce cell level business rules (please see related code below).  The issue is that when an error occurs in a cell, a red text box appears around the cell border as expected, however a tooltip containing the specific error message is not displayed during a mouse hover.

I have noticed during debugging that when the "<Trigger Property="Validation.HasError" Value="False">" line of XAML code executes, "Validation.HasError" is always "False" - even when the related DataGridCell has a red border.  I suspect that the correct validation object is not being accessed.

Any insights into what may be wrong with my XAML syntax/approach would be appreciated.  

Thank you,
Chris

XAML:

<DataGrid Grid.Row="1" Grid.Column="0" Margin="10" AutoGenerateColumns="False" CanUserAddRows="False" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding EmployeeList, ValidatesOnDataErrors=True}" SelectionMode="Single"><DataGrid.CellStyle><Style TargetType="{x:Type DataGridCell}"><Style.Triggers>
// Result is always false.<Trigger Property="Validation.HasError" Value="False"><Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)/ErrorContent}" /></Trigger></Style.Triggers></Style></DataGrid.CellStyle><DataGrid.Style><Style TargetType="DataGrid"><Setter Property="AlternatingRowBackground" Value="LightGray" /></Style></DataGrid.Style><DataGrid.Columns><DataGridTextColumn Width="Auto" MinWidth="150" MaxWidth="150" Binding="{Binding FirstName, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Header="First Name" /><DataGridTextColumn Width="Auto" MinWidth="150" MaxWidth="150" Binding="{Binding LastName, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Header="Last Name" /></DataGrid.Columns></DataGrid>

EmployeeList and Employee classes:

public class EmployeeList : ObservableCollection<Employee> { public bool IsValid() { return this.Items.All(employee => employee.IsEmployeeValid()); } }

public class Employee : ViewModelBase
    {
        private readonly EmployeePresubmitValidator presubmitValidator;
        private readonly EventAggregator eventAggregator;

        private string firstName;
        private string lastName;

        public Employee(
                        EmployeePresubmitValidator presubmitValidator,
                        EventAggregator eventAggregator)
        {
            this.presubmitValidator = presubmitValidator;
            this.eventAggregator = eventAggregator;

            this.Initialize();
        }

        public string FirstName
        {
            get
            {
                return this.firstName;
            }

            set
            {
                this.SetProperty(ref this.firstName, value);
                this.ValidatePropertyPresubmit("FirstName");
            }
        }

        public string LastName
        {
            get
            {
                return this.lastName;
            }

            set
            {
                this.SetProperty(ref this.lastName, value);
                this.ValidatePropertyPresubmit("LastName");
            }
        }

        public bool IsEmployeeValid()
        {
            return this.presubmitValidator.Validate(this).IsValid;
        }

        public override void ValidateViewModelPresubmit()
        {
            var validationResults = this.presubmitValidator.Validate(this);
            this.RefreshErrors(validationResults);
        }

        public override void ValidatePropertyPresubmit(string propertyName)
        {
            var validationResults = this.presubmitValidator.Validate(this);
            this.RefreshErrors(propertyName, validationResults);
        }

        private void Initialize()
        {
            this.ValidateViewModelPresubmit();
        }
 }

The Employee class implements ViewModelBase which, in turn, implements INotifyDataErrorInfo:

public abstract class ViewModelBase : BindableBase, INotifyDataErrorInfo { // Public Events public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; // Public Properties public bool HasErrors => this.ValidationErrors.Count > 0; protected Dictionary<string, List<string>> ValidationErrors { get; } = new Dictionary<string, List<string>>(); // Public Abstract Methods public abstract void ValidateViewModelPresubmit(); public abstract void ValidatePropertyPresubmit(string propertyName); // Public Methods public IEnumerable GetErrors(string propertyName) { List<string> currentErrors; return this.ValidationErrors.TryGetValue(propertyName, out currentErrors) ? currentErrors : null; }
public void RefreshErrors(ValidationResult validationResult) { this.ClearAllErrors(); this.AddErrors(validationResult); } public void RefreshErrors(string propertyName, ValidationResult result) { this.ClearPropertyErrors(propertyName); this.AddPropertyErrors(propertyName, result); } // Implement INotifyDataErrorInfo public void RaiseErrorsChanged(string propertyName) { this.ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); }
private void ClearAllErrors() { this.ValidationErrors.Clear(); } private void AddErrors(ValidationResult result) { foreach (var error in result.Errors) { this.AddError(error.PropertyName, error.ErrorMessage); } } private void AddError(string propertyName, string error) { if (!this.ValidationErrors.ContainsKey(propertyName)) { this.ValidationErrors[propertyName] = new List<string>(); } if (this.ValidationErrors[propertyName].Contains(error)) { return; } this.ValidationErrors[propertyName].Insert(0, error); this.RaiseErrorsChanged(propertyName); } private void ClearPropertyErrors(string propertyName) { if (!this.ValidationErrors.ContainsKey(propertyName)) { return; } this.ValidationErrors[propertyName].Clear(); this.ValidationErrors.Remove(propertyName); } private void AddPropertyErrors(string propertyName, ValidationResult result) { foreach (var error in result.Errors.Where(error => error.PropertyName == propertyName)) { this.AddError(propertyName, error.ErrorMessage); } } }








Viewing all articles
Browse latest Browse all 18858

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>