Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wpf datagrid row not updating when binded collection updated?

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

like image 686
Raj Avatar asked Feb 27 '23 22:02

Raj


2 Answers

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();
like image 160
Abdullah BaMusa Avatar answered Mar 15 '23 17:03

Abdullah BaMusa


It has nothing to do with List or ObservableCollection. All the collection does is to notify the collection has been changed (eg. add a new item, remove a item, etc). It's the individual item itself that should notify UI that some of the fields have been changed. You can either use dependency property or implement INotifyPropertyChanged to utilize WPF property system.

like image 21
treehouse Avatar answered Mar 15 '23 19:03

treehouse