views:

363

answers:

1

Is there a way to keep the selected cells of a DataGridView selected after the DataSource is changed?

+2  A: 

You can match what should be selected based on criteria specific to your needs and just set the Select property of either the cell or row to true/false depending on your matching. Here's a simple example you can drop in a newly created winforms project that will illustrate the point. For this example to work make sure you set the DataGridView's SelectionMode = FullRowSelect. If you want to retain/reapply cell selections the approach would be similar. Note : you could also just retain a list of selected row indexes but this typically wouldn't make sense when loading another data source as it's usually unliklely that there would be any correspondence between the actual rows and their physical position in the data.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace DataGridViewRetainSelection
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private readonly List<Person> currentPeople = new List<Person>();
        private bool dummyToggle = true;

        private void Form1_Load(object sender, EventArgs e)
        {
            SwitchDataSource(); // will just new up the datasource
        }

        private void ButtonSwitchDataSourceClick(object sender, EventArgs e)
        {
            SwitchDataSource();
        }

        private void SwitchDataSource()
        {
            var selectedPeople = (from DataGridViewRow row in dataGridViewPeople.Rows where row.Selected select currentPeople[row.Index]).ToList();

            peopleBindingSource.DataSource = null;

            currentPeople.Clear();
            if (dummyToggle)
            {
                currentPeople.Add(new Person { Name = "Joel Spolsky" });
                currentPeople.Add(new Person { Name = "Jeff Atwood" });
                currentPeople.Add(new Person { Name = "Jarrod Dixon" });
                currentPeople.Add(new Person { Name = "Geoff Dalgas" });
                currentPeople.Add(new Person { Name = "Brent Ozar" });
            }
            else
            {
                currentPeople.Add(new Person { Name = "Joel Spolsky" });
                currentPeople.Add(new Person { Name = "Jeff Atwood" });
                currentPeople.Add(new Person { Name = "Brent Ozar" });
            }

            dummyToggle = !dummyToggle;

            peopleBindingSource.DataSource = currentPeople;

            foreach (var person in selectedPeople)
            {
                foreach (DataGridViewRow row in dataGridViewPeople.Rows)
                {
                    if (string.Equals(row.Cells[0].Value, person.Name))
                    {
                        row.Selected = true;
                    }
                }
            }
        }
    }

    public sealed class Person
    {
        public string Name { get; set; }
    }

}

To implement the same functionality for selected cells do something like the following. I'm leaving the previous code should anyone else need it. Note: I'm just banging out an anonymous type here, you're probably going to need to do something a little more sophisticated depending on member fields, properties, etc. but the general principal of setting the selected cells is illustrated properly and can easily be tested and debugged for understanding I hope.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace DataGridViewRetainSelection
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private readonly List<Person> currentPeople = new List<Person>();
        private bool dummyToggle = true;

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridViewPeople.SelectionMode = DataGridViewSelectionMode.CellSelect;
            SwitchDataSource(); // will just new up the datasource
        }

        private void ButtonSwitchDataSourceClick(object sender, EventArgs e)
        {
            SwitchDataSource();
        }

        private void SwitchDataSource()
        {
            var selectedPeopleAndCells = (from DataGridViewCell cell in dataGridViewPeople.SelectedCells where cell.Selected select new { Person = currentPeople[cell.RowIndex], Cell = cell }).ToList();

            peopleBindingSource.DataSource = null;

            currentPeople.Clear();
            if (dummyToggle)
            {
                currentPeople.Add(new Person { Name = "Joel Spolsky", Id = 0 });
                currentPeople.Add(new Person { Name = "Jeff Atwood", Id = 1 });
                currentPeople.Add(new Person { Name = "Jarrod Dixon", Id = 2 });
                currentPeople.Add(new Person { Name = "Geoff Dalgas", Id = 3 });
                currentPeople.Add(new Person { Name = "Brent Ozar", Id = 4 });
            }
            else
            {
                currentPeople.Add(new Person { Name = "Joel Spolsky", Id = 0 });
                currentPeople.Add(new Person { Name = "Jeff Atwood", Id = 1 });
                currentPeople.Add(new Person { Name = "Brent Ozar", Id = 4 });
            }

            dummyToggle = !dummyToggle;

            peopleBindingSource.DataSource = currentPeople;

            foreach (var personAndCell in selectedPeopleAndCells)
            {
                foreach (DataGridViewRow row in dataGridViewPeople.Rows)
                {
                    if (string.Equals(row.Cells[0].Value, personAndCell.Person.Id))
                    {
                        row.Cells[personAndCell.Cell.ColumnIndex].Selected = true;
                    }
                }
            }
        }
    }

    public sealed class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

}
Dave Jellison
Well works but the entire row is gets selected... I wanted to keep randomly selected cells in the DGV;
Y_Y
Code sample updated to illustrate cell selection.
Dave Jellison
Please note, you're going to need some kind of ID field to match old rows to new rows accurately. Hopefully the example makes that fairly clear.
Dave Jellison