RadListBox behaving strangely embedded in server control

3 posts, 0 answers
  1. Lasse Schioettz
    Lasse Schioettz avatar
    2 posts
    Member since:
    Dec 2009

    Posted 17 Dec 2009 Link to this post

    Hi,

    I like the functionality provided by a pair of listboxes set up as a source and target. What I don't like is to have to declare them separately, databind and ultimately looping through the items in the target listbox to get a list of selected values. I have therefore tried to wrap all of this in a server control. The constructor takes a name, an IEnumerable list as datasource and the names of the text and value properties. It also provides a "GetSelectedItems()" method that returns the selected values as a CSV string (which is what I need). When I instantiate this server control it looks and appears to function as expected.

    Now to the problem: when the page posts back the target listbox is empty. The items added clientside disappears. Clearly, this is not supposed to happen, so I must have done something wrong. I enclose the code for my server control below. Any pointers will be greatly appreciated.

    Sincerely,
    Lasse

    namespace Company.PDC.WebParts  
    {  
        using System;  
        using System.Collections;  
        using System.ComponentModel;  
        using System.Web.UI;  
        using System.Web.UI.WebControls;  
        using Telerik.Web.UI;  
     
        [ToolboxData("<{0}:SearchListBox runat=server></{0}:SearchListBox>")]  
        public class SearchListBox : WebControl  
        {
            #region Attributes  
     
            private Table listBoxTable;  
            private RadListBox source;  
            private RadListBox target;  
            private string separator = ";";  
            private string anyElement = "- Any -";  
            private int height = 200;  
            private int width = 200;
            #endregion  
     
            #region Constructors  
     
            public SearchListBox(string controlName, IEnumerable dataSource, string textField, string valueField)  
            {  
                this.ID = controlName;  
                this.source = new RadListBox();  
                this.target = new RadListBox();  
                this.EnableViewState = true;  
                this.source.EnableViewState = true;  
                this.target.EnableViewState = true;  
                this.LoadData(dataSource, textField, valueField);  
            }
            #endregion  
     
            #region Properties  
     
            public string Separator  
            {  
                get 
                {  
                    return this.separator;  
                }  
     
                set 
                {  
                    this.separator = value;  
                }  
            }  
     
            public string AnyElement  
            {  
                get 
                {  
                    return this.anyElement;  
                }  
     
                set 
                {  
                    this.anyElement = value;  
                }  
            }  
     
            public new int Height  
            {  
                get 
                {  
                    return this.height;  
                }  
     
                set 
                {  
                    this.height = value;  
                }  
            }  
     
            public new int Width  
            {  
                get 
                {  
                    return this.width;  
                }  
     
                set 
                {  
                    this.width = value;  
                }  
            }  
     
            public bool IsEmpty  
            {  
                get 
                {  
                    return this.target.Items.Count.Equals(0);  
                }  
            }
            #endregion  
     
            #region Public Methods  
     
            /// <summary>  
            /// Retrieves a list of selected items.  
            /// </summary>  
            /// <returns>  
            /// A separator delimited string of selected values.  
            /// </returns>  
            public string GetSelectedValues()  
            {  
                string values = string.Empty;  
                foreach (RadListBoxItem item in this.target.Items)  
                {  
                    values += item.Value + this.Separator;  
                }  
     
                return values;  
            }
            #endregion  
     
            #region Override Methods  
     
            protected override void CreateChildControls()  
            {  
                base.CreateChildControls();  
     
                this.DefineListBoxes();  
                this.Controls.Add(this.listBoxTable);  
            }  
     
            protected override void RenderContents(HtmlTextWriter output)  
            {  
                this.source.RenderControl(output);  
                this.target.RenderControl(output);  
            }
            #endregion  
     
            #region Private Support Methods  
     
            private void LoadData(IEnumerable dataSource, string textField, string valueField)  
            {  
                this.source.DataSource = dataSource;  
                this.source.DataTextField = textField;  
                this.source.DataValueField = valueField;  
                this.source.DataBind();  
            }  
     
            private void DefineListBoxes()  
            {  
                this.source.Height = this.Height;  
                this.source.Width = this.Width;  
                this.target.Height = this.Height;  
                this.target.Width = this.Width - 35;  
                this.target.ID = this.ID + "target";  
                this.source.ID = this.ID + "source";  
                this.source.AllowTransfer = true;  
                this.source.AllowTransferDuplicates = false;  
                this.source.TransferMode = ListBoxTransferMode.Copy;  
                this.source.TransferToID = this.target.ID;  
     
                this.listBoxTable = new Table();  
                TableRow row = new TableRow();  
                TableCell cellSource = new TableCell();  
                TableCell cellTarget = new TableCell();  
                cellSource.Controls.Add(this.source);  
                cellTarget.Controls.Add(this.target);  
                row.Cells.Add(cellSource);  
                row.Cells.Add(cellTarget);  
                this.listBoxTable.Rows.Add(row);  
            }
            #endregion  
        }  
    }  
     
  2. Simon
    Admin
    Simon avatar
    2281 posts

    Posted 19 Dec 2009 Link to this post

    Hello Lasse Schioettz,

    Thank you for providing your code.

    The target ListBox looses its state because it is added to the Page Control Tree in the CreateChildControls method, which in your case fires in the PreRender phase. So both ListBoxes miss to load their PostData and they do not reflect they client-side changes.

    In order to resolve this I suggest you create the ListBoxes in the OnInit override of the parent control:

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
     
        this.DefineListBoxes(); 
        this.Controls.Add(this.listBoxTable);
    }

    Greetings,
    Simon
    the Telerik team

    Instantly find answers to your questions on the new Telerik Support Portal.
    Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
  3. Lasse Schioettz
    Lasse Schioettz avatar
    2 posts
    Member since:
    Dec 2009

    Posted 21 Dec 2009 Link to this post

    Hi Simon,

    Thanks for your suggestion. I just tried it out and alas, it makes no difference - still no values in the target listbox after or during postback.

    UPDATE:
    If I move the instantiation of the server control on the consuming page to the override of CreateChildControls it works fine. So OnInit in teh server control and CreateChildControls in the consuming page is the combo that works. Thanks again for your directions.

    Sincerely,
    Lasse
Back to Top