This is a migrated thread and some comments may be shown as answers.

Force Validation After Undo/Redo to remove Validation Error Icon

7 Answers 345 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Scoobz
Top achievements
Rank 1
Scoobz asked on 23 Jan 2019, 12:16 AM

Hello,
I've been spiraling down a sad hole without any answers, so any insight is appreciated!

So I have a collection.  I'm not able to share my code for security reasons, but in the image provided, the data members which are NOT collections themselves are displayed in one radgridview above, while data members with corresponding collections are displayed in additional radgridviews below, as depicted in the image.  I am able to add an error icon onto the main radgridview with a custom message indicating that there is an "Error Below" using the "RowValidating" property of the radgridview.  The issue is that I am unable to remove the error icon from the parent radgridview if that row is not selected, since the the validation occurs on the row.  Once I select the row, the error is removed because the validation occurs.  

 

So I guess my question is, how can I force a validation on all rows?  This needs to happen after I call the Undo function.

 

Hope this was clear enough.

Regards,

Scooba

7 Answers, 1 is accepted

Sort by
0
Vladimir Stoyanov
Telerik team
answered on 25 Jan 2019, 04:33 PM
Hello Scooba,

I will need some more information about the described scenario in order to better understand it and further assist you. My current understanding is that you have a collection with instances of a class and that class has a property which is also a collection. The collection property is shown in a child RadGridView (perhaps through a CellTemplate for the column). Can you also share how you are doing the validation on your end? Do feel free to correct me if I was wrong in my understanding. 

I prepared a sample project in order to try to mimic the scenario on your end and I am attaching it here for your reference. May I ask you to check it out and let me know what I am missing? This way I will be able to investigate the scenario on my end and hopefully better assist you. 

Regards,
Vladimir Stoyanov
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Scoobz
Top achievements
Rank 1
answered on 28 Jan 2019, 12:48 PM

Hi Vladimir,

Thank you for your response! It seems like your understanding is correct, the child RadGridView gets its itemsource from the selected item of its parent collection.  For example, lets say I have a collection of dog breed entries.  An entry stores the average height, average weight, type of food it eats, and a collection of potential nicknames for the type of dog.

I select a row within the dog data.  The parent RadGridView will show how much food the dog eats, as well its average height and weight of the dog, per type of dog.  Once a dog type is selected, a child RadGridView displays potential nicknames for that dog, getting its itemsource from the collection of nicknames from the selected item of its parent class. 

We are performing validation by implementing the IDataErrorInfo interface and calling the OnPropertyChanged() function where relevant. 

 

 

 

 

0
Scoobz
Top achievements
Rank 1
answered on 28 Jan 2019, 01:10 PM
Hi Vladimir,
Thank you for your response! It seems like your understanding is correct, the child RadGridView gets its itemsource from the selected item of its parent collection.  For example, lets say I have a collection of dog breed entries.  An entry stores the average height, average weight, type of food it eats, and a collection of potential nicknames for the type of dog.
I select a row within the dog data.  The parent RadGridView will show how much food the dog eats, as well its average height and weight of the dog, per type of dog.  Once a dog type is selected, a child RadGridView displays potential nicknames for that dog, getting its itemsource from the collection of nicknames from the selected item of its parent class. 
We are performing validation by implementing the IDataErrorInfo interface and calling the OnPropertyChanged() function where relevant. 




0
Scoobz
Top achievements
Rank 1
answered on 29 Jan 2019, 12:55 PM

Hi Vladimir,

I have modified your example to perform the behavior I currently have.  You'll notice if you either empty or add a '-' to a player name for a respective Club, an error occurs.  I force this error to appear on the upper RadGridView using the 'RowValidating" property and adding a custom ValidationResult message indicating there's an error in the lower RadGridView, whose ItemSource is the selectedItem of the upper RadGridView.  My problem occurs after the user corrects the error validation before hitting enter.  If they instead select elsewhere on the RadGridView, the RowValidating property isn't called with the correct row and in turn the error isn't validated until RowValidating is called with that row again.

0
Vladimir Stoyanov
Telerik team
answered on 31 Jan 2019, 11:17 AM
Hello Scooba,

Thank you for the updates. 

I was able to get close to the behavior observed on the attached pictures, however I am still missing the way that the error is forced to the upper RadGridView. By default its RowValidating event should not be fired when an item in the lower grid is edited. I am attaching a modified version of the sample project, which I used for testing. 

Can you check it out and let me know what I am missing in order to achieve the observed behavior on the pictures? Hopefully this will allow me to reproduce the scenario and investigate it.

Regards,
Vladimir Stoyanov
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Scoobz
Top achievements
Rank 1
answered on 31 Jan 2019, 08:35 PM

Hi Vlad,

I worked with off your latest project to reproduce the behavior.  Below is the code for the modified files, apologies to you as I don't believe I can upload entire projects. Thank you in advance!

