DataGridView: prevent column reorder for one column
It is more a beautification issue, but nevertheless what is a GUI for....
I have a DataGridView and it displays depending on the data different columns. I allow the user to reorder and resize columns, but also give him an "AutoSize" button to readjust the widths of the columns if he messes up. Because I do not know how long the data in the columns is, I start with sizing the columns by "AllCells" except the very last one (highest DisplayIndex) which I size to "Fill". Now I discovered that this looks really ugly when the last column is just a CheckBoxColumn, so to cover all cases more nicely I added one dummy column with no header text which should always stay the last column and sizes to fill remaining space.
Adding the column and sizing it is not problem, but I cannot figure out a way to prevent the user from reordering this column to another spot. I tried to hook into the "ColumnDisplayIndexChanged" event and reset the column display index to the maximum DisplayIndex allowed in the grid to keep it at the end, but that operation is not allowed in this event: "System.InvalidOperationException: This operation cannot be performed while the DisplayIndex of a column is being adjusted."
Best would be to prevent the user from even start dragging the column when he clicks on the header, but I have no idea yet of how to accomplish that either.
Does anybody have any suggestions of how to solve this?
[1494 byte] By [
John.Doe] at [2007-12-24]
Actually I figured out how to prevent a user from dragging a specfic column: In OnMouseDown check if the mouse button was pressed over the header of the column, if so set AllowUserToReorderColumns to false and restore the value again in OnMouseUp.
But that was just to discover that I did not invest enough thought in this, because that still does not prevent the user from draggin any other column behind the last column. So I really need to check for the DisplayIndexChanged event and undo the change if the last column is not the dummy column anymore. As I cannot do this reset of the the display indexes inside the eventhandler I must somehow postpone this operation until the event is finished. How would I do that?
Uh... I got it figured out... wicked code ;)
Just to share it, here is a piece of code that would keep the first column always the first column:
void dataGridView_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
if ((e.Column.Index == 0) && (e.Column.DisplayIndex != 0))
{
MouseEventHandler mouseEventHandlerToRemove = null;
MouseEventHandler mouseEventHandler = delegate(object sender1, MouseEventArgs mouseEventArgs)
{
this.dataGridView.Columns[0].DisplayIndex = 0;
this.dataGridView.MouseUp -= mouseEventHandlerToRemove;
};
mouseEventHandlerToRemove = mouseEventHandler;
this.dataGridView.MouseUp += mouseEventHandler;
}
}The column is dragged to a different position with the mouse. If it is the first column which was just due to this action, I hook to the mouse up event to reset the display index of that column to 0 again, after that the delegate removes itself again from the event.
Hi John,
Your solution seems very attractive to me.
I'm a beginner in .NET development. Could you please highlight me how to realize your solution in VB.NET?
I searched for some VB.NET delegates references but not sure how to implement this mouseEvent thing...
Thanks!
Jason
I appreciate your solution, because it will help me for my need: I have three columns in one group, a center 'group', and 3 more columns in another group and I want to prevent any column from columns 1-3 being moved beyond column 4 and I think this will do it for me.
For your issue, though, I think there's a better solution (which unfortunately won't work for me...).
If you make all of your "real" columns set with the property "Frozen" to true and leave the last one 'Frozen=False', then it should prevent the mixing automatically.
P.S. to .Net developers: What this control needs is an intermediate event (c.f. "Closing" or "Opening") which can be cancelled by code to prevent such movements without resorting to this rather "wicked" code.
Bob