How To: Maintaining Selected Cell in DataGridView When Sorting

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



Hi all,

I had a devil of a time figuring this out, so I thought I'd share it for
anyone who might want to do it.

Problem: The DataGridView's default behavior is to maintain the selection on
the cell relative to the ViewPort when sorting, rather than maintaining the
currently selected cell or row. That is, when the DataGridView is sorted,
the selected cell will change from the currently selected cell to whatever
cell is in the same position relative to the ViewPort.

Conditions: For this particular project, I am designing a custom composite
Control from System.Windows.Forms.UserControl. It contains a DataGridView
(among other things). I therefore am not using the protected event handler
methods, but handling the events with my own event handlers.

In addition, this Control is designed to work with a
System.Windows.Forms.BindingSource (the DataSource property of the
DataGridView) that will always be linked to a DataSet and a DataTable in
that DataSet. So, this solution assumes a DataTable is bound to the Control.
However, what the DataSet is, what the DataTable contains, and any other
specific information is not known, as this Control is designed to accomodate
*any* DataSet/DataTable as a BindingSource (DataSource).

Solution: I started by creating a number of private properties to hold
information about the currently-selected cell:

// Tracks Currently-selected Cell
// The DataGridView.CurrentCell is not useful for this,
// As it doesn't change until *during* sorting.
private DataGridViewCell _CurrentCell = null;

// Used for selecting the new Current Cell
private Point _CurrentPoint = new Point(0,0);

// Prevents event handling when it interferes with the process
private bool _Sorting = false;

// Used for selecting the new Current Cell
private DataRow _CurrentDataRow = null;

// Prevents certain events from being handled
// when a DataException occurs
private bool _DataException = false;

//The following event handler for the DataException event
// sets _DataException to true
// It is, of course, important to have some mechanism for
// resetting _DataException to false somewhere.
private void dataGridView1_DataError(object sender,
DataGridViewDataErrorEventArgs e)
{
// Other error-handling code
_DataException = true;
}

// These lines are copied from the InitializeComponent method
// Of the parent Control
this.dataGridView1.MouseDown += new
System.Windows.Forms.MouseEventHandler(
this.dataGridView1_MouseDown);
this.dataGridView1.Sorted += new
System.EventHandler(this.dataGridView1_Sorted);
this.dataGridView1.DataError += new
System.Windows.Forms.DataGridViewDataErrorEventHandler(
this.dataGridView1_DataError);
this.dataGridView1.CellEnter += new
System.Windows.Forms.DataGridViewCellEventHandler(
this.dataGridView1_CellEnter);

// This event handler occurs as soon as a cell is entered.
// It sets the _CurrentCell
private void dataGridView1_CellEnter(object sender,
DataGridViewCellEventArgs e)
{
if (!_DataException)
{
if (_CurrentCell !=
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex])
_CurrentCell =
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
}
}

// Gets Current Cell and Current Row
// This event is used because it happens before anything else changes
// It uses the ColumnHeadersHeight to test if a Column Header has been
// clicked on. It sets the _CurrentRow and _CurrentPoint,
// which are used to reset the selected cell after sorting.
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Y < dataGridView1.ColumnHeadersHeight)
{
_Sorting = true;
_CurrentDataRow = ((System.Data.DataRowView)
(BindingSource.Current)).Row;
_CurrentPoint = new Point(_CurrentCell.ColumnIndex,
_CurrentCell.RowIndex);
}
}

// This event happens after sorting. The DataGridView.CurrentCell property
has already
// changed. This method changes it to the "last" selected cell.
// Note: The MaintainSelectedRecordOnSort is a public member that
// can be used to turn this behavior off. It is not necessary to use it in
order\
// to set the selected Cell.
private void dataGridView1_Sorted(object sender, EventArgs e)
{
if (_Sorting && MaintainSelectedRecordOnSort)
{
_Sorting = false;
DataView dv = ((System.Data.DataRowView)
(dataGridView1.CurrentRow.DataBoundItem)).DataView;
for (int i = 0; i < dv.Count; i++)
{
if (dv[i].Row.Equals(_CurrentDataRow))
{
dataGridView1.CurrentCell =
dataGridView1.Rows[i].Cells[_CurrentPoint.X];
}
}
}
}

A few more notes: Again, this is a solution for a specifically-purposed
DataGridView. However, it can be modified to support other scenarios. It
occurs to me, however, that using a DataSource that is a BindingSource to a
DataSet/DataTable is likely to be a common use for the DataGridView.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
We got a sick zebra a hat,
you ultimate tuna.





.



Relevant Pages

  • dataGridview
    ... How to get the Cell Size Heigh/width ... CurrentCell is not available before the show ... I need to Resize the Datagridview before its shown ...
    (comp.databases.ms-sqlserver)
  • Re: DataGridView question
    ... Kenny Stultz wrote: ... The dataGridView has a CurrentCell, CurrentCellAddress, and CurrentRow ... These should let you choose which cell gets highlighted. ...
    (microsoft.public.dotnet.languages.vb)
  • VB, implementing the high score within this code
    ... Private possibleAs String ... Private Function SolvePuzzleAs Boolean ... ' Calculates the possible values for all the cell ...
    (microsoft.public.dotnet.languages.vb)
  • Re: DataGridView Enter Key
    ... ProcessDialogKey method in the DataGridView, that is where the Enter key was ... is that the DataGridView key events are not being raised, because the cell ... trap the Enter key when the current cell in edit mode. ... press the Enter key, the KeyDown, KeyPress and KeyUp events are raised in ...
    (microsoft.public.dotnet.framework.windowsforms.controls)
  • Re: DataGridRowView.ContextMenuStrip
    ... Erst in der richtigen Cell die rechte Maustaste. ... Wobei ich hier zum Testen ein DataGridView mit Standardeinstellungen ... der Code hat aber die vom Linksklick. ...
    (microsoft.public.de.german.entwickler.dotnet.vb)