This is a migrated thread and some comments may be shown as answers.

[Solved] Dynamic hierarchy details

2 Answers 223 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Enigma
Top achievements
Rank 1
Enigma asked on 05 Nov 2009, 11:38 PM
I'm trying to add/remove different sections from the NestedView details section based on some user selection made outside the grid.

The MasterTableView.NestedViewTemplate property does not seem to be stored in ViewState so I'm currently trying to set the MasterTableView.NestedViewTemplate in the PreRender with no success.

Does anyone have an idea how this might be possible?

PS. For efficiency my child data needs to only be databound when expanded.

2 Answers, 1 is accepted

Sort by
0
Princy
Top achievements
Rank 2
answered on 06 Nov 2009, 06:31 AM
Hi Enigma,

You can access the GridNestedViewItem and then hide the various sections in the NesterdViewTemplate as shown in the example below:
aspx:
<NestedViewTemplate>                     
    <asp:Panel ID="Panel1" runat="server"
    Section 1 
    </asp:Panel> 
    <asp:Panel ID="Panel2" runat="server"
    Section 2 
    </asp:Panel>    
</NestedViewTemplate> 

c#:
protected void RadGrid1_PreRender(object sender, EventArgs e)   
    {   
        foreach (GridDataItem dataItem in RadGrid1.Items)   
        {   
            GridNestedViewItem nestedItem = (GridNestedViewItem)dataItem.ChildItem; // to access the nestedviewitem   
           // if(condition based on selection)                              
                ((Panel)nestedItem.FindControl("Panel2")).Visible = false// to access a control in the mnested view    
           // else          
           //   ((Panel)nestedItem.FindControl("Panel2")).Visible = true;  
        }   
    }   

Thanks
Princy.
0
Enigma
Top achievements
Rank 1
answered on 11 Nov 2009, 01:08 AM

I can't simply show/hide sections defined at design time because the content of the NestedView needs to be far more dynamic than that. Think of it as the user adding any number of modules each with there own set of options.

The good news however is that I have solved my own problem. I was going to attach a sample app that shows what I have done but I can't attach zip files. I was then going to attach a screen shot of the app but this does not seem to be working for some reason.

Basicly the app consists of two RadLists the left one with a list of components that can the included in the NestedView. Items can the transefered to the right hand list (TransferMode=Copy) so the some components can be added multiple times. Once the use clicks the apply button these settings are applyed to the NesterView.

The aspx I use is as follows, Note the NestedView template:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" %> 
<%@ Register TagPrefix="lib" Namespace="DynamicNestedViewTestLibrary.Controls" Assembly="DynamicNestedViewTestLibrary" %> 
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
 
<html xmlns="http://www.w3.org/1999/xhtml">  
<head runat="server">  
    <title></title>  
    <telerik:RadStyleSheetManager id="RadStyleSheetManager1" runat="server" /> 
