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

Having trouble with ViewState and programatically added / removed columns

7 Answers 157 Views
TreeList
This is a migrated thread and some comments may be shown as answers.
Lars-Erik
Top achievements
Rank 1
Lars-Erik asked on 17 Nov 2010, 04:05 PM
Hi!

I've been fiddling a bit with the new TreeList control, and manage to add some template columns dynamically.
It seems it's ok to remove a few and add more, but when I remove a lot and add less, I get an exception saying


Invalid column type: "TreeListTemplateColumn".

[Exception: Invalid column type: "TreeListTemplateColumn".]
   Telerik.Web.UI.RadTreeList.CreateColumnByType(String columnType) +184
   Telerik.Web.UI.TreeListColumnsCollection.System.Web.UI.IStateManager.LoadViewState(Object state) +350
   Telerik.Web.UI.RadTreeList.LoadViewState(Object savedState) +97
   System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +183
   System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +134
   System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +221
   System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState) +134
   System.Web.UI.Control.LoadViewStateRecursive(Object savedState) +221
   System.Web.UI.Page.LoadAllState() +312
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1661

This also happens when "a lot" of columns has been added and I try to collapse a section.

I guess it's pretty easy to reproduce if you just fiddle a bit with the following page / code.
Try for instance to expand "A", then click "Month", and try to collapse "A".
Or just click "Month" then "Quarter".

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TreeViewTimeline.aspx.cs"
    Inherits="Web20.TreeViewTimelineTelerik.TreeViewTimeline" EnableEventValidation="false" %>
  
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
        <asp:LinkButton ID="QtrButton" runat="server" Text="Quarter" OnClick="QtrButtonClicked" />
        <asp:LinkButton ID="MonthButton" runat="server" Text="Month" OnClick="MonthButtonClicked" />
      
        <div id="tbl-container">
            <telerik:RadTreeList runat="server" ID="treeList" Skin="Vista" AutoGenerateColumns="False"
                OnInit="treeListInit"
                DataKeyNames="ID" ParentDataKeyNames="Parent" OnItemCommand="treeListItemCommand"
                  
                >
                <Columns>
                    <telerik:TreeListTemplateColumn UniqueName="Name" HeaderText="Navn" >
                        <HeaderStyle />
                        <ItemStyle />
                        <ItemTemplate>
                            <asp:TextBox runat="server" ID="NameTextBox" Text='<%# Eval("Name") %>' />
                        </ItemTemplate>
                    </telerik:TreeListTemplateColumn>
                </Columns>
            </telerik:RadTreeList>
        </div>
    </div>
    </form>
</body>
</html>

using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Web.UI;
  
