views:

29

answers:

2

Hi, I am trying to make a custom server control which inherits from DropDownList. I give the control an XML input containing some key/value pairs and my control shows them as a DropDownList. I make the list items in the override Render method like this:

foreach (XElement child in root.Elements("Choice"))
{
    string title = child.Element("Title").Value;
    string score = child.Element("Score").Value;
    item = new ListItem();
    item.Text = title;
    item.Value = score;

    this.Items.Add(item);
}

The problem is that, when the user selects and item in the list, and the page posts back, the selected item is lost, and the list is re-initialized with the default data.

Does anyone have any idea how to keep the selected item, i.e. maintain the state?

Here is the complete source:

public class MultipleChoiceQuestionView2 : DropDownList

{ public MultipleChoiceQuestionView2() : base() { }

protected override void Render(HtmlTextWriter writer) { writer.RenderBeginTag(HtmlTextWriterTag.Table); writer.RenderBeginTag(HtmlTextWriterTag.Tr);

writer.RenderBeginTag(HtmlTextWriterTag.Td); #region Parse Contets if (!String.IsNullOrEmpty(this.Contents)) { XElement root = XElement.Parse(this.Contents);

if (root.HasAttributes) { this.NoOfChoices = Int32.Parse(root.Attribute("ItemCount").Value); }

this.Items.Clear(); this.Style.Add("width", "100px"); this.Style.Add("font-family", "Tahoma"); this.Items.Clear(); ListItem item = new ListItem(); item.Text = ""; item.Value = "0"; this.Items.Add(item);

foreach (XElement child in root.Elements("Choice")) { string title = child.Element("Title").Value; string score = child.Element("Score").Value; item = new ListItem(); item.Text = title; item.Value = score;

this.Items.Add(item);

} } #endregion base.Render(writer); writer.RenderEndTag();

if (this.Required) { RequiredFieldValidator rfv = new RequiredFieldValidator(); rfv.ControlToValidate = this.ID; rfv.InitialValue = "0"; rfv.Text = "*"; if (!String.IsNullOrEmpty(this.ValidationGroup)) { rfv.ValidationGroup = this.ValidationGroup; } writer.RenderBeginTag(HtmlTextWriterTag.Td); rfv.RenderControl(writer); writer.RenderEndTag(); }

writer.RenderEndTag(); writer.RenderEndTag(); } #region Properties public string Contents { get { return ViewState["Contents"] == null ? "" : ViewState["Contents"].ToString(); } set { ViewState["Contents"] = value; } }

private int mNoOfChoices; public int NoOfChoices { get { return mNoOfChoices; } set { mNoOfChoices = value; } }

private string mValidationGroup; public string ValidationGroup { get { return mValidationGroup; } set { mValidationGroup = value; } }

public string SelectedChoice { get { return ""; } }

private bool mRequired = false; public bool Required { get { return mRequired; } set { mRequired = value; } }

#endregion }

Thanks in advance.

+1  A: 

You've got two options: ViewState or ControlState.

The difference being ViewState can be overriden by setting EnableViewState="false" in the page directive, whilst ControlState cannot.

Essentially you need to hook into the state bag when you're getting/setting the values of the dropdown.

There's a decent example here where a custom control is derived from the Button class and maintains state between page requests - should fit your scenario nicely.

Hopefully that gets you started.

RPM1984
A: 

Hi, Thanks for your help, I tried the link you specified (ControlState), but I still can't maintain the selected value. Here is what I have:

public class MultipleChoiceQuestionView2 : DropDownList
{
    public MultipleChoiceQuestionView2()
        : base()
    {
    }
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        Page.RegisterRequiresControlState(this);
    }
    protected override object SaveControlState()
    {
        Object obj = base.SaveControlState();
        if (obj != null)
        {
            return new Pair(obj, this.SelectedValue);
        }
        else
        {
            return (this.SelectedValue);
        }
    }
    protected override void LoadControlState(object savedState)
    {
        if (savedState != null)
        {
            Pair p = savedState as Pair;
            if (p != null)
            {
                base.LoadControlState(p.First);
                try
                {
                    this.SelectedValue = (string)p.Second;
                }
                catch (Exception)
                {
                }
            }
            else
            {
                if (savedState is string)
                {
                    this.SelectedValue = (string)savedState;
                }
                else
                {
                    base.LoadControlState(savedState);
                }
            }
        }
    }

    protected override void Render(HtmlTextWriter writer)
    {
        writer.RenderBeginTag(HtmlTextWriterTag.Table);
        writer.RenderBeginTag(HtmlTextWriterTag.Tr);

        writer.RenderBeginTag(HtmlTextWriterTag.Td);
        #region Parse Contets
        if (!String.IsNullOrEmpty(this.Contents))
        {
            XElement root = XElement.Parse(this.Contents);

            if (root.HasAttributes)
            {
                this.NoOfChoices = Int32.Parse(root.Attribute("ItemCount").Value);
            }

            this.Items.Clear();
            this.Style.Add("width", "100px");
            this.Style.Add("font-family", "Tahoma");
            this.Items.Clear();
            ListItem item = new ListItem();
            item.Text = "";
            item.Value = "0";
            this.Items.Add(item);

            foreach (XElement child in root.Elements("Choice"))
            {
                string title = child.Element("Title").Value;
                string score = child.Element("Score").Value;
                item = new ListItem();
                item.Text = title;
                item.Value = score;

                this.Items.Add(item);
            }
        }
        #endregion
        base.Render(writer);
        writer.RenderEndTag();

        if (this.Required)
        {
            RequiredFieldValidator rfv = new RequiredFieldValidator();
            rfv.ControlToValidate = this.ID;
            rfv.InitialValue = "0";
            rfv.Text = "*";
            if (!String.IsNullOrEmpty(this.ValidationGroup))
            {
                rfv.ValidationGroup = this.ValidationGroup;
            }
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            rfv.RenderControl(writer);
            writer.RenderEndTag();
        }

        writer.RenderEndTag();
        writer.RenderEndTag();
    }
    #region Properties
    public string Contents
    {
        get
        {
            return ViewState["Contents"] == null ? "" : ViewState["Contents"].ToString();
        }
        set
        {
            ViewState["Contents"] = value;
        }
    }

    private int mNoOfChoices;
    public int NoOfChoices
    {
        get { return mNoOfChoices; }
        set { mNoOfChoices = value; }
    }

    private string mValidationGroup;
    public string ValidationGroup
    {
        get { return mValidationGroup; }
        set { mValidationGroup = value; }
    }

    public string SelectedChoice
    {
        get
        {
            return "";
        }
    }

    private bool mRequired = false;
    public bool Required
    {
        get { return mRequired; }
        set { mRequired = value; }
    }

    #endregion
}

Do you have any idea what is going wrong?

Ako
Hmm, you're code looks ok. When you breakpoint into the Render method (on postback), is there anything in the ViewState (ie "Contents" property)?
RPM1984