DataGrid Validation for a DataTable

Nov 3, 2008 at 12:18 PM
Edited Nov 3, 2008 at 12:22 PM
Hello,

Is it possible to handle exceptions that arise from data tables using data grid validation?

For example, consider a data table with a single column titled "ID". This column is the table's primary key.
So whenever I add a new row with a null or previously used ID, an exception will arise.

Sample Code:

<dg:DataGrid x:Name="dataGrid" AutoGenerateColumns="False"
            ItemsSource="{Binding Source={StaticResource Table}}" ColumnWidth="*">
            
            <dg:DataGrid.Columns>
                
                <dg:DataGridTextColumn Header="ID">
                    <dg:DataGridTextColumn.Binding>
                        <Binding Path="ID">
                        </Binding>
                    </dg:DataGridTextColumn.Binding>
                </dg:DataGridTextColumn>

            </dg:DataGrid.Columns>
        </dg:DataGrid>
 

How can I handle such cases and display a useful message to the user?

Thank you.
Coordinator
Nov 3, 2008 at 1:34 PM
You should look into using ExceptionValidationRule.  This is a pre-built validation rule that tells WPF to report all exceptions. 
Nov 3, 2008 at 1:55 PM
Thank you for your quick reply.

I tried a lot of different things with validation rules and unfortunately I was not able to solve the problem. Can you please tell me what I exactly have to add.

I tried something like this:

                        <Binding Path="ID" ValidatesOnExceptions="True" NotifyOnValidationError="True">
                            <Binding.ValidationRules>
                                <ExceptionValidationRule></ExceptionValidationRule>
                            </Binding.ValidationRules>
                        </Binding>

However, I still get the System.Data.ConstraintException  {"Column 'Name' is constrained to be unique.  Value 'Name1' is already present."} thrown.
Also note that I did not add any custom error/validation templates. For now, I just want to suppress the exception.

When I tried adding a DataGridTemplateColumn and doing validation on a TextBox in the CellEditingTemplate, the exception was successfully suppressed (using similar code as above). So my question is, why isn't it working with the DataGridTextColumn?

Attached below is the full code for the window's xaml and code behind classes:

XAML:
------------------------------------------------------------------------------------------
<Window x:Class="WPF_Test.Window3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
    Title="Window3" Height="300" Width="500">

    <Window.Resources>
        <ObjectDataProvider x:Key="Table"></ObjectDataProvider>
    </Window.Resources>

    <Grid>
        <dg:DataGrid x:Name="dataGrid" AutoGenerateColumns="False"
            ItemsSource="{Binding Source={StaticResource Table}}" ColumnWidth="*">

            <dg:DataGrid.Columns>

                <dg:DataGridTextColumn Header="Name">
                    <dg:DataGridTextColumn.Binding>
                        <Binding Path="Name" ValidatesOnExceptions="True" NotifyOnValidationError="True">
                            <Binding.ValidationRules>
                                <ExceptionValidationRule></ExceptionValidationRule>
                            </Binding.ValidationRules>
                        </Binding>
                    </dg:DataGridTextColumn.Binding>
                </dg:DataGridTextColumn>
                
            </dg:DataGrid.Columns>
        </dg:DataGrid>
    </Grid>
</Window>
-----------------------------------------------------------------------------------

Code Behind:
----------------------------------------------------------------------------------

namespace WPF_Test
{
    /// <summary>
    /// Interaction logic for Window3.xaml
    /// </summary>
    public partial class Window3 : Window
    {
        public DataTable Table { get; set; }

        public Window3 ()
        {
            InitializeComponent();

            ObjectDataProvider tableResource = (ObjectDataProvider) FindResource("Table");
            tableResource.ObjectInstance = new DataTable("Table");
            Table = (DataTable) tableResource.ObjectInstance;

            DataColumn column1 = new DataColumn("Name");
            column1.Caption = "Name";
            column1.DataType = System.Type.GetType("System.String");

            Table.Columns.Add(column1);


            DataColumn[] primaryKey = new DataColumn[1];
            primaryKey[0] = Table.Columns[0];
            Table.PrimaryKey = primaryKey;
        }
    }
}

----------------------------------------------------------------------------------
Coordinator
Nov 5, 2008 at 7:45 PM

After further investigation, this is a bug in the data binding system as it does not catch exceptions when they are thrown from IEditableObject.EndEdit.  The bug has been filed and will be addressed in the next release.  A possible workaround is to create a custom ValidationRule for the BindingGroup and try to update the source there but catch exceptions yourself.  Sorry for the inconvenience.

Nov 14, 2008 at 12:03 PM
Ziad,

You might be interested in a work-around that I have created for this problem which you will find in this article:

http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx

Basically, the DataTable constraints are checked when the row/cells are validated. This ensures that when the modified row is committed to the DataTable, constraint violation exceptions do not occur.

Colin E.



Nov 14, 2008 at 12:24 PM
Thank you for your reply. I'll will review your code when I have free time. For now, I was able to solve the problem by adding custom validation rules. But this becomes a pain when validating unique constraints since I have to query for duplicates myself.
May 13, 2009 at 8:06 AM

Hi vinsibal,

Can you confirm if this bug was fixed in the march 2009 release? I think i'm experiencing the same issue as the original poster but i'm using the latest version of wpf toolkit.

Oskar H

Jul 20, 2009 at 3:41 PM

Parts of that project don't work anymore.  Is this datagrid dead already ????

Sep 21, 2009 at 10:02 PM

Please, can someone confirm that this bug has been fixed in the latest release? And what's the issue number in the tracker?

Thanks.

Apr 6, 2010 at 8:58 AM
Edited Apr 6, 2010 at 9:06 AM

Hi Vincent,

-I have class CustomItem:

 

public class CustomItem: IEditableObject, INotifyPropertyChanged, IDataErrorInfo

 

-I bind DataGrid with col that is ObservableCollection<CustomItem>

-col has CollectionChanged handler:

 

col.CollectionChanged += new NotifyCollectionChangedEventHandler(CustomItemsCollectionChanged);

 

-handler:

 public void CustomItemCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (object item in e.OldItems)
{
CustomItem itemToDelete = item as CustomItem;
// use the data access layer to delete the wrapped data object
try
{
customItemService.DeleteCustomItem(itemToDelete.Id);
}
catch (Exception exp)
{
//this Exception throw in cycle, i don't able catch exception in IEditableObject.EndEdit in my CustomItem Class = i don't able cancel Remove/Delete operation in DataGrid
throw new Exception("Exception from CustomItemCollectionChanged");

}

}
}
}

My question is:
How can i cancel Remove/Delete operation in DataGrid in my scenario?
Colin Eberhardt say that is a bug(throw in cycle)(end of Handling Updates / Inserts section (http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx#layered_updates))
Thank you for your reply.

Martin.