namespace Web20.TreeViewTimelineTelerik
{
    public partial class TreeViewTimeline : System.Web.UI.Page
    {
        public string Mode
        {
            get { return ViewState["mode"] as string ?? "Quarter"; }
            set { ViewState["mode"] = value; }
        }
  
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                BindList();
            }
        }
  
        private void BindList() 
        {
            var list = new[]
                       {
                        new Item {ID = "A", Name = "A", Parent = "", Periods = new Dictionary<string, Period>
                              {{"Q1", new Period {Name = "Q1"}}, {"Feb", new Period {Name="1/10"}}}}
                        , new Item {ID = "B", Name = "B", Parent = ""}
                        , new Item {ID = "A.A", Name = "A.A", Parent = "A", Periods = new Dictionary<string, Period> 
                              {{"Q2", new Period { Name = "Qtr 2"}}, {"Q3", new Period {Name="Qty 3"}}, {"Mar", new Period{Name="2/10"}} }}
                       };
  
            treeList.DataSource = list;
            treeList.DataBind();
        }
  
        protected void treeListItemCommand(object sender, TreeListCommandEventArgs e)
        {
            if (e.CommandName == RadTreeList.ExpandCollapseCommandName)
            {
                ResetColumns();
            }
        }
  
        protected void treeListInit(object sender, EventArgs e)
        {
            InitColumns();
        }
  
        private void InitColumns()
        {
            switch(Mode)
            {
                case "Quarter":
                    string[] quarters = new[] {"Q1", "Q2", "Q3", "Q4"};
                    foreach(string quarter in quarters)
                        treeList.Columns.Add(new TreeListTemplateColumn{UniqueName = quarter, HeaderText = quarter, ItemTemplate = new PeriodTemplate(quarter)});
                    break;
                case "Month":
                    string[] months = new[] {"Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"};
                    foreach(string month in months)
                        treeList.Columns.Add(new TreeListTemplateColumn { UniqueName = month, HeaderText = month, ItemTemplate = new PeriodTemplate(month) });
                    break;
            }
        }
  
        private void ResetColumns() {
            RemoveDynamicColumns();
            InitColumns();
            BindList();
        }
  
        private void RemoveDynamicColumns()
        {
            for(int i = treeList.Columns.Count - 1; i>=1; i--)
                treeList.Columns.RemoveAt(i);
        }
  
        protected void QtrButtonClicked(object sender, EventArgs e)
        {
            Mode = "Quarter";
            ResetColumns();
        }
  
        protected void MonthButtonClicked(object sender, EventArgs e)
        {
            Mode = "Month";
            ResetColumns();
        }
    }
  
    public class PeriodTemplate : ITemplate
    {
        private readonly string quarter;
  
        public PeriodTemplate(string quarter)
        {
            this.quarter = quarter;
        }
  
        public void InstantiateIn(Control container)
        {
            Label label = new Label();
            label.EnableViewState = false;
            label.ID = quarter + "Label";
            Item dataItem = (Item)DataBinder.GetDataItem(container.BindingContainer);
            if (dataItem != null && dataItem.Periods != null)
            {
                if (dataItem.Periods.ContainsKey(quarter))
                    label.Text = dataItem.Periods[quarter].Name;
            }
            container.Controls.Add(label);
        }
    }
  
    public class Item
    {
        public string ID { get; set; }
        public string Parent { get; set; }
        public string Name { get; set; }
  
        public Dictionary<string, Period> Periods { get; set; }
    }
  
    public class Period
    {
        public string Name { get; set; }
    }
}

Hope you guys can help. :)

Lars-Erik

7 Answers, 1 is accepted

Sort by
0
Veli
Telerik team
answered on 23 Nov 2010, 09:39 AM
Hello Lars-Erik,

You need to create RadTreeList entirely in the Page_Init event and add it to a container on every postback. This is the only supported approach of initialization if you need to dynamically change the treelist columns structure.

Regards,
Veli
the Telerik team
Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Veli
Telerik team
answered on 23 Nov 2010, 11:33 AM
Just to clarify, any modifications to the RadTreeList structure need to happen in Page_Init. This means you cannot use a postback event to modify the columns collection. You need to change the columns when the control is recreated.

Veli
the Telerik team
Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Lars-Erik
Top achievements
Rank 1
answered on 02 Dec 2010, 03:04 PM
Hi again, thanks for the input!

It still has trouble. When adding columns in Page_Init (OnInit) it still throws "Invalid column type "TreeListTemplateColumn" (my class) from LoadViewState on PostBack. Even when not modifying the columns.
I'm starting to believe this i a problem with code templates, and not when they're added?

Here's the modified code, I've removed the grid entirely from the aspx.