</head> 
<body> 
    <form id="form1" runat="server">  
    <telerik:RadScriptManager ID="RadScriptManager1" runat="server">  
        <Scripts> 
            <asp:ScriptReference Assembly="Telerik.Web.UI, Version=2009.2.826.35, Culture=neutral, PublicKeyToken=121fae78165ba3d4" Name="Telerik.Web.UI.Common.Core.js" /> 
            <asp:ScriptReference Assembly="Telerik.Web.UI, Version=2009.2.826.35, Culture=neutral, PublicKeyToken=121fae78165ba3d4" Name="Telerik.Web.UI.Common.jQuery.js" /> 
        </Scripts> 
    </telerik:RadScriptManager> 
    <telerik:RadAjaxManager ID="RadAjaxManager1" runat="server">  
    </telerik:RadAjaxManager> 
   
    <telerik:RadSkinManager ID="RadSkinManager1" Runat="server" Skin="Sunset">  
    </telerik:RadSkinManager> 
    <div> 
          
        <telerik:RadListBox ID="lstOption" TransferToID="lstShown" TransferMode="Copy" AllowTransfer="true" AllowTransferDuplicates="true" AllowTransferOnDoubleClick="true" Height="150" runat="server">  
            <Items> 
                <telerik:RadListBoxItem Value="Note_Add" Text="Note Add" /> 
                <telerik:RadListBoxItem Value="Note_Sub" Text="Note Sub" /> 
                <telerik:RadListBoxItem Value="Note_Move" Text="Note Move" /> 
                <telerik:RadListBoxItem Value="Pet_Cat" Text="Pet cat" /> 
                <telerik:RadListBoxItem Value="Pet_Dog" Text="Pet dog" /> 
                <telerik:RadListBoxItem Value="Pet_Bird" Text="Pet bird" /> 
            </Items> 
        </telerik:RadListBox> 
          
        <telerik:RadListBox ID="lstShown" AllowDelete="true" AllowReorder="true" Height="150" runat="server">  
        </telerik:RadListBox> 
          
        <asp:Button ID="btnApply" Text="Apply" OnClick="btnApply_Click" runat="server" /> 
        <asp:Button ID="btnClear" Text="Clear" OnClick="btnClear_Click" runat="server" /> 
          
        <br /> 
        <br /> 
        <asp:LinkButton ID="lnkExpandAll" Text="Expand All" OnClick="lnkExpandAll_Click" runat="server" /> 
        <asp:LinkButton ID="lnkCollapseAll" Text="Collapse All" OnClick="lnkCollapseAll_Click" runat="server" /> 
          
        <telerik:RadGrid ID="MyGrid" AllowPaging="true" OnPreRender="MyGrid_PreRender" OnNeedDataSource="MyGrid_NeedDataSource" runat="server">  
          
            <MasterTableView DataKeyNames="Id" HierarchyLoadMode="ServerOnDemand" AllowSorting="true" AutoGenerateColumns="false" > 
                  
                <GroupByExpressions> 
                 <telerik:GridGroupByExpression> 
                    <GroupByFields> 
                        <telerik:GridGroupByField FieldName="Gender" /> 
                    </GroupByFields> 
                    <SelectFields> 
                        <telerik:GridGroupByField FieldName="Gender" /> 
                    </SelectFields> 
                 </telerik:GridGroupByExpression> 
                </GroupByExpressions> 
                  
                <Columns> 
                    <telerik:GridBoundColumn UniqueName="Id" DataField="Id" HeaderText="Id" /> 
                    <telerik:GridBoundColumn UniqueName="Name" DataField="Name" HeaderText="Name" /> 
                    <telerik:GridBoundColumn UniqueName="Age" DataField="Age" HeaderText="Age" /> 
                    <telerik:GridBoundColumn UniqueName="Gender" DataField="Gender" HeaderText="Gender" /> 
                </Columns> 
                  
                <NestedViewTemplate> 
                    <lib:Details ID="ctlDetails" runat="server" /> 
                </NestedViewTemplate> 
 
            </MasterTableView> 
        </telerik:RadGrid> 
          
    </div> 
    </form> 
</body> 
</html> 

The Details control in the NesterView template has a settings property (csv of the items to show) and addes more custom controls to its self depending the settings:

public class Details : System.Web.UI.Control  
{  
 
    public string Settings  
    {  
        get { return (string)ViewState["Settings"]; }  
        set 
        {  
            if (Settings != value)  
            {  
                ViewState["Settings"] = value;  
                RenderMe();  
            }  
        }  
    }  
 
    public Details()  
    {  
    }  
 
    protected override void OnLoad(EventArgs e)  
    {  
        base.OnLoad(e);  
        EnsureChildControls();  
    }  
 
    protected override void CreateChildControls()  
    {  
        base.CreateChildControls();  
 
        RenderMe();  
    }  
 
