Hi,
I've been trying to use IDataErrorInfo with the RagGridView, and i ran into some problems.
First of all i haven't been able to find any documentation on RadGridView support for IDataErrorInfo.
there was a single post on the forum that mentioned working with it - and it does work to a certain extent.
What im doing is this: i implemented IDataErrorInfo on in my data model, and i am binding to the grid with ValidatesOnDataErrors="True"
The binding code is:
<controls:RadGridView Name="keywordGrid" ShowGroupPanel="False" AutoGenerateColumns="False" Height="300" |
> |
<controls:RadGridView.Columns> |
<controls:GridViewDataColumn Header="Name" DataMemberBinding="{Binding DeferredEntity.Data.Name, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Destination Url" DataMemberBinding="{Binding DeferredEntity.Data.DestinationUrl, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Tracking Url" DataMemberBinding="{Binding DeferredEntity.Data.TrackingUrl, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Match Type" DataMemberBinding="{Binding DeferredEntity.Data.MatchType, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Status" DataMemberBinding="{Binding DeferredEntity.Data.Status, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Search Bid" DataMemberBinding="{Binding DeferredEntity.Data.SearchBid, ValidatesOnDataErrors=True}"/> |
</controls:RadGridView.Columns> |
</controls:RadGridView> |
When scrolling down on the grid everything works as it should - a red border around the invalid data elements shows that there's an error there and the error appears around the correct elements and does not appear around valid elements.
The problem starts when i scroll UP in the grid. as soon as i scroll up everything starts failing - error markers start appearing around all elements regardless of their validity. after scrolling 20-30 records up it doesnt matter what i do - scroll up or down, everything seems to have an error and the boarders start drawing in the wrong place, sometimes over the text of the cells in the grid.
is this the right way to use IDataErrorInfo with Telerik's RadDataGrid?
Is there some other way (but still using IDataErrorInfo binding)?
What is causing this strange behavior?
Also - how do i get the grid to show a tooltip when hovering over an element with an error (with the string that returned from IDataErrorInfo as the error message).
Thanks,
Yossi.
EDIT:
After the above post i thought i'd try a simple test project outside of the rest of our app.
What i found was this - If we bind directly to a property of a class - validation is not called.
If we bind indirectly (through a nested element) - validation is called, but the strange "up/down" behavior i mentioned above occurs.
I am attaching my test project.
Scroll up and down on the "Nested" grid to see the errors i mentioned, the "Direct" grid demonstrates that the validation code is never called.
Hmm...looks like i can't attach the project - so here is the source:
Window1.xaml:
<Window x:Class="GridIDataErrorInfoTest.Window1" |
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:controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView" |
xmlns:grid="clr-namespace:Telerik.Windows.Controls.GridView;assembly=Telerik.Windows.Controls.GridView" |
xmlns:gridView="clr-namespace:Telerik.Windows.Controls.GridView;assembly=Telerik.Windows.Controls.GridView" |
Title="Window1" Height="800" Width="600"> |
<Grid> |
<Grid.RowDefinitions> |
<RowDefinition Height="300"/> |
<RowDefinition Height="300"/> |
</Grid.RowDefinitions> |
<controls:RadGridView Grid.Row="0" Name="directGrid" ShowGroupPanel="False" AutoGenerateColumns="False" Height="300" |
> |
<controls:RadGridView.Columns> |
<controls:GridViewDataColumn Header="Name - DirectBinding" DataMemberBinding="{Binding Name, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Binding Type - DirectBinding" DataMemberBinding="{Binding BindingType, ValidatesOnDataErrors=True}"/> |
</controls:RadGridView.Columns> |
</controls:RadGridView> |
<controls:RadGridView Grid.Row="1" Name="nestedGrid" ShowGroupPanel="False" AutoGenerateColumns="False" Height="300" |
> |
<controls:RadGridView.Columns> |
<controls:GridViewDataColumn Header="Name - NestedBinding" DataMemberBinding="{Binding Test.Name, ValidatesOnDataErrors=True}"/> |
<controls:GridViewDataColumn Header="Binding Type - NestedBinding" DataMemberBinding="{Binding Test.BindingType, ValidatesOnDataErrors=True}"/> |
</controls:RadGridView.Columns> |
</controls:RadGridView> |
</Grid> |
</Window> |
Window1.cs.xaml Code:
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 System.ComponentModel; |
using System.Diagnostics; |
namespace GridIDataErrorInfoTest |
{ |
public class DeeperBinding |
{ |
private TestData test; |
public TestData Test |
{ |
get { return test; } |
set { test = value; } |
} |
} |
public class TestData : IDataErrorInfo,INotifyPropertyChanged |
{ |
private String name; |
public String Name |
{ |
get { return name; } |
set { |
name = value; |
if (this.PropertyChanged != null) |
this.PropertyChanged(this, new PropertyChangedEventArgs("Name")); |
} |
} |
private String bindingType; |
public String BindingType |
{ |
get { return bindingType; } |
set { |
bindingType = value; |
if (this.PropertyChanged != null) |
this.PropertyChanged(this, new PropertyChangedEventArgs("BindingType")); |
} |
} |
#region IDataErrorInfo Members |
public string Error |
{ |
get { |
return null; |
} |
} |
public string this[string columnName] |
{ |
get |
{ |
Debug.WriteLine("Calling validation - BindingType = "+this.bindingType); |
if (!columnName.Equals("Name")) |
return null; |
if (this.name.Equals("MyErrorValue")) |
return "Error !!! WAAHAHAHAHA"; |
else |
return null; |
} |
} |
#endregion |
#region INotifyPropertyChanged Members |
public event PropertyChangedEventHandler PropertyChanged; |
#endregion |
} |
/// <summary> |
/// Interaction logic for Window1.xaml |
/// </summary> |
public partial class Window1 : Window |
{ |
public Window1() |
{ |
InitializeComponent(); |
//direct binding ignores validation |
this.directGrid.ItemsSource = GenerateTestData("Direct"); |
//binding to a nested element calls validation on the nested elements, but does not work properly. |
this.nestedGrid.ItemsSource = WrapInDeeperBinding(GenerateTestData("Nested")); |
} |
private List<TestData> GenerateTestData(String bindingType) |
{ |
int count = 10000; |
List<TestData> result = new List<TestData>(); |
for (int i = 0; i < count; i++) |
if (i % 2 == 0) |
result.Add(new TestData() { Name = "grgrbgrb", BindingType = bindingType}); |
else |
result.Add(new TestData() { Name = "MyErrorValue", BindingType = bindingType }); |
return result; |
} |
private List<DeeperBinding> WrapInDeeperBinding(List<TestData> dataList) |
{ |
List<DeeperBinding> result = new List<DeeperBinding>(); |
foreach(var data in dataList) |
result.Add(new DeeperBinding(){Test = data}); |
return result; |
} |
} |
} |