views:

1029

answers:

2

I have an ASP.NET Page that contains a User control called ReportCtrl (my own control that has nothing to do with Reporting services etc.). ReportCtrl has a User control called TreeViewCtrl which contains a Telerik TreeView with some funky business logic to display nodes.

The TreeView is placed inside a ASP.NET AJAX panel. When a user clicks on a checkable node, it posts back to the server and saves a new Mapping object (marked Serializable) into a List which is stored in ViewState.

The issue I've been bumping against is that:-

  1. When the first checkbox is checked, the item is saved into the List which is then added to ViewState.
  2. When the second checkbox is checked, the item is saved into the List which is then added to ViewState.
  3. When the third checkbox is checked, the loaded ViewState only has 1 item in it.

I have overridden to check the number of items in ViewState and I can see that when the second item is checked, the SaveViewState is saving the ViewState with 3 items. When the LoadViewState is called on the third checkbox, I can see the decoded ViewState only has 1 item in it.

protected override void LoadViewState(object savedState)
protected override object SaveViewState()

Somehow, the Viewstate only works for 1 item and only for the FIRST item.

We have verified that this has nothing to do with the Telerik TreeView by removing it and just adding items manually on button click events. We have also eliminated the object by storing a list of strings.

We're fresh out of ideas on what to try. Has anyone run into this issue before? Any ideas that we can try?

Thanks.

CODE

Here is the code for the UpdatePanel:

<asp:UpdatePanel runat="server" ID="upnlTreeView" ChildrenAsTriggers="true" 
        RenderMode="Inline" UpdateMode="Conditional" EnableViewState="true">
<ContentTemplate>
    <telerik:RadAjaxManager runat="server" ID="RadAjaxManager1">
        <AjaxSettings>
            <telerik:AjaxSetting AjaxControlID="RadAjaxManager1">
                <UpdatedControls>
                    <telerik:AjaxUpdatedControl ControlID="ClickedNodeLabel" />
                </UpdatedControls>
            </telerik:AjaxSetting>
        </AjaxSettings>
    </telerik:RadAjaxManager>
        <telerik:RadTreeView ID="RadTreeView1" runat="server" Width="100%" Height="420px"
            PersistLoadOnDemandNodes="true" LoadingStatusPosition="BelowNodeText" CausesValidation="false"
            OnClientNodePopulated="nodePopulated" OnClientNodePopulating="nodePopulating" OnClientLoad="onLoad"
            CheckBoxes="true" CheckChildNodes="false" AllowNodeEditing="false" MultipleSelect="false" 
            LoadingMessage="Loading..." AppendDataBoundItems="true" Skin="Vista" EnableViewState="true" 
            onnodecheck="RadTreeView1_NodeCheck"  >

            <ExpandAnimation Type="none" />
            <CollapseAnimation Type="none" />
            <WebServiceSettings Path="/ESConsole/ws/PTService.asmx" Method="GetNodes" />

        </telerik:RadTreeView>

</ContentTemplate>

Here is the code for the List definition and other methods in the code behind:

    public List<ECodeMapping> ECodeMappings
    {
        get
        {
            return (ViewState["__lstECodeMapping"] == null) ? new List<ECodeMapping>()
                : ViewState["__lstECodeMapping"] as List<ECodeMapping>;
        }
        set { ViewState["__lstECodeMapping"] = value; }
    }
    protected override void LoadViewState(object savedState)
    {
        base.LoadViewState(savedState);
        int count1 = (ViewState["__lstECodeMapping"] as List<ECodeMapping>).Count;
    }

    protected override object SaveViewState()
    {
        int count1 = (ViewState["__lstECodeMapping"] as List<ECodeMapping>).Count;
        return base.SaveViewState();
    }
    protected void RadTreeView1_NodeCheck(object sender, RadTreeNodeEventArgs e)
    {
        RadTreeNode node = e.Node;
        int iLevel = node.Attributes["Level"].ToSafeInt();
        if (iLevel == 2)
        {
            var nList = ECodeMappings.FindAll(x => x.DocId == node.Value.ToSafeInt() && x.SecId < 1);
            if (nList.Count() == 0 && node.Checked == true)
            {
                // Add the node if it doesn't exist
                ECodeMapping newMapping = new ECodeMapping { ReportId = ReportId, DocId = node.Value.ToSafeInt(), SecId = int.MinValue };
                ECodeMappings.Insert(0, newMapping);
                return;
            }
A: 

Is the UpdatePanel actually sending the ViewState to the server and replacing the current ViewState on updates? Use Fiddler or similar tool to look at the actual HTTP traffic. I'm guessing that you are not getting back a ViewState for all your updates.

Bryan
Thanks for the feedback. It is in fact getting Viewstate information back.
AboutDev
A: 

Found the problem.

We had a script in the parent user control that looked as follows:-

BAD CODE

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(EndRequest);
var postBackElement;
function EndRequest(sender, args) {
    if (postBackElement.id == '<%= btnUpload.ClientID %>')
        var uprog1 = $get('<%= this.UpdateProgress1.ClientID %>');
        if(uprog1 != null)
        {
         uprog1.style.display = 'none';
        }
        $find('<%= mpeProgress.ClientID %>').hide();
}


This offending script had to be changed to the following:-

GOOD CODE

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(EndRequest);
var postBackElement = null;
function EndRequest(sender, args) {
    if (postBackElement != null && postBackElement.id == '<%= btnUpload.ClientID %>')
        var uprog1 = $get('<%= this.UpdateProgress1.ClientID %>');
        if(uprog1 != null)
        {
         uprog1.style.display = 'none';
        }
        $find('<%= mpeProgress.ClientID %>').hide();
}


Summary

The postBackElement needed to be checked for nulls.

AboutDev