    public void RenderMe()  
    {  
        this.Controls.Clear();  
        if (!string.IsNullOrEmpty(Settings))  
        {  
            int count = 0;  
            foreach (string itm in Settings.Split(","[0]))  
            {  
                count++;  
                if (!string.IsNullOrEmpty(itm))  
                {  
                    if (itm.StartsWith("Note_"))  
                    {      
                        DetailItem_Note note = new DetailItem_Note();  
                        note.ID = "note_" + count;  
                        note.ItemSettings = itm.Remove(0, 5);  
                        this.Controls.Add(note);  
                    }  
                    else if (itm.StartsWith("Pet_"))  
                    {  
                        DetailItem_Pet pet = new DetailItem_Pet();  
                        pet.ID = "pet_" + count;  
                        pet.ItemSettings = itm.Remove(0, 4);  
                        this.Controls.Add(pet);  
                    }  
                    this.Controls.Add(new LiteralControl("<br />"));  
                }  
            }  
        }  
    }  
 
The two types of detail sections I have in this example are pet and Note, they both inherit from a common base control. Here is the base control:
public class DetailItem_Base : System.Web.UI.Control  
{  
 
    public string ItemSettings  
    {  
        get 
        {  
            return (string)ViewState["ItemSettings"];  
        }  
        set 
        {  
            ViewState["ItemSettings"] = value;  
        }  
    }  
 
    protected override void OnLoad(EventArgs e)  
    {  
        base.OnLoad(e);  
        EnsureChildControls();  
    }  
 
}//class  
 
And the Note Control:
public class DetailItem_Note : DetailItem_Base  
{  
    private Label lbl;  
    private Button btn;  
    private TextBox txt;  
 
    protected override void CreateChildControls()  
    {  
        base.CreateChildControls();  
 
        lbl = new Label();  
                lbl.ID = "lbl_" + this.ID;  
                lbl.Text = "0";  
                this.Controls.Add(lbl);  
 
        btn = new Button();  
        btn.ID = "btn_" + this.ID;  
        btn.Click += btn_Click;  
 
        switch (this.ItemSettings)  
        {  
            case "Add":  
                btn.Text = "Add";  
                break;  
 
            case "Sub":  
                btn.Text = "Subtract";  
                break;  
 
            case "Move":  
                txt = new TextBox();  
                txt.ID = "txt_" + this.ID;  
                txt.Width = 75;  
                this.Controls.Add(txt);  
 
                btn.Text = "Move";  
                break;  
        }  
 
        this.Controls.Add(btn);  
 
    }  
 
    private void btn_Click(object sender, EventArgs e)  
    {  
        switch (this.ItemSettings)  
        {  
            case "Add":  
                lbl.Text = (int.Parse(lbl.Text) + 1).ToString();  
                break;  
 
            case "Sub":  
                lbl.Text = (int.Parse(lbl.Text) - 1).ToString();  
                break;  
 
            case "Move":  
                lbl.Text = txt.Text;  
                txt.Text = string.Empty;  
                break;  
        }  
    }  
 
And the Pet control:
public class DetailItem_Pet : DetailItem_Base  
{  
 
    protected override void CreateChildControls()  
    {  
        base.CreateChildControls();  
 
        if (ViewState["DataFromDB"] == null)  
        {  
            // Simulate getting data  
            System.Threading.Thread.Sleep(1000);  
 
            switch (this.ItemSettings)  
            {  
                case "Cat":  
                    ViewState["DataFromDB"] = "Cats eat native birds, bad cats.";  
                    break;  
 
                case "Dog":  
                    ViewState["DataFromDB"] = "Dogs can NOT climb trees.";  
                    break;  
 
                case "Bird":  
                    ViewState["DataFromDB"] = "Birds saw but not through wood!";  
                    break;  
            }  
        }  
 
        this.Controls.Add(new LiteralControl((string)ViewState["DataFromDB"]));  
    }  
So all this leaves is a way to hook the settings up. I do this in the grids PreRender event. This is the pages code behind:
public partial class Default : System.Web.UI.Page   
{  
    protected void Page_Load(object sender, EventArgs e)  
    {  
        if (!IsPostBack)  
        {  
            btnClear_Click(this, EventArgs.Empty);  
 
            MyGrid.DataSource = People.GetTestData();  
            MyGrid.DataBind();  
        }  
    }  
 
    protected void MyGrid_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)  
    {  
        MyGrid.DataSource = People.GetTestData();  
    }  
 