public partial class TreeViewTimeline : System.Web.UI.Page
{
    private RadTreeList treeList;
    public string Mode
    {
        get { return ViewState["mode"] as string ?? "Quarter"; }
        set { ViewState["mode"] = value; }
    }
    protected override void OnInit(EventArgs e)
    {
        treeList = new RadTreeList();
        treeList.ID = "treeList";
        treeList.ItemCommand += TreeListItemCommand;
        treeList.Skin = "Vista";
        treeList.AutoGenerateColumns = false;
        treeList.DataKeyNames = new[] {"ID"};
        treeList.ParentDataKeyNames = new[] {"Parent"};
        gridContainer.Controls.Add(treeList);
        InitColumns();
        base.OnInit(e);
    }
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            BindList();
        }
    }
    private void BindList() 
    {
        var list = new[]
                   {
                    new Item {ID = "A", Name = "A", Parent = "", Periods = new Dictionary<string, Period>
                          {{"Q1", new Period {Name = "Q1"}}, {"Feb", new Period {Name="1/10"}}}}
                    , new Item {ID = "B", Name = "B", Parent = ""}
                    , new Item {ID = "A.A", Name = "A.A", Parent = "A", Periods = new Dictionary<string, Period> 
                          {{"Q2", new Period { Name = "Qtr 2"}}, {"Q3", new Period {Name="Qty 3"}}, {"Mar", new Period{Name="2/10"}} }}
                   };
        treeList.DataSource = list;
        treeList.DataBind();
    }
    protected void TreeListItemCommand(object sender, TreeListCommandEventArgs e)
    {
        if (e.CommandName == RadTreeList.ExpandCollapseCommandName)
        {
            BindList();
        }
    }
    private void InitColumns()
    {
        treeList.Columns.Add(new TreeListTemplateColumn{UniqueName = "Name", HeaderText = "Name", ItemTemplate = new TextBoxTemplate("Name")});
        switch(Mode)
        {
            case "Quarter":
                string[] quarters = new[] {"Q1", "Q2", "Q3", "Q4"};
                foreach(string quarter in quarters)
                    treeList.Columns.Add(new TreeListTemplateColumn{UniqueName = quarter, HeaderText = quarter, ItemTemplate = new PeriodTemplate(quarter)});
                break;
            case "Month":
                string[] months = new[] {"Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"};
                foreach(string month in months)
                    treeList.Columns.Add(new TreeListTemplateColumn { UniqueName = month, HeaderText = month, ItemTemplate = new PeriodTemplate(month) });
                break;
        }
    }
}
public class PeriodTemplate : ITemplate
{
    private readonly string quarter;
    public PeriodTemplate(string quarter)
    {
        this.quarter = quarter;
    }
    public void InstantiateIn(Control container)
    {
        Label label = new Label();
        label.ID = quarter + "Label";
        Item dataItem = (Item)DataBinder.GetDataItem(container.BindingContainer);
        if (dataItem != null && dataItem.Periods != null)
        {
            if (dataItem.Periods.ContainsKey(quarter))
                label.Text = dataItem.Periods[quarter].Name;
        }
        container.Controls.Add(label);
    }
}
public class TextBoxTemplate : ITemplate
{
    private readonly string field;
    public TextBoxTemplate(string field)
    {
        this.field = field;
    }
    public void InstantiateIn(Control container)
    {
        TextBox textBox = new TextBox();
        textBox.EnableViewState = true;
        textBox.ID = field + "TextBox";
        Item dataItem = (Item)DataBinder.GetDataItem(container.BindingContainer);
        if (dataItem != null)
            textBox.Text = dataItem.Name;
        container.Controls.Add(textBox);
    }
}
public class Item
{
    public string ID { get; set; }
    public string Parent { get; set; }
    public string Name { get; set; }
    public Dictionary<string, Period> Periods { get; set; }
}
public class Period
{
    public string Name { get; set; }
}
0
Accepted
Veli
Telerik team
answered on 02 Dec 2010, 03:23 PM
Hi Lars-Erik,

Try disabling the ViewState of the RadTreeList container. You will need to rebind RadTreeList on every postback in this scenario. Attaching a test page using a similar approach. Note how I have used RadTreeList's NeedDataSource event to pass the data source and only call Rebind() where I need to bind it.

Veli
the Telerik team
Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Lars-Erik
Top achievements
Rank 1
answered on 02 Dec 2010, 03:41 PM
Thanks!
Looks good, except I can't get it to collapse after expanding?

L-E
0
Accepted
Veli
Telerik team
answered on 02 Dec 2010, 04:30 PM
Confirmed. I have reported this issue for investigation. It seems, for now, there is no way RadTreeList columns can be changed dynamically without breaking the control's functionality. What you can do is add all your columns you would ever need in RadTreeList and selectively show/hide the ones you need/do not need.
Veli
the Telerik team
Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
0
Lars-Erik
Top achievements
Rank 1
answered on 02 Dec 2010, 04:33 PM
OK, thanks.
Looking forward to a future release then. :)

Lars-Erik
Tags
TreeList
Asked by
Lars-Erik
Top achievements
Rank 1
Answers by
Veli
Telerik team
Lars-Erik
Top achievements
Rank 1
Share this question
or