Hi,
I'm trying to manually handle the synchronization of the header checkbox and the cell values in a grid with filtering and group by functionality enabled.
Filtered out rows should not be updated by the header checkbox, so in the AfterHeaderCheckStateChanged handler, I'm only updating the rows returned by the e.Rows.GetFilteredInNonGroupByRows() method:
private void AfterHeaderCheckStateChanged_EventHandler(object sender, AfterHeaderCheckStateChangedEventArgs e)
{
if (_isInCellChange > 0) return; //Return if event is triggered by the SetHeaderCheckedState() in the CellChange event
bool isChecked = e.Column.GetHeaderCheckedState(e.Rows) == CheckState.Checked;
foreach (var filteredInNonGroupByRow in e.Rows.GetFilteredInNonGroupByRows())
filteredInNonGroupByRow.Cells[e.Column].SetValue(isChecked, false);
}
Updating the header checkbox when a cell value is changed is handled in the CellChange event:
private void CellChange_EventHandler(object sender, CellEventArgs e)
if (e.Cell.Column.Index != 2) return; //Checkbox column is index 2
_isInCellChange++;
var cell = e.Cell;
var column = cell.Column;
var rowsCollection = cell.Row.ParentCollection;
var newCellValue = (bool)cell.EditorResolved.Value;
CheckState currentCheckState = column.GetHeaderCheckedState(rowsCollection);
if (newCellValue)
if (currentCheckState != CheckState.Checked)
bool shouldCheckHeader = true;
foreach (var row in rowsCollection.GetFilteredInNonGroupByRows())
var cellInRow = row.Cells[column];
if ((bool)cellInRow.EditorResolved.Value == false)
shouldCheckHeader = false;
break;
if (shouldCheckHeader)
column.SetHeaderCheckedState(rowsCollection, true);
else
column.SetHeaderCheckedState(rowsCollection, false);
_isInCellChange--;
Two issues:
When the grid is grouped by a column (not the checkbox column), the checkbox header is unchecked and all child-elements are set to false (unchecked). How can I prevent this?
When the filter is changed, the header checkbox is not updated - this is why the synchronization has to be done manually as far as I understand. But how can I force an update of the checkbox state after the filter is changed? Checkbox state should be determined based on the filtered in rows only.
Thanks in advance
Hello,
The current state of the header checkbox is stored on the RowsCollection when the synchronization is set to None. When the GroupBy functionality of the grid is used, different sets of RowCollections are generated (1 RowsCollection for the group of GroupByRows, and a RowsCollection for each GroupByRow that contains all the child rows in each group). When a header is generated for a new RowsCollection that has not had it's header checkbox state specified yet, the header initializes the state to UnChecked which is firing the Before/AfterHeaderCheckStateChanged events. This is triggering your custom synchronization in the AfterHeaderCheckStateChanged event handler. To get around this, I suggest handling grid's InitializeGroupByRow event, and synchronizing the header to match the values in the e.Rows.Rows collection.
Try the following code:
private void ultraGrid1_InitializeGroupByRow(object sender, InitializeGroupByRowEventArgs e) { this.SynchronizeHeader(e.Row.Band.Columns[2], e.Row.Rows); } private int _isInSynchronizeHeader = 0; private void SynchronizeHeader(UltraGridColumn column, RowsCollection rows) { this._isInSynchronizeHeader++; bool allTrue = true; bool allFalse = true; foreach (UltraGridRow row in rows.GetFilteredInNonGroupByRows()) { if ((bool)row.Cells[column].Value == true) { allFalse = false; } else { allTrue = false; } } CheckState state = CheckState.Indeterminate; if (allFalse) state = CheckState.Unchecked; else if (allTrue) state = CheckState.Checked; column.SetHeaderCheckedState(rows, state); this._isInSynchronizeHeader--; }
Make sure to added a _isInSynchronizeHeader flag check to your AfterHeaderCheckStateChanged event handler.
if (this._isInSynchronizeHeader > 0) return; //Return if event is triggered by the SetHeaderCheckedState() in the InitializeGroupByRow event
Let me know if you have any other questions.
Chris
Thanks,
That solved the group-by issue.
My only problem now is how to trigger an update of the header checkbox(es) when a filter is changed. How do I get a reference to all RowsCollection when the grid is grouped?
Thanks again.
If you are utilizing the AfterRowFilterChanged event, I believe you can get to the RowsCollection for the Band via e.Column.Band.Layout.Rows.
Thanks! That's exactly what I was after