    protected void MyGrid_PreRender(object sender, EventArgs e)  
    {  
        foreach (GridDataItem item in MyGrid.MasterTableView.Items)  
        {  
            DynamicNestedViewTestLibrary.Controls.Details ctlDetails = (DynamicNestedViewTestLibrary.Controls.Details)item.ChildItem.FindControl("ctlDetails");  
 
            if (item.Expanded)  
            {  
                string strCurrentSettings = (string)(ViewState["CurrentSettings"] ?? string.Empty);  
                //if (string.IsNullOrEmpty(strCurrentSettings))  
                    //item.Expanded = false;                      
                //else  
                //{  
                ctlDetails.Settings = strCurrentSettings;  
                //}  
            }  
            else 
                ctlDetails.Settings = null;  
        }  
    }  
 
    protected void btnApply_Click(object sender, EventArgs e)  
    {  
        string strNewSettings = string.Empty;  
        foreach (RadListBoxItem itm in lstShown.Items)  
        {  
            strNewSettings += "," + itm.Value;  
        }  
 
        ViewState["CurrentSettings"] = strNewSettings;  
 
        MyGrid.MasterTableView.ExpandCollapseColumn.Display = true;  
    }  
 
    protected void btnClear_Click(object sender, EventArgs e)  
    {  
        lstShown.Items.Clear();  
        ViewState["CurrentSettings"] = string.Empty;  
        MyGrid.MasterTableView.ExpandCollapseColumn.Display = false;  
          
        // This could be replaced by un-expanding in MyGrid_PreRender() (see   
        //commented out code). However this better fits my full example.  
        MyGrid.Rebind();  
    }  
 
    protected void lnkExpandAll_Click(object sender, EventArgs e)  
    {  
        foreach (GridDataItem itm in MyGrid.MasterTableView.Items)  
            itm.Expanded = itm.Visible;  
    }  
 
    protected void lnkCollapseAll_Click(object sender, EventArgs e)  
    {  
        foreach (GridDataItem itm in MyGrid.MasterTableView.Items)  
            itm.Expanded = false;  
    }  
 
}//class 

The only other component I used was a People class to simulate the web service data I have in my full app:

public class People  
{  
 
    public int Id { getset; }  
    public string Name { getset; }  
    public int Age { getset; }  
    public string Gender { getset; }  
 
    /// <summary>  
    /// Get some test data for a grid  
    /// </summary>  
    /// <returns></returns>  
    public static People[] GetTestData()  
    {  
        People[] Out = new People[13];  
          
        Out[0] = new People() { Id = 0, Name = "Jill", Age = 34, Gender = "F" };  
        Out[1] = new People() { Id = 1, Name = "Bob", Age = 23, Gender = "M" };  
        Out[2] = new People() { Id = 2, Name = "Max", Age = 8, Gender = "M" };  
        Out[3] = new People() { Id = 3, Name = "Kate", Age = 63, Gender = "F" };  
        Out[4] = new People() { Id = 4, Name = "John", Age = 93, Gender = "M" };  
        Out[5] = new People() { Id = 5, Name = "Jo", Age = 46, Gender = "F" };  
        Out[6] = new People() { Id = 6, Name = "Aaron", Age = 2, Gender = "M" };  
        Out[7] = new People() { Id = 7, Name = "Jen", Age = 24, Gender = "F" };  
        Out[8] = new People() { Id = 8, Name = "Penny", Age = 76, Gender = "F" };  
        Out[9] = new People() { Id = 9, Name = "Charlie", Age = 45, Gender = "M" };  
        Out[10] = new People() { Id = 10, Name = "Simon", Age = 54, Gender = "M" };  
        Out[11] = new People() { Id = 11, Name = "Lex", Age = 13, Gender = "F" };  
        Out[12] = new People() { Id = 12, Name = "Anna", Age = 24, Gender = "F" };  
 
        return Out;  
    }  
}//class 
And that is all the core components to what I did, I hope it helps someone some day.
Tags
Grid
Asked by
Enigma
Top achievements
Rank 1
Answers by
Princy
Top achievements
Rank 2
Enigma
Top achievements
Rank 1
Share this question
or