New to Telerik UI for .NET MAUI? Start a free 30-day trial

.NET MAUI DataGrid Validation Command

The .NET MAUI DataGrid control provides a validation command that has an entry point for validating cells content. The execution parameter is of type ValidateCellContext and exposes the following properties:

  • CellInfo—Gets the cell information associated with the operation.
  • Errors—Gets or sets the errors (if any) that occurred during the validation.

Example

Here is an example how the DataGrid ValidateCell command works:

1. Create a Data class (the business object) that inherits from the INotifyDataErrorInfo and INotifyPropertyChanged interfaces. For demonstration purposes, the example will do the validation through the INotifyDataErrorInfo interface.

public class Data : INotifyDataErrorInfo, INotifyPropertyChanged
{
    private Dictionary<string, HashSet<object>> errors = new Dictionary<string, HashSet<object>>();
    private string country;

    public string Country
    {
        get
        {
            return this.country;
        }

        set
        {
            this.country = value;

            if (this.country.Length > 15)
            {
                this.AddError("Country", string.Format("Country too long", new DateTime()));
            }
            else
            {
                this.RemoveErrors("Country");
            }

            this.OnPropertyChanged("Country");
        }
    }

    public string Capital { get; set; }

    public bool HasErrors
    {
        get
        {
            return this.errors.Count > 0;
        }
    }

    public IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            return this.errors.SelectMany(c => c.Value);
        }

        HashSet<object> propertyErrors;

        this.errors.TryGetValue(propertyName, out propertyErrors);

        return propertyErrors ?? Enumerable.Empty<object>();
    }

    protected virtual void AddError(string propertyName, object errorMessage)
    {
        HashSet<object> propertyErrors;

        if (!this.errors.TryGetValue(propertyName, out propertyErrors))
        {
            propertyErrors = new HashSet<object>();
            this.errors.Add(propertyName, propertyErrors);

            propertyErrors.Add(errorMessage);

            this.OnErrorsChanged(propertyName);
        }
        else
        {
            if (!propertyErrors.Contains(errorMessage))
            {
                propertyErrors.Add(errorMessage);
                this.OnErrorsChanged(propertyName);
            }
        }
    }

    protected virtual void RemoveErrors(string propertyName = null)
    {
        if (string.IsNullOrEmpty(propertyName))
        {
            if (this.errors.Count > 0)
            {
                this.errors.Clear();
                this.OnErrorsChanged(propertyName);
            }
        }
        else
        {
            if (this.errors.Remove(propertyName))
            {
                this.OnErrorsChanged(propertyName);
            }
        }
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    protected virtual void OnErrorsChanged(string propertyName)
    {
        if (this.ErrorsChanged != null)
        {
            this.ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

2. Create a ViewModel with a collection of Data objects:

public class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Data> Items { get; set; }
    public ViewModel()
    {
        this.Items = new ObservableCollection<Data>()
        {
                new Data { Country = "India", Capital = "New Delhi"},
                new Data { Country = "South Africa", Capital = "Cape Town"},
                new Data { Country = "Nigeria", Capital = "Abuja" },
                new Data { Country = "Singapore", Capital = "Singapore" }
        };
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

3. Handle the CellTap action as a Command. First, create a class that inherits from the DataGridCommand and set its Id property. You will also need to override the CanExecute and Execute methods as demonstrated in the example below:

public class ValidateCellCommand : DataGridCommand
{
    Grid grid;
    public ValidateCellCommand(Grid grid)
    {
        this.Id = DataGridCommandId.ValidateCell;
        this.grid = grid;
    }

    public override void Execute(object parameter)
    {
        var context = (ValidateCellContext)parameter;
        this.grid.IsVisible = context.Errors.Count > 0;
    }
}

4. Set the BindingContext to be the ViewModel and add this command to the Commands collection of the RadDataGrid instance:

this.BindingContext = new ViewModel();
this.dataGrid.Commands.Add(new ValidateCellCommand(errorContainer));

5. Define the DataGrid in XAML:

<Grid Margin="0,20,0,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid x:Name="errorContainer" 
          IsVisible="false">
        <BoxView BackgroundColor="DarkRed" />
        <Label Text="country name length must be less than 15 symbols" 
               FontSize="15"
               HorizontalOptions="CenterAndExpand"
               VerticalOptions="CenterAndExpand"
               HorizontalTextAlignment="Center"
               TextColor="White"/>
    </Grid>
    <telerik:RadDataGrid x:Name="dataGrid"
                         Grid.Row="1"
                         UserEditMode="Cell"
                         AutoGenerateColumns="False"
                         ItemsSource="{Binding Items}">
            <telerik:RadDataGrid.Columns>
                <telerik:DataGridTextColumn PropertyName="Country" HeaderText="Country"/>
                <telerik:DataGridTextColumn PropertyName="Capital" HeaderText="Capital"/>
            </telerik:RadDataGrid.Columns>
    </telerik:RadDataGrid>
</Grid>

6. Use the telerik namespace:

xmlns:telerik="http://schemas.telerik.com/2022/xaml/maui"

See Also

In this article