protected
void grdOrderItems_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item.OwnerTableView.Name == "Steps")
{
if (e.Item is GridDataItem && !e.Item.IsInEditMode)
{
string stepId = e.Item.OwnerTableView.DataKeyValues[e.Item.ItemIndex]["Id"].ToString();
GridDataItem item = e.Item as GridDataItem;
// item.DataItem is valid here
GridDataItem parentItem = item.OwnerTableView.ParentItem;
// parentItem.DataItem is returning null
}
}
}
15 Answers, 1 is accepted
The above given code must work correctly. Can you confirm whether 'Steps' is the Name that you have set for the Master or Detail table. You can also refer the following help article which explains how to access ParentItem from Detail table.
Extracting primary key value for parent item in hierarchy on Update/Insert
Thanks
Shinu
GridDataItem item = e.Item as GridDataItem;
OrderItemSummay os = item.DataItem;
Where OrderItemSummary is the name of my object. However, when I run the original code where I try to access the object of the parent table I get a NULL returned. So if I write the code:
GridDataItem item = e.Item as GridDataItem;
GridDataItem parentItem = item.OwnerTableView.ParentItem;
OrderItemStep step = parentItem.DataItem;
Then step return NULL.
Thanks
One suggestion is adding the field (here it is 'user_role') into the DataKeyNames collection of RadGrid. Then in ItemDataBound, as mentioned in the above post get reference to e.Item.OwnerTableView.ParentItem and access the value using GetDataKeyValue() method.
ASPX:
<
telerik:RadGrid
ID
=
"RadGrid1"
. . . . . . >
<
MasterTableView
Name
=
"Master"
runat
=
"server"
DataKeyNames
=
"EmployeeID,user_role"
. . . . . . . >
. . . . . . . . . . . . . . . . . .
C#:
protected
void
RadGrid1_ItemDataBound(
object
sender, GridItemEventArgs e)
{
if
(e.Item.OwnerTableView.Name ==
"DetailTable"
)
{
if
(e.Item
is
GridDataItem )
{
GridDataItem parentItem = e.Item.OwnerTableView.ParentItem;
string
user_role = parentItem.GetDataKeyValue(
"user_role"
).ToString();
}
}
}
Accessing cells and rows
Thanks,
Princy.
In our DetailTableDataBind event we expected to be able to get the underlying data item on the parent row by doing this:
protected void grdFees_DetailTableDataBind(object sender, GridDetailTableDataBindEventArgs e)
{
MyCustomObject obj = (MyCustomObj)e.DetailTableView.ParentItem.DataItem;
...
}
but the DataItem is always null..
Any thoughts?
Thanks,
Mike
As far as I know, DataItem is not directly available in DetailTableDataBind event. It is available only in the bound event of the grid. There are two options to get the field from your underlying DataSource.
if the column(field) is not present in MasterTableView, you can use DataKeyNames/DataKeyValues instead and then use the key value to find the respective field from your ParentItem row.
ASPX:
<
telerik:RadGrid
ID
=
"RadGrid1"
. . . . . . >
<
MasterTableView
Name
=
"Master"
runat
=
"server"
DataKeyNames
=
"EmployeeID,user_role"
. . . . . . . >
C#:
protected
void
RadGrid1_ItemDataBound(
object
sender, GridItemEventArgs e)
{
if
(e.Item.OwnerTableView.Name ==
"DetailTable"
)
{
if
(e.Item
is
GridDataItem )
{
GridDataItem parentItem = e.Item.OwnerTableView.ParentItem;
string
user_role = parentItem.GetDataKeyValue(
"user_role"
).ToString();
}
}
}
Or if the column(field) is visible in MasterTableView, then you can access it by using its ColumnUniqueName.
C#:
protected
void
RadGrid1_DetailTableDataBind(
object
source, GridDetailTableDataBindEventArgs e)
{
GridDataItem dataItem = (GridDataItem)e.DetailTableView.ParentItem;
// accessing parent data item
string
id = dataItem[
"ColumnUniqueName"
].Text;
// access cell value of parent row by using its ColumnUniqueName
}
Thanks,
Princy.
Hi all,
I have a scenario where I want to extract Parent Item and Parent/Parent item from Child or Child/Child while Child/Child Table is in Edit Mode.
Parent Item and Parent/Parent item's are not data key values. Refer to attached.
Another word when I am editing DetailTables: 'Details' with Productid: 14:
1) I would like to capture Employee id: 3 of Orderid: 10625 from DetailTables: 'Orders'.
2) Capture Customer Name: Ana Trujillo of CustomerId: Anatar from MasterTableView: 'Customers'
Hierarchy is below:
MasterTableView: 'Customers'
DetailTables: 'Orders'
DetailTables: 'Details'
____
Any help will be appreciated.
gc_0620
Hello,
Try this example: Assuming the 3 level hierarchical RadGrid markup is configured as follows:
<telerik:RadGrid ID="RadGrid1" runat="server"
OnItemCommand="RadGrid1_ItemDataBound">
<MasterTableView Name="MasterTable" DataKeyNames="MasterID">
<DetailTables>
<telerik:GridTableView Name="ChildTable" DataKeyNames="ChildID">
<DetailTables>
<telerik:GridTableView Name="GrandChildTable" DataKeyNames="GrandChildID">
</telerik:GridTableView>
</DetailTables>
</telerik:GridTableView>
</DetailTables>
</MasterTableView>
</telerik:RadGrid>
In the ItemDataBound event when Editing:
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item.IsInEditMode && e.Item.OwnerTableView.Name == "GrandChildGrid")
{
// Capture the ItemDataBound event of the GrandChildTable
GridTableView grandChildTable = e.Item.OwnerTableView;
// Access the parents by Going up on the tree
GridDataItem parentItem = grandChildTable.NamingContainer as GridDataItem; // ChildTable Row
var parentTableKeyValue = parentItem.GetDataKeyValue("SomeField"); // ChildTable DataKeyValue
GridTableView parentTable = parentItem.OwnerTableView; // ChildTable
GridDataItem grandParentItem = parentTable.NamingContainer as GridDataItem; // MasterTable Row
var grandParentTableKeyValue = grandParentItem.GetDataKeyValue("SomeField"); // MasterTable DataKeyValue
GridTableView grandParentTable = grandParentItem.OwnerTableView; // MasterTable
}
}
Kind regards,
Attila Antal
Progress Telerik
Dear Attila
I fully understand your examples but they give me access to the master key on the event that is happening in the page that contains the grid. But please tell me how I get the master key inside the edit control that is opened popup when editing the record. Inside that edit control i dont have access to the parent key this way.
As long as I'm editing an existing child the _dataitem object will contain that info but when I'm adding a new child item the _dataitem object is kind of empty and does not contain the parent key.
Could you please pass an example where the parent key is obtained inside the code behind of the custom edit control that is used for editing the child record and also in the specific situation that there is an add record action and not an edit action on an existing child record.
Hope my question is now clear.
Kind regards
Hi,
I assume that you are trying to access the parentItem.Dataitem object which returns null. This is the correct behavior as this information is only available in the ItemDataBound event for the current item for which the event is raised. In this case that would be the e.Item.DataItem. That is how we keep our application lightweight. If all information were kept across all postbacks and events, the performance will decrease, loading time will increase.
If you want to fetch the Key Values from the Parent or Grand parent tables, you must define those fields in the DataKeyValues collection. Once you have access to the Data Key Value using the GetDataKeyValue() method, you can use this key to query the database/table.
Here is a complete example for a Hierarchy with Programmatic Binding and accessing Parent/Child data by querying using Data key values.
Place the following snippet into an ASPX page:
<telerik:RadGrid ID="RadGrid1" runat="server"
AutoGenerateEditColumn="true"
OnItemDataBound="RadGrid1_ItemDataBound"
OnDetailTableDataBind="RadGrid1_DetailTableDataBind"
OnNeedDataSource="RadGrid1_NeedDataSource">
<MasterTableView Name="Customers" DataKeyNames="CustomerID">
<DetailTables>
<telerik:GridTableView Name="Orders" DataKeyNames="OrderID">
<DetailTables>
<telerik:GridTableView Name="Details" DataKeyNames="ProductID">
</telerik:GridTableView>
</DetailTables>
</telerik:GridTableView>
</DetailTables>
</MasterTableView>
</telerik:RadGrid>
Place the following C# code snippet in the code behind of the ASPX page:
private string sessionKey = "MyKey";
public MyDataBase SessionDataSource
{
get
{
if (!IsPostBack || Session[sessionKey] == null)
{
MyDataBase db = new MyDataBase();
var IncrementalOrderID = 0;
db.Customers = Enumerable.Range(1, 5).Select(cIndex => new Customer()
{
// Customer
CustomerID = cIndex,
CustomerName = "First Last " + cIndex,
CustomerOrders = Enumerable.Range(1, 3).Select(oIndex => new Order()
{
// Order
OrderID = ++IncrementalOrderID,
CustomerID = cIndex,
OrderDetails = Enumerable.Range(1, 3).Select(dIndex => new OrderDetail()
{
// OrderDetail
ProductID = oIndex + dIndex,
OrderID = IncrementalOrderID,
OrderDescription = "Description " + dIndex
}).ToList()
}).ToList()
}).ToList();
db.Orders = db.Customers.SelectMany(cust => cust.CustomerOrders).ToList();
db.OrderDetails = db.Orders.SelectMany(ord => ord.OrderDetails).ToList();
Session[sessionKey] = db;
}
return (MyDataBase)Session[sessionKey];
}
set
{
Session[sessionKey] = value;
}
}
protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
{
if (!e.IsFromDetailTable)
{
(sender as RadGrid).DataSource = SessionDataSource.Customers;
}
}
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
// When in Edit Mode
if (e.Item.IsInEditMode && e.Item.OwnerTableView.Name == "Details")
{
GridTableView TableDetails = e.Item.OwnerTableView;
GridNestedViewItem OrderNestedItem = TableDetails.NamingContainer as GridNestedViewItem;
GridDataItem orderRow = OrderNestedItem.ParentItem;
GridTableView TableOrder = orderRow.OwnerTableView;
var OrderID = orderRow.GetDataKeyValue("OrderID");
// Query database - Orders table for records with this OrderID
GridNestedViewItem CustomerNestedItem = TableOrder.NamingContainer as GridNestedViewItem;
GridDataItem customerRow = CustomerNestedItem.ParentItem;
GridTableView TableCustomer = customerRow.OwnerTableView;
var CustomerID = customerRow.GetDataKeyValue("CustomerID");
// Query database - Customers table for records with this CustomerID
}
}
protected void RadGrid1_DetailTableDataBind(object sender, GridDetailTableDataBindEventArgs e)
{
GridNestedViewItem ParentNestedView = e.DetailTableView.NamingContainer as GridNestedViewItem;
GridDataItem parentItem = ParentNestedView.ParentItem;
switch (e.DetailTableView.Name)
{
case "Orders":
int CustomerID = (int)parentItem.GetDataKeyValue("CustomerID");
var Orders = SessionDataSource.Orders.Where(o => o.CustomerID == CustomerID);
e.DetailTableView.DataSource = Orders;
break;
case "Details":
int OrderID = (int)parentItem.GetDataKeyValue("OrderID");
var OrderDetails = SessionDataSource.OrderDetails.Where(od => od.OrderID == OrderID);
e.DetailTableView.DataSource = OrderDetails;
break;
}
}
public class MyDataBase
{
public List<Customer> Customers { get; set; }
public List<Order> Orders { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
public class Customer
{
public int CustomerID { get; set; }
public string CustomerName { get; set; }
public List<Order> CustomerOrders { get; set; }
}
public class Order
{
public int OrderID { get; set; }
public int CustomerID { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
public class OrderDetail
{
public int ProductID { get; set; }
public int OrderID { get; set; }
public string OrderDescription { get; set; }
}
Kind regards,
Attila Antal
Progress Telerik
Dear Attila<
I appreciate your help but we keep talking on two different tracks. Let me explain better my problem:
In a page I have the hierarchy grid (RadGV_DATA). its configured to use popup edit with a user control.
RadGV_DATA.MasterTableView.DetailTables(0).EditFormSettings.UserControlName = "specification_edit.ascx"
So far no problem. When I edit an existing record I can get the detailid of that record and that is all I need. However when I add a new child I need to know the parent ID to be able to add the record to the correct parent ID.
Currently I can get this parent ID in the page itself. No problem there. You gave me three other ways to get that key as well but in the main page its easy. No issue.
However, how to get the key in the edit control code behind (specification_edit.ascx).
In that control I have:
Public Property DataItem() As Object
Get
Return Me._dataItem
End Get
Set(ByVal value As Object)
Me._dataItem = value
End Set
End Property
In the load event of the control
Try
HF_DETAILID.Value = DataBinder.Eval(DataItem, "DETAILID").ToString()
If HF_DETAILID.Value = "" Then
HF_DETAILID.Value = 0
End If
Catch
End Try
When editing an existing child the detail ID will be the right one. When adding a new one the detail ID will be set to 0. Thats fine.
But when the detail ID =0 the control needs to know the parent key ID to be able to insert the new child for the correct parent record ID.
I use:
CType(Page.FindControl("HF_MATERIAALBUDGETID"), HiddenField).Value
Where the HF_MATERIAALBUDGETID is the parent key I need and is set on edit in the page that contains the grid. By reading that key from the hiddenfield I bypass my problem that I dont know a more sophisticated way to get that ID inside the code behind of the control.
All your examples as far as I can see show me how to get all kinds of keys but always inside the main page that contains the radgrid and never in a custom user control that is used for the edit / append action.
Hope this helps to point me to a more sophisticated method. if not then I use the bypass as I already do for ages. I was just wondering if things could be done more intelligent.
Kind regards
Hello,
Regardless, how many controls are nested (UserControl inside UserControl inside another UserControl) when using the Grid events, you can access the parents, parents of parent in the same way.
Here is the complete VB example of how to access the Parent Item's DataKeyValue from the EditForm itself (the form that is actually a usercontrol and is popping up). Try this code and place a debugger inside the InsertCommand after the OrderID variable and you'll be able to see the value you are looking for.
RadGrid on the ASPX Page:
<telerik:RadGrid ID="RadGrid1" runat="server"
AutoGenerateEditColumn="true"
OnPreRender="RadGrid1_PreRender"
OnItemDataBound="RadGrid1_ItemDataBound"
OnDetailTableDataBind="RadGrid1_DetailTableDataBind"
OnInsertCommand="RadGrid1_InsertCommand"
OnNeedDataSource="RadGrid1_NeedDataSource">
<MasterTableView Name="Customers" DataKeyNames="CustomerID">
<DetailTables>
<telerik:GridTableView Name="Orders" DataKeyNames="OrderID">
<DetailTables>
<telerik:GridTableView Name="Details" DataKeyNames="ProductID" EditMode="PopUp" CommandItemDisplay="Top">
<EditFormSettings EditFormType="WebUserControl" UserControlName="WebUserControl.ascx">
</EditFormSettings>
</telerik:GridTableView>
</DetailTables>
</telerik:GridTableView>
</DetailTables>
</MasterTableView>
</telerik:RadGrid>
WebUserControl.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl_WebUserControl" %>
<telerik:RadLabel ID="RadLabel1" runat="server" Text="Order Description"></telerik:RadLabel>
<telerik:RadTextBox ID="RadTextBox1" runat="server" Text='<%# Bind("OrderDescription") %>'></telerik:RadTextBox>
<telerik:RadButton ID="RadButton1" runat="server" Text="Update" CommandName="PerformInsert"></telerik:RadButton>
Code behind file of the ASPX Page
Class SurroundingClass
Private sessionKey As String = "MyKey"
Public Property SessionDataSource As MyDataBase
Get
If Not IsPostBack OrElse Session(sessionKey) Is Nothing Then
Dim db As MyDataBase = New MyDataBase()
Dim IncrementalOrderID = 0
db.Customers = Enumerable.Range(1, 5).[Select](Function(cIndex) New Customer() With {
.CustomerID = cIndex,
.CustomerName = "First Last " & cIndex,
.CustomerOrders = Enumerable.Range(1, 3).[Select](Function(oIndex) New Order() With {
.OrderID = System.Threading.Interlocked.Increment(IncrementalOrderID),
.CustomerID = cIndex,
.OrderDetails = Enumerable.Range(1, 3).[Select](Function(dIndex) New OrderDetail() With {
.ProductID = oIndex + dIndex,
.OrderID = IncrementalOrderID,
.OrderDescription = "Description " & dIndex
}).ToList()
}).ToList()
}).ToList()
db.Orders = db.Customers.SelectMany(Function(cust) cust.CustomerOrders).ToList()
db.OrderDetails = db.Orders.SelectMany(Function(ord) ord.OrderDetails).ToList()
Session(sessionKey) = db
End If
Return CType(Session(sessionKey), MyDataBase)
End Get
Set(ByVal value As MyDataBase)
Session(sessionKey) = value
End Set
End Property
'This method fires when Inserting a new Item into
Protected Sub RadGrid1_InsertCommand(ByVal sender As Object, ByVal e As GridCommandEventArgs)
' currently edited item (Edit Form Insert item)
' This is the Pop Up element with its controls in it
Dim insertItem As GridEditFormInsertItem = TryCast(e.Item, GridEditFormInsertItem)
'Current Table for which the event is fired
Dim currentTable As GridTableView = insertItem.OwnerTableView
'Condition to only run the next few lines if the event is fired for the Details table
If currentTable.Name = "Details" Then
'Nested Container holding the Details table
Dim parentNestedViewItem As GridNestedViewItem = TryCast(currentTable.NamingContainer, GridNestedViewItem)
'GridDataItem that belongs to the Orders table, and is parent of Details table
Dim parentItem As GridDataItem = TryCast(parentNestedViewItem.DataItem, GridDataItem)
'extract the DataKeyValues of Orders Table
Dim OrderID = parentItem.GetDataKeyValue("OrderID")
'Orders table
Dim ordersTableView As GridTableView = parentNestedViewItem.OwnerTableView
End If
End Sub
Protected Sub RadGrid1_NeedDataSource(ByVal sender As Object, ByVal e As GridNeedDataSourceEventArgs)
If Not e.IsFromDetailTable Then
(TryCast(sender, RadGrid)).DataSource = SessionDataSource.Customers
End If
End Sub
Protected Sub RadGrid1_ItemDataBound(ByVal sender As Object, ByVal e As GridItemEventArgs)
If e.Item.IsInEditMode AndAlso e.Item.OwnerTableView.Name = "Details" Then
Dim TableDetails As GridTableView = e.Item.OwnerTableView
Dim OrderNestedItem As GridNestedViewItem = TryCast(TableDetails.NamingContainer, GridNestedViewItem)
Dim orderRow As GridDataItem = OrderNestedItem.ParentItem
Dim TableOrder As GridTableView = orderRow.OwnerTableView
Dim OrderID = orderRow.GetDataKeyValue("OrderID")
Dim CustomerNestedItem As GridNestedViewItem = TryCast(TableOrder.NamingContainer, GridNestedViewItem)
Dim customerRow As GridDataItem = CustomerNestedItem.ParentItem
Dim TableCustomer As GridTableView = customerRow.OwnerTableView
Dim CustomerID = customerRow.GetDataKeyValue("CustomerID")
End If
End Sub
Protected Sub RadGrid1_DetailTableDataBind(ByVal sender As Object, ByVal e As GridDetailTableDataBindEventArgs)
Dim ParentNestedView As GridNestedViewItem = TryCast(e.DetailTableView.NamingContainer, GridNestedViewItem)
Dim parentItem As GridDataItem = ParentNestedView.ParentItem
Select Case e.DetailTableView.Name
Case "Orders"
Dim CustomerID As Integer = CInt(parentItem.GetDataKeyValue("CustomerID"))
Dim Orders = SessionDataSource.Orders.Where(Function(o) o.CustomerID = CustomerID)
e.DetailTableView.DataSource = Orders
Case "Details"
Dim OrderID As Integer = CInt(parentItem.GetDataKeyValue("OrderID"))
Dim OrderDetails = SessionDataSource.OrderDetails.Where(Function(od) od.OrderID = OrderID)
e.DetailTableView.DataSource = OrderDetails
End Select
End Sub
Public Class MyDataBase
Public Property Customers As List(Of Customer)
Public Property Orders As List(Of Order)
Public Property OrderDetails As List(Of OrderDetail)
End Class
Public Class Customer
Public Property CustomerID As Integer
Public Property CustomerName As String
Public Property CustomerOrders As List(Of Order)
End Class
Public Class Order
Public Property OrderID As Integer
Public Property CustomerID As Integer
Public Property OrderDetails As List(Of OrderDetail)
End Class
Public Class OrderDetail
Public Property ProductID As Integer
Public Property OrderID As Integer
Public Property OrderDescription As String
End Class
End Class
Regards,
Attila Antal
Progress Telerik
Dear Attila,
Problem is now solved.
Thanks again for your elaborate effort and time to help me solve my issue. You put me now on the right track and together with some other help topic from Telerik (https://docs.telerik.com/devtools/aspnet-ajax/controls/grid/data-editing/edit-mode/custom-edit-forms) I was able to solve the issue.
My approach was : try to get the datakey value from the parent row in the code behind of the custom edit user control. However its a much more smart approach to turn it the other way around. From the main page set the value you need in the custom edit user control. Getting the parent key in the main page where the radgrid is hosted is easy and using the ondatabind method it is possible to reference a control inside the edit user control from the code behind in the main page.
Below is my approach now and this solves the problem:
Protected Sub RadGV_DATA_ItemDataBound(ByVal sender As Object, ByVal e As Telerik.Web.UI.GridItemEventArgs) Handles RadGV_DATA.ItemDataBound
If (e.Item.IsInEditMode And e.Item.OwnerTableView.Name = "DetailView") Then
Dim my_nestedItem As GridNestedViewItem
Dim my_mainrow As GridDataItem
my_nestedItem = e.Item.OwnerTableView.NamingContainer
my_mainrow = my_nestedItem.ParentItem
Dim MyUserControl As UserControl = CType(e.Item.FindControl(GridEditFormItem.EditFormUserControlID), UserControl)
Dim LBL1 As Label = CType(MyUserControl.FindControl("LBL_PARTNER"), Label)
LBL1.Text = my_mainrow.GetDataKeyValue("MATERIAALBUDGETID")
End If
End Sub
The above code reads the key of the main row (the parent from the child I want to add) in the way you pointed out. Then in the databound event I also reference the edit control and find the control (label) I want to manipulate inside that referenced control. This works. Now I'm able to pass a parameter to the edit control which can be used on a later record insert action.
Thank you for your support and helping me to think from the main page ==> edit control instead of thinking from the edit control ==> main page.
kind regards
Thanks Attila,
Your solution works.
My another question is I would like to export only Selected Parent Record, related Child Records and Related Grand Child Records into PDF Format.
Below is prototype I am using.
Another word:
If I choose Customer Id 'ANATAR' and click a button 'Export to PDF selected row'
1) It should Export all columns from just Customer Id 'ANATAR' row
2) All Order id's that belongs to Customer Id 'ANATAR' without expending Customer id Row
3) All Product Id's that belongs to Customer Id 'ANATAR' expending Customer id/Order Id Row
Refer to attached (Export all Child_Grand_Child Records Selected Record into PDF.png)
My desired export to PDF result set should be Form Template Edit form for Selected Parent Record, related Child Records and Related Grand Child Records. Like below format.
Thanks for your help.
sincerely
gc_0620
Hi gc_0620,
Please inspect the following articles which are discussing the topic of exporting RadGrid with hierarchy and export only selected rows. You can try and modify the samples provided in this article to achieve the required output.
- Grid Hierarchy Export
- Export RadGrid with hierarchy and grouping to Excel and Word
- Export Hierarchical Grid
- Export grouped grid to CSV
- Exporting only selected rows
- Export DataRow from Selected Grid row to Excel on Button Click
- Radgrid; export only selected rows
You might also need to know how to loop through the DetailTables/NestedViews following the instructions from Traversing detail tables/items in Telerik RadGrid.
Kind regards,
Attila Antal
Progress Telerik