-Scooba

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// clubs.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace VisualStudioFilteringIcon
{
    /// <summary>
    /// A football club.
    /// </summary>
    public class Club : INotifyPropertyChanged/*, IDataErrorInfo*/
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        private DateTime established;
        private int stadiumCapacity;
        private ObservableCollection<Player> players;

        public string Name
        {
            get { return this.name; }
            set
            {
                if (value != this.name)
                {
                    this.name = value;
                    this.OnPropertyChanged("Name");
                }
            }
        }

        public DateTime Established
        {
            get { return this.established; }
            set
            {
                if (value != this.established)
                {
                    this.established = value;
                    this.OnPropertyChanged("Established");
                }
            }
        }

        public int StadiumCapacity
        {
            get { return this.stadiumCapacity; }
            set
            {
                if (value != this.stadiumCapacity)
                {
                    this.stadiumCapacity = value;
                    this.OnPropertyChanged("StadiumCapacity");
                }
            }
        }

        public ObservableCollection<Player> Players
        {
            get
            {
                if (null == this.players)
                {
                    this.players = new ObservableCollection<Player>();
                }

                return this.players;
            }
        }

        public Club()
        {

        }

        public Club(string name, DateTime established, int stadiumCapacity)
        {
            this.name = name;
            this.established = established;
            this.stadiumCapacity = stadiumCapacity;
        }

        public Club(string name, DateTime established, int stadiumCapacity, ObservableCollection<Player> players)
            : this(name, established, stadiumCapacity)
        {
            this.players = players;
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, args);
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        public override string ToString()
        {
            return this.Name;
        }

        public static ObservableCollection<Club> GetClubs()
        {
            ObservableCollection<Club> clubs = new ObservableCollection<Club>();
            Club club;

            // Liverpool
            club = new Club("Liverpool", new DateTime(1892, 1, 1), 45362);
            club.Players.Add(new Player("Pepe Reina", 25, Position.GK, "Spain"));
            club.Players.Add(new Player("Jamie Carragher", 23, Position.DF, "England"));
            club.Players.Add(new Player("Steven Gerrard", 8, Position.MF, "England"));
            club.Players.Add(new Player("Fernando Torres", 9, Position.FW, "Spain"));
            clubs.Add(club);

            // Manchester Utd.
            club = new Club("Manchester Utd.", new DateTime(1878, 1, 1), 76212);
            club.Players.Add(new Player("Edwin van der Sar", 1, Position.GK, "Netherlands"));
            club.Players.Add(new Player("Rio Ferdinand", 5, Position.DF, "England"));
            club.Players.Add(new Player("Ryan Giggs", 11, Position.MF, "Wales"));
            club.Players.Add(new Player("Wayne Rooney", 10, Position.FW, "England"));
            clubs.Add(club);

            // Chelsea
            club = new Club("Chelsea", new DateTime(1905, 1, 1), 42055);
            club.Players.Add(new Player("Petr ÄŒech", 1, Position.GK, "Czech Republic"));
            club.Players.Add(new Player("John Terry", 26, Position.DF, "England"));
            club.Players.Add(new Player("Frank Lampard", 8, Position.MF, "England"));
            club.Players.Add(new Player("Nicolas Anelka", 39, Position.FW, "France"));
            clubs.Add(club);

            // Arsenal
            club = new Club("Arsenal", new DateTime(1886, 1, 1), 60355);
            club.Players.Add(new Player("Manuel Almunia", 1, Position.GK, "Spain"));
            club.Players.Add(new Player("Gaël Clichy", 22, Position.DF, "France"));
            club.Players.Add(new Player("Cesc Fàbregas", 4, Position.MF, "Spain"));
            club.Players.Add(new Player("Robin van Persie", 11, Position.FW, "Netherlands"));
            clubs.Add(club);

            return clubs;
        }

        //public string Error
        //{
        //    get
        //    {
        //        return null;
        //    }
        //}

        //public string this[string columnName]
        //{
        //    get
        //    {
        //        if (columnName == "Name")
        //        {
        //            if (string.IsNullOrEmpty(this.name))
        //            {
        //                return this.Name + "cannot be empty";
        //            }
        //        }
        //        return null;
        //    }
        //}
    }
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// MainWindow.xaml

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

<Window x:Class="VisualStudioFilteringIcon.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
        xmlns:my="clr-namespace:VisualStudioFilteringIcon"
        Title="MainWindow" Height="700" Width="700">
<Window.Resources>
        <my:MyViewModel x:Key="MyViewModel"/>
    </Window.Resources>
