0

I have a DataGridView and Checkbox column attached to it. I would like to achieve something like this, when a few checkboxes are selected, it will compare the cells value of column named Description between those selected row. If the values are not same, a message box will be show up, else the value will be parse into a textbox.

Example

As in example above, a messagebox should be show up when those rows are selected.

This is what i have done so far and i don't know how to continue from here.


private void datagridview1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            foreach (DataGridViewRow r in datagridview1.Rows)
            {
                bool ckboxselected = !Convert.ToBoolean(r.Cells[0].Value);

                if (e.RowIndex >= 0 && e.ColumnIndex == 0)
                {
                    if (ckboxselected)
                    {
                        //compare
                    }
                    else
                    {
                        //another action
                    }
                }
            }
        }

I appreciate you help!

Charly
  • 123
  • 1
  • 2
  • 11
  • there could be multiple rows which have the same Description? so you want to show a message if all selected rows have same description? – Vivek Nuna Dec 17 '22 at 08:02
  • @viveknuna yes correct – Charly Dec 17 '22 at 08:07
  • Its been year I have not worked on DataGridView. but your code should look something like `var rows = MyDatagrid.Rows .Cast() .Where(r => r.CheckBoxPropertyName == true); List ls foreach(var row in rows) { ls.Add(row[Description]) } if (list.Any(o => o != list[0])) { //diffrenet } else { //all same }` – Vivek Nuna Dec 17 '22 at 08:16

3 Answers3

0

From what you write, I think your code should look like something along the lines of this:

    private void datagridview1_CellClick(object sender, DataGridViewCellEventArgs e)
    {
        string description =null;
        bool differentDescriptionsChecked=false;
        foreach (DataGridViewRow r in datagridview1.Rows)
        {
            bool ckboxselected = Convert.ToBoolean(r.Cells[0].Value);
            if (ckboxselected)
            {
                 string description2 = Convert.ToString(r.Cells[2].Value);
                 if(description==null)
                 {
                      description=description2;
                 }
                 else if(description!=description2)
                 {
                      differentDescriptionsChecked=true;
                      break;
                 }
            }
        }
        if(description==null)
        {
              // show message "no row checked"
        }
        else if(differentDescriptionsChecked)
        {
             // show message "different descriptions checked"
        }
        else
        {
             // do something with "description"
        }
    }

Note I removed the if (e.RowIndex >= 0 && e.ColumnIndex == 0) from your code, it looked superfluous for me (but maybe I am missing something). Also in ckboxselected = !Convert.ToBoolean(r.Cells[0].Value); the "not" operator did not look right (decide by yourself if your original version was correct).

When the requirements become slightly more complicated, I would recommend to approach this in more than step: first, fill some collection like a list, hashset or dictionary with the content from the rows which you are interested in. Then, in a second step evaluate the content to make decisions from it. That could have been done here in this case, too.

Doc Brown
  • 19,739
  • 7
  • 52
  • 88
  • `string description2 = Convert.ToBoolean(r.Cells[2].Value);` ? -- You'll have to rethink this procedure as a whole, because it's clearly not getting there – Jimi Dec 17 '22 at 10:14
0

Another approach is to load the DataGridView using a class which means when performing assertions there is, in this case a call to commit changes of the DataGridViewCheckBoxColumn.

enter image description here

Sample model/class, where INotifyPropertyChanged notifies clients that a property value has changed.

public class Item : INotifyPropertyChanged
{
    private bool _selected;
    private string _description;



    public bool Selected
    {
        get => _selected;
        set
        {
            _selected = value;
            OnPropertyChanged();
        }
    }
    public int Id { get; set; }    
    public string Description
    {
        get => _description;
        set
        {
            _description = value; 
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

Form code

public partial class Form1 : Form
{
    private readonly BindingSource _bindingSource = new BindingSource();
    private BindingList<Item> _bindingList;
    public Form1()
    {
        InitializeComponent();
        Shown += OnShown;
    }
    
    private void OnShown(object sender, EventArgs e)
    {

        _bindingList = new BindingList<Item>(new List<Item>()
        {
            new Item() {Selected = false,Id = 1,Description = "A"},
            new Item() {Selected = false,Id = 2,Description = "B"},
            new Item() {Selected = false,Id = 3,Description = "B"},
            new Item() {Selected = false,Id = 4,Description = "A"},
        });

        _bindingSource.DataSource = _bindingList;
        dataGridView1.DataSource = _bindingSource;
        dataGridView1.Columns["Id"]!.ReadOnly = true;
        dataGridView1.CellContentClick += DataGridView1OnCellContentClick;
    }

    private void DataGridView1OnCellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        if (e.RowIndex < 0 || e.ColumnIndex != 0) return;

        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);

        for (int index = 0; index < _bindingList.Count; index++)
        {
            if (_bindingList[index].Selected)
            {
                // TODO
            }
            else
            {
                // TODO
            }
        }
    }
}
Karen Payne
  • 4,341
  • 2
  • 14
  • 31
0

The CellClick event is raised when you mouse-click anywhere within the cell's bounds including the CheckBox area of the DataGridViewCheckBoxCell. Also, it's raised when you press the Space key while a content cell has focus. On the other hand, the CellContentClick event is raised when a content area (i.e. CheckBox) is hit by mouse or key and the cell's Value is about to change.

As I understand your question, you need to implement the latter to take an action if you get different descriptions (column 2) of the checked rows. If so, a simple LINQ query will do.

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex >= 0 && e.ColumnIndex == 0)
    {
        // To get the new value...
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);

        var row = dataGridView1.Rows[e.RowIndex];
        var any = dataGridView1.Rows.Cast<DataGridViewRow>().Where(
            r => r.Index != row.Index && (bool)r.Cells[0].FormattedValue).Any(
            r => r.Cells[2].Value?.ToString().ToLower() != row.Cells[2].Value?.ToString().ToLower());

        if (any)
        {
            // Uncomment if you need to cancel the check...
            //row.Cells[0].Value = false;
            //dataGridView1.EndEdit();
            MessageBox.Show("Not same descriptions...");
        }
        else
        {
            // ...
        }
    }
}

If you need to skip the null descriptions.

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex >= 0 && e.ColumnIndex == 0)
    {
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);

        var row = dataGridView1.Rows[e.RowIndex];

        if (row.Cells[2].Value == null) return;

        var any = dataGridView1.Rows.Cast<DataGridViewRow>().Where(
            r => r.Index != row.Index && (bool)r.Cells[0].FormattedValue && r.Cells[2].Value != null).Any(
            r => r.Cells[2].Value.ToString().ToLower() != row.Cells[2].Value.ToString().ToLower());

        if (any)
        {
            // Uncomment if you need to uncheck...
            //row.Cells[0].Value = false;
            //dataGridView1.EndEdit();
            MessageBox.Show("Not same descriptions...");
        }
        else
        {
            // ...
        }
    }
}

Trim .ToLower() calls for the case-sensitive comparisons.

dr.null
  • 4,032
  • 3
  • 9
  • 12