Hi,
(I have removed any business specific information from the markup and code samples)
I have a problem with binding to a hierarchical data structure. The structure for the grid is following:
Type1 and Type2 naturally have different properties.
For all levels I use custom sorting, custom paging and custom filtering. I get all data for the entire grid (all sub levels included) in the Page_PreRender stage (of the UserControl the Grid is in).
The problem is that I have not been able to get the detail grids to bind at all after I expand a row.
Here is a little bit of background information before I go on:
The life cycle of the control is following:
1. At Init (of the user control) the user control registeres it to the page. The user control implements a custom IView interface and the Page implements a custom IViewContiner interface. The code for this is following:
2. In the the containing Page's Page_LoadComplete the Page calls all its IView (user control) objects Initialize method where the user control collects its state information and sends it to an application controller. At this stage the user control should traverse the grid structure and get all expanded rows. From this information the back end can get all the information needed to get the data for the view(s) (user control(s)).
3. At user control's Page_PreRender the user control receives the data it is supposed to bind to the grid. The hierarchical data structure could be of type:
Where the Type1 objects are objects that should be bound to the MasterTableView level and the IEnumerable of trees should be bound to the detail tables.
The Tree and its TreeNode classes look like this:
Now back to the problem at hand. I tried to bind the MasterTableView to the IEnumerable<Type1>:
RadGridExample.MasterTableView.DataSource = hierarchy.Select(tuple => tuple.Item1); Where hierarchy is the IEnumerable<Tuple<Type1,IEnumerable<Tree<Type2>>>>.
Then in the RadGridExample_DetailTableDataBind handler I Tried the following:
The rules for binding are following (as the code above suggests):
- If the IEnumerable<Type2> associated with the Type1 in the Tuple is null, then the row is not expanded and its detail table should not be bound to anything.
- If the TreeNode<Type2> object has IsLeaf == true then it is not expanded and its detail table should not be bound to anything.
Is it possible to bind this kind for data structures the grid hierarchy all at once at Page_PreRender? The self referencing hierarchy is out of the question since I want to some day have custom paging on all levels of the hierarchy separately. For now I would settle for getting the data binding working.
I attached an example picture of the kind of data that the grid should bind to.
EDIT:
Some more issues I ran into:
Issue1:
If I set the data source of the grid or grid's master table view as IEnumerable<Type1> the Grid_ItemDataBound handler tries to bind the Type1 objects also to the DetailTable levels. This is not at all what I intended to do. The IEnumerable<Type1> objects should be bound to the master table view level (outer most level) and the trees should be bound to the detail table levels.
For example If my data source for the master table view level would be following:
{item1, item2, item3, item4}
The grid tries to create the following hierarchy from this list:
item1
-Item1
-Item2
-Item3
-Item4
Item2
-Item1
-Item2
-Item3
-Item4
...
And so on
So it is repeating the main level objects as the children of the main level objects.
Issue2:
I got the hierarchy expanding but it is super slow. Now the problem is that if I want to collapse any row the grid won't event make a request to the server. Although this only happens when the web app is run on the Visual Studio development web server. On IIS the collapse seems to work.
(I have removed any business specific information from the markup and code samples)
I have a problem with binding to a hierarchical data structure. The structure for the grid is following:
<
telerik:RadGrid
ID
=
"RadGridExample"
runat
=
"server"
GridLines
=
"Both"
Skin
=
"WebBlue"
>
<
MasterTableView
AutoGenerateColumns
=
"false"
Name
=
"Main"
> <%-- This level holds items of Type1 --%>
<
Columns
>
</
Columns
>
<
DetailTables
>
<
telerik:GridTableView
Name
=
"SubLevel1"
ShowHeadersWhenNoRecords
=
"false"
AutoGenerateColumns
=
"false"
> <%-- This level holds items of Type2 --%>
<
Columns
>
</
Columns
>
<
DetailTables
>
<
telerik:GridTableView
Name
=
"SubLevel2"
ShowHeader
=
"false"
AutoGenerateColumns
=
"false"
> <%-- This level holds items of Type2 --%>
<
Columns
>
</
Columns
>
<
DetailTables
>
<
telerik:GridTableView
Name
=
"SubLevel3"
ShowHeader
=
"false"
AutoGenerateColumns
=
"false"
> <%-- This level holds items of Type2 --%>
<
Columns
>
</
Columns
>
<
DetailTables
>
<
telerik:GridTableView
Name
=
"SubLevel4"
ShowHeader
=
"false"
AutoGenerateColumns
=
"false"
> <%-- This level holds items of Type2 --%>
<
Columns
>
</
Columns
>
</
telerik:GridTableView
>
</
DetailTables
>
</
telerik:GridTableView
>
</
DetailTables
>
</
telerik:GridTableView
>
</
DetailTables
>
</
telerik:GridTableView
>
</
DetailTables
>
</
MasterTableView
>
</
telerik:RadGrid
>
For all levels I use custom sorting, custom paging and custom filtering. I get all data for the entire grid (all sub levels included) in the Page_PreRender stage (of the UserControl the Grid is in).
The problem is that I have not been able to get the detail grids to bind at all after I expand a row.
Here is a little bit of background information before I go on:
The life cycle of the control is following:
1. At Init (of the user control) the user control registeres it to the page. The user control implements a custom IView interface and the Page implements a custom IViewContiner interface. The code for this is following:
protected
void
Page_Init(
object
sender, EventArgs e)
{
IViewContainer container =
this
.Page
as
IViewContainer;
if
(container !=
null
)
{
container.Register(
this
);
}
}
2. In the the containing Page's Page_LoadComplete the Page calls all its IView (user control) objects Initialize method where the user control collects its state information and sends it to an application controller. At this stage the user control should traverse the grid structure and get all expanded rows. From this information the back end can get all the information needed to get the data for the view(s) (user control(s)).
3. At user control's Page_PreRender the user control receives the data it is supposed to bind to the grid. The hierarchical data structure could be of type:
IEnumerable<Tuple<Type1,IEnumerable<Tree<Type2>>>>
The Tree and its TreeNode classes look like this:
public
class
Tree<TItem>
{
public
Tree(TItem rootItem)
{
root =
new
TreeNode<TItem>(rootItem);
}
public
Tree(TreeNode<TItem> rootNode)
{
this
.root = rootNode;
}
private
TreeNode<TItem> root;
public
TreeNode<TItem> Root
{
get
{
return
root; }
}
}
public
class
TreeNode<TItem>
{
public
TreeNode(TItem item)
{
this
.item = item;
this
.children =
new
List<TreeNode<TItem>>();
this
.isLeaf =
true
;
}
public
TreeNode(TItem item,
bool
isLeaf)
{
this
.item = item;
this
.isLeaf = isLeaf;
this
.children =
new
List<TreeNode<TItem>>();
}
public
TreeNode(TItem node, IEnumerable<TItem> children)
{
this
.item = node;
this
.children =
new
List<TreeNode<TItem>>(children.Count());
foreach
(var child
in
children)
{
this
.children.Add(
new
TreeNode<TItem>(child));
}
this
.isLeaf =
false
;
}
private
TItem item;
public
TItem Item
{
get
{
return
item;}
}
private
List<TreeNode<TItem>> children;
public
IEnumerable<TreeNode<TItem>> Children
{
get
{
if
(isLeaf)
throw
new
InvalidOperationException(
"Node is set as Leaf so it can't have children"
);
return
children;
}
}
private
bool
isLeaf;
public
bool
IsLeaf
{
get
{
return
isLeaf; }
set
{ isLeaf = value; }
}
public
void
AddChild(TItem item)
{
isLeaf =
false
;
children.Add(
new
TreeNode<TItem>(item));
}
public
void
AddChild(TreeNode<TItem> item)
{
isLeaf =
false
;
children.Add(item);
}
public
void
AddChildren(IEnumerable<TItem> items)
{
isLeaf =
false
;
foreach
(var item
in
items)
{
children.Add(
new
TreeNode<TItem>(item));
}
}
public
void
AddChildren(IEnumerable<TreeNode<TItem>> items)
{
isLeaf =
false
;
foreach
(var item
in
items)
{
children.Add(item);
}
}
}
Now back to the problem at hand. I tried to bind the MasterTableView to the IEnumerable<Type1>:
RadGridExample.MasterTableView.DataSource = hierarchy.Select(tuple => tuple.Item1); Where hierarchy is the IEnumerable<Tuple<Type1,IEnumerable<Tree<Type2>>>>.
Then in the RadGridExample_DetailTableDataBind handler I Tried the following:
object
parentDataItem = e.DetailTableView.ParentItem.DataItem;
if
(parentDataItem
is
Type1)
{
Type1 fac = parentDataItem
as
Type1;
var tuple = hierarchy.Single(t => t.Item1 == fac);
if
(tuple.Item2 !=
null
)
{
var roots = tuple.Item2.Select(tree => tree.Root);
//selects IEnumerable<TreeNode<Type2>>
e.DetailTableView.DataSource = roots;
}
}
else
if
(parentDataItem
is
TreeNode<Type2>)
{
TreeNode<Type2> node = parentDataItem
as
TreeNode<Type2>;
if
(!node.IsLeaf)
{
e.DetailTableView.DataSource = node.Children;
}
}
The rules for binding are following (as the code above suggests):
- If the IEnumerable<Type2> associated with the Type1 in the Tuple is null, then the row is not expanded and its detail table should not be bound to anything.
- If the TreeNode<Type2> object has IsLeaf == true then it is not expanded and its detail table should not be bound to anything.
Is it possible to bind this kind for data structures the grid hierarchy all at once at Page_PreRender? The self referencing hierarchy is out of the question since I want to some day have custom paging on all levels of the hierarchy separately. For now I would settle for getting the data binding working.
I attached an example picture of the kind of data that the grid should bind to.
EDIT:
Some more issues I ran into:
Issue1:
If I set the data source of the grid or grid's master table view as IEnumerable<Type1> the Grid_ItemDataBound handler tries to bind the Type1 objects also to the DetailTable levels. This is not at all what I intended to do. The IEnumerable<Type1> objects should be bound to the master table view level (outer most level) and the trees should be bound to the detail table levels.
For example If my data source for the master table view level would be following:
{item1, item2, item3, item4}
The grid tries to create the following hierarchy from this list:
item1
-Item1
-Item2
-Item3
-Item4
Item2
-Item1
-Item2
-Item3
-Item4
...
And so on
So it is repeating the main level objects as the children of the main level objects.
Issue2:
I got the hierarchy expanding but it is super slow. Now the problem is that if I want to collapse any row the grid won't event make a request to the server. Although this only happens when the web app is run on the Visual Studio development web server. On IIS the collapse seems to work.