<Grid DataContext="{StaticResource MyViewModel}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<telerik:RadGridView Grid.Row="0" 
                             Name="clubsGrid" 
                             ItemsSource="{Binding Clubs}"
                             AutoGenerateColumns="False"
                             GroupRenderMode="Flat"
                             ValidatesOnDataErrors="InViewMode"
                             SelectedItem="{Binding SelectedItem}"
                             RowValidating="clubsGrid_RowValidating"
                             Margin="5">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Established}"
                                            Header="Est." 
                                            DataFormatString="{}{0:yyyy}"/>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding StadiumCapacity}" 
                                            Header="Stadium" 
                                            DataFormatString="{}{0:N0}"/>
            </telerik:RadGridView.Columns>
</telerik:RadGridView>
        <telerik:RadGridView ItemsSource="{Binding SelectedItem.Players}" AutoGenerateColumns="False" ValidatesOnDataErrors="InViewMode"
                             GroupRenderMode="Flat" Grid.Row="1" RowValidating="RadGridView_RowValidating">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/>
            </telerik:RadGridView.Columns>
        </telerik:RadGridView>
    </Grid>
</Window>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MainWindow.xaml.cs
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
using System.Globalization;

namespace VisualStudioFilteringIcon
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            GreenPalette.LoadPreset(GreenPalette.ColorVariation.Light);

            InitializeComponent();
        }

        private void clubsGrid_RowValidating(object sender, GridViewRowValidatingEventArgs e)
        {
            // e.IsValid = 
            var radGrid = sender as RadGridView;
            var selectedClub = radGrid.SelectedItem as Club;

            // check for error in player list for selected item
            e.ValidationResults.Clear();
            foreach (var player in selectedClub.Players)
            {
                if (player.IsValid == false)
                {
                    var temp = new GridViewCellValidationResult();
                    temp.ErrorMessage = "this a test";
                    e.ValidationResults.Add(temp);
                    break;
                }
            }
        }

        private void RadGridView_RowValidating(object sender, GridViewRowValidatingEventArgs e)
        {
            clubsGrid.BeginEdit();
            clubsGrid.CommitEdit();
        }
    }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Player.cs
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace VisualStudioFilteringIcon
{
    /// <summary>
    /// A football player.
    /// </summary>
    public class Player : INotifyPropertyChanged, IDataErrorInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        private int number;
        private Position position;
        private string country;
        private bool? isValid;

        public string Name
        {
            get { return this.name; }
            set
            {
                if (value != this.name)
                {
                    this.name = value;
                    this.OnPropertyChanged("Name");
                }
            }
        }

        public int Number
        {
            get { return this.number; }
            set
            {
                if (value != this.number)
                {
                    this.number = value;
                    this.OnPropertyChanged("Number");
                }
            }
        }

        public Position Position
        {
            get { return this.position; }
            set
            {
                if (value != this.position)
                {
                    this.position = value;
                    this.OnPropertyChanged("Position");
                }
            }
        }

        public string Country
        {
            get { return this.country; }
            set
            {
                if (value != this.country)
                {
                    this.country = value;
                    this.OnPropertyChanged("Country");
                }
            }
        }

        public Player()
        {

        }

        public Player(string name, int number, Position position, string country)
        {
            this.name = name;
            this.number = number;
            this.position = position;
            this.country = country;
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, args);
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        public override string ToString()
        {
            return this.Name;
        }

        public static ObservableCollection<Player> GetPlayers()
        {
            return new ObservableCollection<Player>(Club.GetClubs().SelectMany(c => c.Players));
        }

        public string Error
        {
            get
            {
                return null;
            }
        }

        public bool? IsValid
        {
            get
            {
                return isValid;
            }

            set
            {
                isValid = value;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (columnName == "Name")
                {
                    if (string.IsNullOrEmpty(this.name))
                    {
                        isValid = false;
                        return this.Name + "cannot be empty";
                    }

                    if (this.name.Contains('-'))
                    {
                        isValid = false;
                        return "cannot input a '-' character.";
                    }

                    isValid = true;
                    return null;
                }

                return null;
            }
        }
    }
}

0
Vladimir Stoyanov
Telerik team
answered on 05 Feb 2019, 04:50 PM
Hello Scooba,

Thank you for the update. 

I investigated the described scenario and what you have observed is the expected behavior. Since the ValidatesOnDataErrors property of the lower grid is set to InViewMode, the RowValidating event will be called when other rows are clicked. A possible approach that I can suggest is setting the ValidatesOnDataErrors property of the lower grid to InEditMode. This way the if there is an error, no other cells will be editable before the error is resolved. 

That said, you can also try to handle the entire validation on the data level. You can take a look at the ValidationINotifyDataErrorInfo SDK example, which shows how you can sync the validation between two RadGridViews sharing the same itemssource. Perhaps you can use a similar approach with two different sources. Please, give this approach a try and let me know how it goes. 

Regards,
Vladimir Stoyanov
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.

Tags
GridView
Asked by
Scoobz
Top achievements
Rank 1
Answers by
Vladimir Stoyanov
Telerik team
Scoobz
Top achievements
Rank 1
Share this question
or