Xard
Xard

Reputation: 3

Count Duplicates and sum values in datagridview in C#

I'm trying to Count up and delete the duplicates rows when a new row is added, and if the row does not exist it should make a new row for it. If a new row is added and is the same as one of the existing ones is would add it to the count.

It should look for if: 'Code' is the same and if the 'Part' is the same.

What I'm getting:

enter image description here

Updated code now: CodeCombox has been replaced with textBoxScanner.

    private void addcodes()
    {
        if (!int.TryParse(CountTextBox.Text, out var count)) return;

        var product = _bindingList
            .FirstOrDefault(prod =>
                prod.Code == Convert.ToString(textBoxScanner.Text) &&
                prod.Parts == PartsComboBox.Text);

        if (product == null)
        {
            _bindingList.Add(new Product()
            {
                Code = Convert.ToString(textBoxScanner.Text),
                Parts = PartsComboBox.Text,
                Count = count
            });

        }
        else
        {
            product.Count = product.Count + count;
        }
        textBoxScanner.Focus();
        textBoxScanner.Clear();            
    }

Class has been updated to a string:

public class Product : INotifyPropertyChanged
        {
            private string _code;
            private string _parts;
            private int _count;

            public string Code
            {
                get => _code;
                set
                {
                    _code = value;
                    OnPropertyChanged();
                }
            }

            public string Parts
            {
                get => _parts;
                set
                {
                    _parts = value;
                    OnPropertyChanged();
                }
            }

            public int Count
            {
                get => _count;
                set
                {
                    _count = value;
                    OnPropertyChanged();
                }
            }



            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }

Upvotes: 0

Views: 450

Answers (1)

Karen Payne
Karen Payne

Reputation: 5127

One solution is to use a BindingList with a concrete class rather than work directly from the DataGridView. In the following sample there are two ComboBox controls for Code and Parts, a TextBox for Count.

Class to store information

public class Product : INotifyPropertyChanged
{
    private int _code;
    private string _parts;
    private int _count;

    public int Code
    {
        get => _code;
        set
        {
            _code = value;
            OnPropertyChanged();
        }
    }

    public string Parts
    {
        get => _parts;
        set
        {
            _parts = value;
            OnPropertyChanged();
        }
    }

    public int Count
    {
        get => _count;
        set
        {
            _count = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

In the add button lambda determines if a Product exists, if yes, add count, if no add new record. Note there is a current button if you need to inspect or change the current row in the DataGridView.

public partial class Form1 : Form
{
    private readonly BindingList<Product> _bindingList;

    public Form1()
    {
        InitializeComponent();

        _bindingList = new BindingList<Product>();
        
        dataGridView1.DataSource = _bindingList;
        dataGridView1.AllowUserToAddRows = false;
        
        Shown += OnShown;
    }

    private void OnShown(object sender, EventArgs e)
    {
        Controls
            .OfType<ComboBox>()
            .ToList()
            .ForEach(cb => cb.SelectedIndex = 0);
    }

    private void AddButton_Click(object sender, EventArgs e)
    {
        if (!int.TryParse(CountTextBox.Text, out var count)) return;
        
        var product = _bindingList
            .FirstOrDefault(prod =>
                prod.Code == Convert.ToInt32(CodeComboBox.Text) &&
                prod.Parts == PartsComboBox.Text);

        if (product == null)
        {
            _bindingList.Add(new Product()
            {
                Code = Convert.ToInt32(CodeComboBox.Text),
                Parts = PartsComboBox.Text,
                Count = count
            });

        }
        else
        {
            product.Count = product.Count + count;
        }


    }

    private void CurrentButton_Click(object sender, EventArgs e)
    {
        if (_bindingList.Count >0 && dataGridView1.CurrentRow != null)
        {
            var product = _bindingList[dataGridView1.CurrentRow.Index];
            MessageBox.Show($"{product.Code}\n{product.Parts}\n{product.Count}");
        }
        else
        {
            // no current row
        }
    }
}

enter image description here

Upvotes: 1

Related Questions