Wpf datagrid row not updating when binded collection updated

bindingwpfwpfdatagrid

I have product class named-Products.cs

class Products : INotifyPropertyChanged
{
    private int productId = 0;
    private int quantity = 0;
    private string description = string.Empty;
    private decimal price = 0.0m;

    public event PropertyChangedEventHandler PropertyChanged;

    public Products()
    {
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #region Properties

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

    public int Quantity
    {
        get { return this.quantity; }
        set
        {
            if (value != this.quantity)
            {
                this.quantity = value;
                OnPropertyChanged("Quantity");
                OnPropertyChanged("SubTotal");
            }

        }
    }

    public String Description
    {
        get { return this.description;}
        set
        {
            if (value != this.description)
            {
                this.description = value;
                OnPropertyChanged("Description");
            }
        }
    }

    public Decimal Price
    {
        get { return this.price; }
        set
        {
            if (value != this.price)
            {
                this.price = value;
                OnPropertyChanged("Price");
            }
        }
    }

    public Decimal SubTotal
    {
        get { return Quantity * Price; }
    }

    public static List<Products> ProductList
    {
        get { return new List<Products>(); }
    }     

    #endregion
}

Then I have BilClass.cs to implement add, edit & remove items from List.

class BillClass
{
    public List<Products> ProductsList = new List<Products>();
    Products products;

    public BillClass()
    {
        AddProducts(1, 2, 20.00m, "a");            
    }

    public void AddProducts(int _pid, int _quantity, decimal _price, string _desc)
    {
        products = new Products();
        products.ProductID = _pid;
        products.Quantity = _quantity;
        products.Price = _price;            
        products.Description = _desc;

        ProductsList.Add(products);
    }

    public bool RemoveProduct(int _id)
    {
        ProductsList.Remove(ProductsList.Find(e => e.ProductID.Equals(_id)));
        return true;
    }

    public void EditProducts(int _pid, int _quantity)
    {
        Products ob = ProductsList.Find(e => e.ProductID.Equals(_pid));
        ob.Quantity = _quantity;            
    }

    public List<Products> GetItems()
    {
        return ProductsList;
    }

I have binded this "ProductList" to wpf datagrid. This datagrid shows item already in collection (data added in BillClass constructor) but not showing new item added via sales window which contains DataGrid.

DataGrid XAML Code

<Custom:DataGrid ItemsSource="{Binding Path=ProductsList}" Margin="16,100,16,120" AutoGenerateColumns="False" x:Name="dataGrid" HorizontalGridLinesBrush="#FFD0D0D0" 
            VerticalGridLinesBrush="#FFD0D0D0" CanUserDeleteRows="True" CanUserResizeRows="False" Background="White" IsTabStop="False" Focusable="False" IsReadOnly="True" CanUserSortColumns="False" CanUserResizeColumns="False" CanUserReorderColumns="False" GridLinesVisibility="Horizontal" EnableRowVirtualization="False">
            <Custom:DataGrid.Columns>
                <Custom:DataGridTextColumn Binding="{Binding Path=ProductID}" Header="Sl" Width="40" IsReadOnly="True" CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
                <Custom:DataGridTextColumn Binding="{Binding Path=ProductID}" Header="Product Code" Width="100" IsReadOnly="True" CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
                <Custom:DataGridTextColumn Binding="{Binding Path=Description}" Header="Description" Width="250" IsReadOnly="True" CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
                <Custom:DataGridTextColumn Binding="{Binding Path=Price}" Header="Unit Price (in Rs.)" Width="120" IsReadOnly="True" CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
                <Custom:DataGridTextColumn Binding="{Binding Path=Quantity}" Header="Quantity" Width="120" IsReadOnly="True" CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
                <Custom:DataGridTextColumn Binding="{Binding Path=SubTotal, Mode=OneWay}" Header="Total (in Rs.)" Width="120" IsReadOnly="True" CanUserSort="False" CanUserResize="False" CanUserReorder="False" />                                         
            </Custom:DataGrid.Columns>                      
        </Custom:DataGrid>

Some code will help

thanks

Best Answer

Your Product class has to implement INotifyPropertyChanged interface and you should update your bind-able properties to raise this event every time have changed. This is the way binding works in WPF. Something like this snippet

public class Produts : INotifyPropertyChanged
    {
public Produts()
        {

        }
    int productID;
    public int ProductID
    {
        get { return productID; }
        set
        {
            if (productID != value)
            {
                productID = value;
                OnPropertyChange("ProductID");
            }
        }
    }
    int quantity;
    public int Quantity
    {
        get { return quantity; }
        set
        {
            quantity = value;
            OnPropertyChange("Quantity");
            //Force Subtotal to be updated
            OnPropertyChange("SubTotal");
        }
    }
    string description;
    public string Description
    {
        get { return description; }

        set
        {
            description = value;
            OnPropertyChange("Description");
        }
    }
    decimal price;
    public decimal Price
    {
        get { return price; }
        set
        {
            price = value;
            OnPropertyChange("Price");
            //Force Subtotal to be updated
            OnPropertyChange("SubTotal");
        }
    }
    public decimal SubTotal
    {
        get { return Quantity * Price; }
    }

    public static List<Produts> ProductList
    {
        get
        {
            return new List<Produts>();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChange(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Here's XAML:

<DataGrid ItemsSource="{Binding Path=ProductList}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding Path= ProductID}"/>
                <DataGridTextColumn Header="Quantity" Binding="{Binding Path=Quantity}"/>
                <DataGridTextColumn Header="Description" Binding="{Binding Path=Description}"/>
                <DataGridTextColumn Header="Price" Binding="{Binding Path=Price}"/>
                <DataGridTextColumn Header="Subtotal" Binding="{Binding Path=SubTotal, Mode=OneWay}"/>
            </DataGrid.Columns>
        </DataGrid>

And this line in Window's constructor

base.DataContext = new Produts();
Related Topic