Removing and Recreating Dynamically Created Controls inside an Event

LexiksTalionis
LexiksTalionis used Ask the Experts™
on
Hi,

I'm trying to build a simple custom paginator. But I came across a specific problem, which I guess should be a common problem while creating a user control.

I'm dynamically creating controls inside the user control. When the user fires an event, I'm clearing the whole controls and dynamically creating them again. OK, at this point the control that I'm trying to create is important. The control as I said is a paginator control. There are LinkButtons which links to certain pages like "1, 2, 3, Next, Previous" and so.

As long as the controls are dynamically created, I should recreate them in Page_Load after each postback exactly the same to be able to catch events. I mean their IDs, CommandNames should all be exactly the same with before PostBack.

After that, I catch the event. Say the user clicked LinkButton with text "4" to navigate to fourth page. Inside the event I clear all the LinkButtons created before and recreate them. I recreate them because, the CurrentPage has changed to page "4". And the LinkButton at the center should be "4".

Ok, the problem happens here, altough I have deleted all previously created LinkButtons, If I create a new LinkButton with the same ID (BTW I'm giving them ID's by the page numbers they should redirect to), I get an error as "Sys.WebForms.PageRequestManagerServerErrorException: Multiple controls with the same ID"

This should be directly related to inner ASP.NET mechanism. I guess as long as I'm doing this inside an event there should be some problem with Page LifeCycle or so. May be I should do more than clearing them.

protected void Page_Load(object sender, EventArgs e)
        {
            panelPaginator.CssClass = CssClass;
            panelPaginator.Attributes.Add("style", style);

            string alignStr = "left";
            switch (Align)
            {
                case HorizontalAlign.Center: alignStr = "center"; break;
                case HorizontalAlign.Left: alignStr = "left"; break;
                case HorizontalAlign.Right: alignStr = "right"; break;
                case HorizontalAlign.Justify: alignStr = "center"; break;
                case HorizontalAlign.NotSet: alignStr = "left"; break; 
            }

            tdPaginator.Attributes.Add("style", "text-align:" + alignStr);
        }

        protected void lbNavigator_Click(object sender, EventArgs e)
        {
            int pageToGo = PageNumber;
            try { pageToGo = Int32.Parse((sender as LinkButton).CommandName); }
            catch (Exception ex)
            {
                string command = (sender as LinkButton).CommandName;
                if (command.Equals("Previous"))
                {
                    if (PageNumber - 1 == 0)
                    {
                        pageToGo = 1;
                    }
                    else
                    {
                        pageToGo = PageNumber - 1;
                    }
                }
                else if (command.Equals("Next"))
                {
                    double tempDouble = TotalItems / ItemPerPage;
                    int totalNumberPages = Int32.Parse(Math.Ceiling(tempDouble).ToString());

                    if (PageNumber + 1 == totalNumberPages)
                    {
                        pageToGo = PageNumber;
                    }
                    else
                    {
                        pageToGo = PageNumber + 1;
                    }
                }
            }

            PageNumber = pageToGo;

            Navigate(this, new NavigateEventArgs(PageNumber, ItemPerPage, TotalItems));

            PopulateNavigationButtons();
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            PopulateNavigationButtons();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);

            EnsureChildControls();
        }

        protected void PopulateNavigationButtons()
        {
            panelPaginatorInner.Controls.Clear();

            double tempDouble = TotalItems / ItemPerPage;
            int totalNumberPages = Int32.Parse(Math.Ceiling(tempDouble).ToString());
            LinkedList<LinkButton> navigators = new LinkedList<LinkButton>();

            int maxLength = totalNumberPages < 9 ? totalNumberPages : 9;
            int lowNum = PageNumber;
            int highNum = PageNumber;

            navigators.AddFirst(GetLinkButton(PageNumber.ToString(), PageNumber.ToString(), "PaginatorNavigatorLink ActivePaginatorNavigatorLink"));

            while (navigators.Count < maxLength && totalNumberPages > 1)
            {
			    lowNum = lowNum - 1;
			    highNum = highNum + 1;
			    if(lowNum > 0){
                    navigators.AddFirst(GetLinkButton(lowNum.ToString(), lowNum.ToString(), "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
			    }
                if(highNum <= totalNumberPages){
                    navigators.AddLast(GetLinkButton(highNum.ToString(), highNum.ToString(), "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
			    }
		    }

            if((lowNum - 1) > 3)
            {
                navigators.AddFirst(GetLinkButton("", "...", "PaginatorDot"));
                navigators.AddFirst(GetLinkButton(2.ToString(), 2.ToString(), "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
                navigators.AddFirst(GetLinkButton(1.ToString(), 1.ToString(), "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
            }

            if ((totalNumberPages - highNum) > 3)
            {
                navigators.AddLast(GetLinkButton("", "...", "PaginatorDot"));
                navigators.AddLast(GetLinkButton((totalNumberPages - 1).ToString(), (totalNumberPages - 1).ToString(), "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
                navigators.AddLast(GetLinkButton(totalNumberPages.ToString(), totalNumberPages.ToString(), "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
            }

            navigators.AddFirst(GetLinkButton("Previous", "<< Önceki", "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
            navigators.AddLast(GetLinkButton("Next", "Sonraki >>", "PaginatorNavigatorLink InActivePaginatorNavigatorLink"));
            
            foreach (LinkButton l in navigators)
            {
                panelPaginatorInner.Controls.Add(l);
            }
        }

        private LinkButton GetLinkButton(string commandName, string text, string cssClass)
        {
            LinkButton lbNavigator = new LinkButton();
            lbNavigator.CommandName = commandName.ToString();
            lbNavigator.ID = "NavigatorLink" + commandName;
            lbNavigator.Text = text.ToString();
            if (commandName.Equals("Previous")) { lbNavigator.Attributes.Add("style", "margin:0px 1px 0px 0px;"); }
            if (commandName.Equals("Next")) { lbNavigator.Attributes.Add("style", "margin:0px 0px 0px 1px;"); }
            lbNavigator.Click += new EventHandler(lbNavigator_Click);
            lbNavigator.Attributes.Add("class", cssClass);
            return lbNavigator;
        }

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Kamal KhaleefaInformation Security Specialist

Commented:
Hi
are you using Ajax Update panel
if yes try to remove it and test it again and check if this error happen

Author

Commented:
The exception is not generated by AJAX mechanism. It is just caught by it. So removing Update Panel doesn't seem to work.
Scrum Trainer | Microsoft MVP | ALM Ranger | Consultant
Commented:
I usually do the second pass of control creation in the OnPreRender event. To date I haven't had any issues with that approach. You're safe there asno new events will be triggered. Also make sure you have unsubscribed from any events that are attached to these controls, they keep the controls alive.

Also, when adding controls dynamically you must create them, assign their id, add them to their container, then set other values, attach events. Right now you're adding them to the container late, which can cause all kinds of issues later on.

Also, instead of using int.Parse in a try catch, consider using int.TryParse, it's much faster as it doesn't generate an exception.
int pageNr = -1,
if (int.TryParse(commandName, out pageNr)

Even better would be to just use CommandName = "navigate", and then put the page number in CommandArgument;
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.linkbutton.commandargument.aspx

Author

Commented:
It was not completely enough; but it helped me finding a way to fix the problem.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial