Q:

wpf Datagrid: throw duplicated entry

In my application I want to validate if the user enter an item which is already exist on the DataGrid when I enter a new Item on the cell. I validate my business object using IDataErrorInfo.
My object is as follows:
 class clsProducts : INotifyPropertyChanged, IDataErrorInfo
{
    private string _ProductName;
    private decimal _PurchaseRate;
    private int _AvailableQty;
    private int _Qty;
    private decimal _Amount;

    #region Property Getters and Setters

    public string ProductName
    {
        get { return _ProductName; }
        set
        {

            if (_ProductName != value)
            {
                _ProductName = value;
                OnPropertyChanged("ProductName");
            }
        }
    }

    public decimal PurchaseRate
    {
        get { return _PurchaseRate; }
        set
        {
            _PurchaseRate = value;
            OnPropertyChanged("PurchaseRate");
        }
    }

    public int AvailableQty
    {
        get { return _AvailableQty; }
        set
        {
            _AvailableQty = value;
            OnPropertyChanged("AvailableQty");
        }
    }

    public int Qty
    {
        get { return _Qty; }
        set
        {
            _Qty = value;
            this._Amount = this._Qty * this._PurchaseRate;
            OnPropertyChanged("Qty");
            OnPropertyChanged("Amount");
        }
    }

    public decimal Amount
    {
        get { return _Amount; }
        set
        {
            _Amount = value;
            OnPropertyChanged("Amount");
        }
    }

    #endregion

    #region IDataErrorInfo Members

    public string Error
    {
        get
        {
            StringBuilder error = new StringBuilder();
            // iterate over all of the properties
            // of this object - aggregating any validation errors
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this);
            foreach (PropertyDescriptor prop in props)
            {
                string propertyError = this[prop.Name];
                if (!string.IsNullOrEmpty(propertyError))
                {
                    error.Append((error.Length != 0 ? ", " : "") + propertyError);
                }
            }
            return error.ToString();
        }
    }

    public string this[string name]
    {
        get
        {
            string result = null;

            if (name == "ProductName")
            {
                if (this._ProductName != null)
                {
                    int count = Global.ItemExist(this._ProductName);
                    if (count == 0)
                    {
                        result = "Invalid Product "+this._ProductName;
                    }
                }
            }

            else if (name == "Qty")
            {
                if (this._Qty > this._AvailableQty)
                {
                    result = "Qty must be less than Available Qty . Avaialble Qty : " + this._AvailableQty;
                }
            }

            return result;
        }
    }

    #endregion

    #region INotifyPropertyChanged Members

    // Declare the event
    public event PropertyChangedEventHandler PropertyChanged;

    //// Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion
}

My xaml is :
 <my:DataGrid Name="dgReceiveInventory" RowStyle="{StaticResource RowStyle}"  ItemsSource="{Binding}" GotFocus="dgReceiveInventory_GotFocus"  CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserSortColumns="False"  RowHeight="23"  SelectionUnit="Cell"   AutoGenerateColumns="False" Margin="12,84,10,52"  BeginningEdit="dgReceiveInventory_BeginningEdit">
        <my:DataGrid.Columns>

            <!--0-Product Column-->

            <my:DataGridTemplateColumn Header="Product Name" Width="200">
                <my:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Style="{StaticResource TextBlockInError}" Text="{Binding ProductName,ValidatesOnDataErrors=True}"  ></TextBlock>
                    </DataTemplate>
                </my:DataGridTemplateColumn.CellTemplate>
                <my:DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <TextBox x:Name="txtbxProduct" Style="{StaticResource TextBoxInError}" Text="{Binding Path=ProductName,UpdateSourceTrigger=LostFocus,ValidatesOnDataErrors=True}"  TextChanged="txtbxProduct_TextChanged" PreviewKeyDown="txtbxProduct_PreviewKeyDown" >
                                    </TextBox>
                    </DataTemplate>
                </my:DataGridTemplateColumn.CellEditingTemplate>
            </my:DataGridTemplateColumn>

            <!--1-Purchase Rate Column-->
            <my:DataGridTextColumn Header="Purchase Rate" Width="100" Binding="{Binding PurchaseRate}" IsReadOnly="True"></my:DataGridTextColumn>

            <!--2-Avaialable Qty Column-->
            <my:DataGridTextColumn Header="AvailableQty"  Binding="{Binding AvailableQty}" IsReadOnly="True" Visibility="Hidden"></my:DataGridTextColumn>

            <!--3-Qty Column-->

            <my:DataGridTextColumn Header="Qty"  Binding="{Binding Qty,ValidatesOnExceptions=True,ValidatesOnDataErrors=True}" EditingElementStyle="{StaticResource TextBoxInError}">

            </my:DataGridTextColumn>

            <!--4-Amount Column-->
            <my:DataGridTextColumn Header="Amount" Width="100"  Binding="{Binding Amount}" ></my:DataGridTextColumn>
        </my:DataGrid.Columns>
    </my:DataGrid>

Now I want to show the user ,if he made a duplicate entry in the datagrid cell how to do this ?

A:

You can't do this functionality in your model or data type class using the IDataErrorInfo interface because you won't have access to the other objects there. Instead, you'll have to do it in your view model. However, you can report the error using that interface. I have extended its functionality by adding a property into my data type base class:
public virtual ObservableCollection<string> ExternalErrors
{
    get { return externalErrors; }
}

As you can see, mine deals with multiple errors, but you can easily change this to:
public virtual string ExternalError
{
    get { return externalError; }
}

Then I 'plug' this into my Errors property:
public override ObservableCollection<string> Errors
{
    get
    {
        errors = new ObservableCollection<string>();
        errors.AddUniqueIfNotEmpty(this["Name"]);
        errors.AddUniqueIfNotEmpty(this["EmailAddresses"]);
        errors.AddUniqueIfNotEmpty(this["StatementPrefixes"]);
        errors.AddRange(ExternalErrors);
        return errors;
    }
}

Again, I have adapted this interface to return multiple errors, but you can change this to:
public override string Error
{
    get
    {
        error = string.Empty;
        if ((error = this["Name"])) != string.Empty) return error;
        if ((error = this["EmailAddresses"])) != string.Empty) return error;
        if ((error = this["Name"])) != string.Empty) return error;
        if (ExternalError != string.Empty) return ExternalError;
        return error;
    }
}

Incidentally, it is far more efficient to call just the indexers that you are actually validating rather than your example of calling all properties using reflection. However, that is your choice.
So now that we have this ExternalError property, we can use it to display external error messages from your view model (create a class that contains a collection property to bind to the DataGrid.ItemsSource property). 
If you are using ICommand objects, then you can put this code into the CanExecute method of your Save command:
public bool CanSave(object parameter)
{
    clsProducts instance = (clsProducts)parameter;
    instance.ExternalError = YourCollectionProperty.Contains(instance) ? 
        "The values must be unique" : string.Error;
    // Perform your can save checks here
}

Please note that you will need to implement the Equals method in your data type object for this to work. There are many similar ways to achieve this and I trust that from this example you will be able to work one out that works for you.

