Hi,
I am using Hierarchy (without tabs for child template) grid view and for each master and child row one checkbox required as first column and also required checked changed event for both the check box columns.
Help me on this.
Thanks,
Praveen Palla.
16 Answers, 1 is accepted
There is a KB article explaining how to add a "Check All" in the header cell for a GridViewCheckBoxColumn,
if you also require a check box in the column, otherwise if you just want to know when a specific check box has been checked you can use one of the following events (not both)
void
radGridView1_ValueChanged(
object
sender, EventArgs e)
{
if
(radGridView1.CurrentCell ==
null
)
{
return
;
}
if
(radGridView1.CurrentCell
is
GridCheckBoxCellElement)
{
MessageBox.Show(
string
.Format(
"Value changed for cell on column index {0} and row index {1}"
, radGridView1.CurrentCell.ColumnIndex, radGridView1.CurrentCell.RowIndex));
}
}
void
radGridView1_CellValueChanged(
object
sender, GridViewCellEventArgs e)
{
if
(radGridView1.CurrentCell
is
GridCheckBoxCellElement)
{
MessageBox.Show(
string
.Format(
"Value changed for cell on column index {0} and row index {1}"
, e.ColumnIndex, e.RowIndex));
}
}
The difference between these two being that the ValueChanged event will fire every time the value of the checkbox will change, as for the CellValueChanged, this will only fire when the user will leave that cell (cell validated).
Hope this helps, if you have any other questions or comments, please let me know,
Best Regards,
Emanuel Varga
Telerik WinForms MVP
how should i differenciate the events since I have different functionality
-on selection child row, the parent row should be selected automatically
-on deselection of parent row, all it's child rows should be deselected
Thanks in advance,
Praveen Kumar Palla.
The fastest way of doing this is to always check the parent row, if this is another row, then a child row has been changed, like so:
void
radGridView1_ValueChanged(
object
sender, EventArgs e)
{
if
(radGridView1.CurrentCell ==
null
)
{
return
;
}
if
(radGridView1.CurrentCell
is
GridCheckBoxCellElement)
{
if
(radGridView1.CurrentCell.Parent !=
null
&& radGridView1.CurrentCell.RowInfo.Parent
is
GridViewDataRowInfo)
{
MessageBox.Show(
"Child Row changed"
);
}
else
{
MessageBox.Show(
"Parent row changed!"
);
}
MessageBox.Show(
string
.Format(
"Value changed for cell on column index {0} and row index {1}"
, radGridView1.CurrentCell.ColumnIndex, radGridView1.CurrentCell.RowIndex));
}
}
There are also some other ways, like getting the child template rows and searching for the CurrentCell.RowInfo, if found => child row, else parent row, but in my opinion this way is cleaner and faster.
Hope this helps, if you have any other questions or comments, please let me know,
Best Regards,
Emanuel Varga
Telerik WinForms MVP
Thanks for the responce and I am using vb.net and telerik version (winforms Q3 2009 sp1). Implemented code as below
on form load binding the data to the grid view
Private Sub BethReport_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
Dim dsTemp As New DataSet
dsTemp = objBethReport.getinstitutionsAndSites()
RadGridView1.DataSource = dsTemp.Tables("Institution")
Dim CheckBoxColumn As Telerik.WinControls.UI.GridViewCheckBoxColumn = New Telerik.WinControls.UI.GridViewCheckBoxColumn
CheckBoxColumn.DataType = GetType(Boolean)
CheckBoxColumn.FieldAlias = "Select"
CheckBoxColumn.HeaderText = "Select"
CheckBoxColumn.UniqueName = "Select"
RadGridView1.MasterGridViewTemplate.Columns.Insert(0, CheckBoxColumn)
Dim GridViewTemplate4 As New GridViewTemplate()
GridViewTemplate4.DataSource = dsTemp.Tables("Site")
Dim CheckBoxColumn1 As Telerik.WinControls.UI.GridViewCheckBoxColumn = New Telerik.WinControls.UI.GridViewCheckBoxColumn
CheckBoxColumn1.DataType = GetType(Boolean)
CheckBoxColumn1.FieldAlias = "Select"
CheckBoxColumn1.HeaderText = "Select"
CheckBoxColumn1.UniqueName = "Select"
GridViewTemplate4.Columns.Insert(0, CheckBoxColumn1)
RadGridView1.MasterGridViewTemplate.ChildGridViewTemplates.Add(GridViewTemplate4)
Dim relation As New GridViewRelation(RadGridView1.MasterGridViewTemplate)
relation.ChildTemplate = GridViewTemplate4
relation.RelationName = "Institute-Site"
relation.ParentColumnNames.Add("Institution ID")
relation.ChildColumnNames.Add("Institution ID")
RadGridView1.Relations.Add(relation)
Catch ex As Exception
End Try
End Sub
And the below line is giving exception as 'Parent is not a member of Telerik.Wincontrols.Ui.GridviewRowInfo'
radGridView1.CurrentCell.RowInfo.Parent is GridViewDataRowInfo
And when i use as below
Private Sub RadGridView1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadGridView1.ValueChanged
Try
If RadGridView1.CurrentCell Is Nothing Then
Exit Sub
End If
If TypeOf RadGridView1.CurrentCell Is GridCheckBoxCellElement Then
If RadGridView1.CurrentCell.Parent IsNot Nothing AndAlso TypeOf RadGridView1.CurrentCell.RowInfo Is GridViewDataRowInfo Then
MessageBox.Show("Child Row changed")
Else
MessageBox.Show("Parent row changed!")
End If
End If
Catch ex As Exception
End Try
End Sub
End Class
Always getting the first message only "Child Row Changed" even selecting parent row also
Could you please suggest me on this!
Thanks In Advance.
Praveen.
In your version of the controls, you can use the ViewTemplate property of the GridCellElement to determine if the cell belongs to the parent or the child GridViewTemplate:
Private
Sub
RadGridView1_ValueChanged(
ByVal
sender
As
System.
Object
,
ByVal
e
As
System.EventArgs)
Handles
RadGridView1.ValueChanged
If
RadGridView1.CurrentCell
Is
Nothing
Then
Exit
Sub
End
If
If
TypeOf
RadGridView1.CurrentCell
Is
GridCheckBoxCellElement
Then
If
RadGridView1.CurrentCell.ViewTemplate
Is
RadGridView1.MasterGridViewTemplate
Then
MessageBox.Show(
"Parent row changed!"
)
Else
MessageBox.Show(
"Child Row changed!"
)
End
If
End
If
End
Sub
I hope it helps.Best regards,
Alexander
the Telerik team
Now I am able to find out the parent and child on gridview_value changed event but need small help I want when user deselects the parent check box (first column) all the child check boxes should be unchecked automatically. For this I have implemented the code as below
Private Sub RadGridView1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadGridView1.ValueChanged
Try
If RadGridView1.CurrentCell Is Nothing Then
Exit Sub
End If
If TypeOf RadGridView1.CurrentCell Is GridCheckBoxCellElement Then
Dim editor As RadCheckBoxEditor = TryCast(sender, RadCheckBoxEditor)
If RadGridView1.CurrentCell.ViewTemplate Is RadGridView1.MasterGridViewTemplate Then
If Not editor Is Nothing AndAlso CBool(editor.Value) = False Then
Me.RadGridView1.GridElement.BeginUpdate()
Dim rowIdx As Integer = RadGridView1.CurrentCell.RowIndex
Dim rowInfo As GridViewDataRowInfo = RadGridView1.MasterGridViewInfo.Rows(rowIdx)
Dim childRows As GridViewRowInfo() = RadGridView1.MasterGridViewTemplate.ChildGridViewTemplates(0).GetChildRows(rowInfo)
Dim expandedState As Boolean
expandedState = rowInfo.IsExpanded
rowInfo.IsExpanded = True
If childRows.Length > 0 Then
For i As Integer = 0 To childRows.Length - 1
MessageBox.Show(childRows(i).Cells(0).Value.ToString)
childRows(i).Cells(0).Value = False
MessageBox.Show(childRows(i).Cells(0).Value.ToString)
Next
End If
rowInfo.IsExpanded = expandedState
Me.RadGridView1.GridElement.EndUpdate()
End If
Else
End If
End If
Catch ex As Exception
End Try
End Sub
End Class
Message box is showing true (before update) and false (after update) but in UI, the child check box not getting unchecked (May be not refreshed) how can I achieve this
Could you please suggest me on this.
Thanks,
Praveen kumar Palla.
You can use the Update method to refresh the UI of the control after its data is changed. You should call it for the template which contains the changes. I have added it to your code snippet:
Private
Sub
RadGridView1_ValueChanged(
ByVal
sender
As
System.
Object
,
ByVal
e
As
System.EventArgs)
Handles
RadGridView1.ValueChanged
If
RadGridView1.CurrentCell
Is
Nothing
Then
Exit
Sub
End
If
If
TypeOf
RadGridView1.CurrentCell
Is
GridCheckBoxCellElement
Then
Dim
editor
As
RadCheckBoxEditor = TryCast(sender, RadCheckBoxEditor)
If
RadGridView1.CurrentCell.ViewTemplate
Is
RadGridView1.MasterGridViewTemplate
Then
If
Not
editor
Is
Nothing
AndAlso
CBool
(editor.Value) =
False
Then
Me
.RadGridView1.GridElement.BeginUpdate()
Dim
rowIdx
As
Integer
= RadGridView1.CurrentCell.RowIndex
Dim
rowInfo
As
GridViewDataRowInfo = RadGridView1.MasterGridViewInfo.Rows(rowIdx)
Dim
childRows
As
GridViewRowInfo() = RadGridView1.MasterGridViewTemplate.ChildGridViewTemplates(0).GetChildRows(rowInfo)
Dim
expandedState
As
Boolean
expandedState = rowInfo.IsExpanded
rowInfo.IsExpanded =
True
If
childRows.Length > 0
Then
For
i
As
Integer
= 0
To
childRows.Length - 1
MessageBox.Show(childRows(i).Cells(0).Value.ToString)
childRows(i).Cells(0).Value =
False
MessageBox.Show(childRows(i).Cells(0).Value.ToString)
Next
End
If
rowInfo.IsExpanded = expandedState
Me
.RadGridView1.GridElement.EndUpdate()
Me
.RadGridView1.MasterGridViewTemplate.ChildGridViewTemplates(0).Update(GridUINotifyAction.DataChanged)
End
If
Else
End
If
End
If
End
Sub
I hope it helps you to solve your case.
Kind regards,
Alexander
the Telerik team
Obrigado pelo post.
Hi Team,
Please suggest the way to access HeaderRows in the child templates of the Gridview in the GridView_ValueChanged event, or If I am wrong Please tell the name of the event in which we can access the HeaderRows in the child templates of the Gridview
Thanks And Regards,
Swarupa
Thank you for writing.
You can access the header row from the TableElement.ViewInfo. Here is a sample code snippet demonstrating how to get the GridViewTableHeaderRowInfo in the ValueChanged event when editing a cell from the child template:
private
void
radGridView1_ValueChanged(
object
sender, EventArgs e)
{
BaseGridEditor editor = sender
as
BaseGridEditor;
if
(editor !=
null
)
{
GridDataCellElement cell = editor.OwnerElement
as
GridDataCellElement;
if
(cell.RowInfo.HierarchyLevel > 0)
//you edit a cell in the child template
{
GridViewTableHeaderRowInfo headerRow = cell.TableElement.ViewInfo.TableHeaderRow;
}
}
}
I hope this information helps. Should you have further questions I would be glad to help.
Regards,
Dess
Telerik by Progress
Hi Dess,
Thank you very much for the solution.
I have a three level gridview. I have select All header checkbox in the three levels and I am using KB article. My requirement is : To access the header row of the corresponding child and grand child templates and change their toggle state if the sender is the parent header checkbox (if the Parent gridview header check box is checked/Unchecked).What is the correct event to handle these functions
Can we do the above mentioned things in the checkbox_toggleStatechanged event.
Thanks,
Swarupa
Thank you for writing back.
In the latest the check all functionality is available out of the box for the GridViewCheckBoxColumn by setting the EnableHeaderCheckBox property to true. The HeaderCellToggleStateChanged event is fired when the header checkbox is toggled. Here is available additional information: http://docs.telerik.com/devtools/winforms/gridview/columns/column-types/gridviewcheckboxcolumn
As to the custom implementation, in the header you have access to the TableElement of the current level. I have attached a sample project demonstrating a approach how to toggle the header checkbox and propagate the relevant state to the inner levels. The Tag property for the data row is used in the SetContent method to store the correct state of the checkbox. Note that this is just a sample approach and it may not cover all possible cases. Feel free to modify it in a way which suits your requirement best.
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Dess
Telerik by Progress
Thank you Dess for the solution..
I have three level gridview with checkboxes in the header rows and datarows
I am facing three issues..
1)
I am facing an issue while scrolling horizontally the third level gridview which has almost 12 columns.
I am using the following code ..
private void GvEmployees_CreateCell(object sender, GridViewCreateCellEventArgs e)
{
if (e.Row is GridTableHeaderRowElement && e.Column.HeaderText == "Select All")
{
e.CellElement = new CheckBoxHeaderCell(e.Column, e.Row);
}
}
where checkboxHeaderCell is the KB class
Since the third level gridview has more number of columns, I have to scroll it horizontally.In the scrolling process the table header element is
being treated as Dataelelment instead of header element, so the header checkbox is not created in the third level.
2)
The Solution you have given is working well for the header cells in top down order, I mean when header cell in the parent is checked/unchecked, the
toggle state of the corresponding header check boxes and data check boxes in the child and grandchild are changed properly, but not working as
expected when processed in the reverse order eg..when header checkbox in child is checked, the parent header check box not checked properly.
3)
I am using the following code which I have got from Telerik forums, to work on the data row chekboxes in the multi level gridview.
My final code for handling header row checkboxes and data row chekcboxes is below which is not giving the expected results.
Please provide me solution.
private void GrdiViewResult_CreateCell(object sender, GridViewCreateCellEventArgs e)
{
if (e.Row is GridTableHeaderRowElement && e.Column.HeaderText == "Select All")
{
e.CellElement = new CheckBoxHeaderCell(e.Column, e.Row);
}
}
bool suspendEvent = false;
private void GrdiViewResult_CellValueChanged(object sender, GridViewCellEventArgs e)
{
if (!suspendEvent && e.Column.Name == "column1")
{
List<GridViewHierarchyRowInfo> parents = new List<GridViewHierarchyRowInfo>();
GridViewHierarchyRowInfo parent = e.Row.Parent as GridViewHierarchyRowInfo;
while (parent != null)
{
parents.Add(parent);
parent = parent.Parent as GridViewHierarchyRowInfo;
}
suspendEvent = true;
foreach (GridViewHierarchyRowInfo p in parents)
{
p.Cells["column1"].Value = this.CheckCellsForLevel(e.Row.ViewInfo);
}
GridViewHierarchyRowInfo hierarchyRow = e.Row as GridViewHierarchyRowInfo;
if (hierarchyRow != null)
{
Queue<GridViewHierarchyRowInfo> children = new Queue<GridViewHierarchyRowInfo>();
children.Enqueue(hierarchyRow);
while (children.Count > 0)
{
GridViewHierarchyRowInfo current = children.Dequeue();
foreach (GridViewRowInfo row in current.ChildRows)
{
row.Cells["column1"].Value = e.Value;
if (row is GridViewHierarchyRowInfo)
{
children.Enqueue((GridViewHierarchyRowInfo)row);
}
}
}
}
suspendEvent = false;
}
}
private bool CheckCellsForLevel(GridViewInfo template)
{
foreach (GridViewRowInfo rowInfo in template.Rows)
{
if (rowInfo.Cells["column1"].Value!=null)
{
if ((bool)rowInfo.Cells["column1"].Value == false)
{
return false;
}
}
}
return true;
}
private void GrdiViewResult_ValueChanged(object sender, EventArgs e)
{
GrdiViewResult.EndEdit();
}
public class CheckBoxHeaderCell : GridHeaderCellElement
{
RadCheckBoxElement checkbox;
protected override Type ThemeEffectiveType
{
get
{
return typeof(GridHeaderCellElement);
}
}
public CheckBoxHeaderCell(GridViewColumn column, GridRowElement row) : base(column, row)
{
}
public override void Initialize(GridViewColumn column, GridRowElement row)
{
base.Initialize(column, row);
column.AllowSort = false;
}
public override void SetContent()
{
this.DrawText = false;
checkbox.ToggleStateChanged -= new StateChangedEventHandler(checkbox_ToggleStateChanged);
if (this.RowInfo.Tag != null)
{
this.checkbox.ToggleState = ((ToggleState)this.RowInfo.Tag);
}
checkbox.ToggleStateChanged += new StateChangedEventHandler(checkbox_ToggleStateChanged);
}
protected override void DisposeManagedResources()
{
checkbox.ToggleStateChanged -= new StateChangedEventHandler(checkbox_ToggleStateChanged);
base.DisposeManagedResources();
}
protected override void CreateChildElements()
{
base.CreateChildElements();
checkbox = new RadCheckBoxElement();
checkbox.ToggleStateChanged += new StateChangedEventHandler(checkbox_ToggleStateChanged);
this.Children.Add(checkbox);
}
protected override SizeF ArrangeOverride(SizeF finalSize)
{
SizeF size = base.ArrangeOverride(finalSize);
RectangleF rect = GetClientRectangle(finalSize);
this.checkbox.Arrange(new RectangleF((finalSize.Width - this.checkbox.DesiredSize.Width) / 2, (rect.Height - 20) / 2, 20, 20));
return size;
}
public override bool IsCompatible(GridViewColumn data, object context)
{
return data.Name == "IsChecked" && context is GridTableHeaderRowElement &&
base.IsCompatible(data, context);
}
private void checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args)
{
if (!suspendProcessingToggleStateChanged)
{
bool valueState = false;
if (args.ToggleState == Telerik.WinControls.Enumerations.ToggleState.On)
{
valueState = true;
}
this.GridViewElement.EditorManager.EndEdit();
this.TableElement.BeginUpdate();
UpdateChildren(this.ViewInfo.Rows, valueState);
this.TableElement.EndUpdate(false);
this.RowInfo.Tag = args.ToggleState;
this.TableElement.Update(GridUINotifyAction.DataChanged);
}
}
private void UpdateChildren(GridViewChildRowCollection gridViewChildRowCollection, bool valueState)
{
for (int i = 0; i < gridViewChildRowCollection.Count; i++)
{
int columnIndex = GetIndex(gridViewChildRowCollection[i]);
gridViewChildRowCollection[i].Cells[columnIndex].Value = valueState;
if (gridViewChildRowCollection[i].ChildRows.Count > 0)
{
UpdateChildren(gridViewChildRowCollection[i].ChildRows, valueState);
GridViewHierarchyRowInfo row = gridViewChildRowCollection[i] as GridViewHierarchyRowInfo;
foreach (GridViewDataRowInfo child in row.ViewTemplate.Templates[0].Rows)
{
if (child.Parent== row )
{
child.ViewInfo.TableHeaderRow.Tag = valueState == true ? ToggleState.On : ToggleState.Off;
child.ViewInfo.TableHeaderRow.InvalidateRow();
}
}
}
}
}
private int GetIndex(GridViewRowInfo gridViewRowInfo)
{
int index = -1;
for (int i = 0; i < gridViewRowInfo.Cells.Count; i++)
{
if (gridViewRowInfo.Cells[i].ColumnInfo is GridViewCheckBoxColumn)
{
index = i;
break;
}
}
return index;
}
private bool suspendProcessingToggleStateChanged;
public void SetCheckBoxState(Telerik.WinControls.Enumerations.ToggleState state)
{
suspendProcessingToggleStateChanged = true;
this.checkbox.ToggleState = state;
suspendProcessingToggleStateChanged = false;
}
public override void Attach(GridViewColumn data, object context)
{
base.Attach(data, context);
this.GridControl.ValueChanged += new EventHandler(GridControl_ValueChanged);
}
public override void Detach()
{
if (this.GridControl != null)
{
this.GridControl.ValueChanged -= GridControl_ValueChanged;
}
base.Detach();
}
void GridControl_ValueChanged(object sender, EventArgs e)
{
RadCheckBoxEditor editor = sender as RadCheckBoxEditor;
if (editor != null)
{
GridCellElement cell = editor.OwnerElement as GridCellElement;
cell.GridViewElement.GridControl.EditorManager.EndEdit();
if ((ToggleState)editor.Value == ToggleState.Off)
{
SetCheckBoxState(ToggleState.Off);
}
else if ((ToggleState)editor.Value == ToggleState.On)
{
bool found = false;
foreach (GridViewRowInfo row in cell.ViewInfo.Rows)
{
if (row != this.RowInfo && row.Cells[cell.ColumnIndex].Value == null || !(bool)row.Cells[cell.ColumnIndex].Value)
{
found = true;
break;
}
}
if (!found)
{
cell.TableElement.ViewInfo.TableHeaderRow.Tag = ToggleState.On;
SetCheckBoxState(ToggleState.On);
}
}
}
}
}
Thanks,
Swarupa
Thank you for writing back.
1. The IsCompatible method of the custom cell element is the appropriate place where you can restrict that the custom cell is applicable for the header row and for a specific column. Thus, during operations like scrolling due to the data virtualization in RadGridView, the cell won't be compatible with other columns and won't be reused. However, it is necessary to indicate that the rest of the cell elements shouldn't be applicable for the row/column of your custom cell. That is why it is necessary to create another custom header cell which will be applied the rest of the columns. The following help article demonstrates a approach for creating a custom column which uses a custom cell element and how the IsCompatible method is implemented: http://docs.telerik.com/devtools/winforms/gridview/cells/creating-custom-cells
2. In the RadCheckBoxElement.ToggleStateChanged event the UpdateChildren method is called. This iterates the child rows and toggles the state. It is necessary to implement a similar custom functionality for the parent row, to achieve the desired reversed way from child to parent and update the parent accordingly considering your custom requirement if all of its children are checked.
3. I have created a brand new project with the provided code snippet. When I toggle the header cell's state, the child rows are affected as well. However, when you toggle the data cells one by one, the header is not always affected correctly. I have performed some modifications in order to affect the header as it is demonstrated in the attached gif file.
If you are still experiencing any further difficulties, feel free to submit a support ticket from your account and provide a sample project. Thus, we would be able to investigate the precise case and assist you further. Thank you.
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Dess
Telerik by Progress