Asp Composite控制子控件(radiobutton)失去检查值

时间:2010-10-04 10:05:00

标签: c# asp.net composite-controls

我正在使用动态创建的问题和选项在asp.net中进行测验控制。 主要控件基本上是容纳所有问题的容器。 在设计视图中,用户可以通过自定义集合编辑器添加问题。 每次我向集合编辑器列表添加一个问题时,它都会为我生成一个问号。 每个问题对象内部都有一个标签和一个继承Radiobutton控件的 n 量的Option对象。这些Option对象中的每一个又代表用户可以为每个问题选择的选项。

这一切都有效,除了我现在在我希望能够读取每个单选按钮的Checked值的部分。当我想在页面中实现此测验并检查问题时,我想在此页面中放置一个按钮并调用控件内的以下函数:

$

    public String checkQuestions()
    {


        if (questions != null)
        {

            foreach (Question question in questions)
            {

                options = question.readOptions();

                int i = 0;
                foreach (Option option in options)
                {
                    testLabel.Text = option.Checked.ToString(); // test purposes only
                }

            }



        }
       return errors;

    }

但是,一旦我选择了一个单选按钮并单击了提交按钮,对于所有选项,Checked值将始终为false。 基本上它在Postback之后失去了它的检查值,而我只是试图解决它。 如果有人能指出我正确的方向,我将不胜感激。

1 个答案:

答案 0 :(得分:4)

乍一看,有两件事我要检查。首先,确保您正在实施IPostBackDataHandler。这需要您实现两种方法LoadPostDataRaisePostDataChangedEvent。在我的第一次猜测中,第一个可能是你问题的根源。

手动处理回发

LoadPostData使用字符串postDataKeyNameValueCollection postCollection并返回bool,表示由于回发而值是否已更改。你没有需要以.Net最初打算的方式实现这一点,例如我创建了一个控件,其中包含几个单选按钮(由于这里不重要的原因,不能只是一个{ {1}}控制)并确保它们都由属性RadioButtonList命名,并检查了string GroupName postCollection

GroupName

你会注意到我在这里重新定义public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection) { bool oldValue = _isChecked; postCollection = HttpContext.Current.Request.Form; // See note below _isChecked = (postCollection[this.GroupName] == this.Text); return oldValue == _isChecked; } ;这是因为postCollection仅包含与ASP.Net认为您的控件应该关注的postCollection的子集。正如您在这里构建复合控件一样,您可能也希望这样做。

如果第一次不能正常工作,请不要担心;值得逐步介绍在调试模式下传递给此方法的内容(或将内容输出到HttpRequest.Form,这通常会更容易),以了解为什么您的代码不是您所需要的。

快速警告

最后一件事:仅当发布的表单包含名称与您的控件的HttpContext.Trace匹配的字段时,才会调用LoadPostData。由于你的控件是一个复合控件,你可能想稍微牛仔,如下:

UniqueID

这是一个肮脏的黑客,但它会起作用; o)

手动处理视图状态

如果手动处理回发无法解决您的问题,则可能需要弄乱控件的视图状态。别担心,如果您遵循一些简单的规则,这似乎远不像看起来那么可怕。

要手动处理您的视图状态,您只需要覆盖两个名为protected override void Render(HtmlTextWriter writer) { base.Render(writer); writer.WriteBeginTag("input"); writer.WriteAttribute("type", "hidden"); writer.WriteAttribute("name", this.UniqueID); writer.WriteAttribute("value", "post"); writer.Write(" />"); } LoadViewState的方法。第一个使用SaveViewState视图状态进行膨胀,另一个返回相同的object结构。如果您使object覆盖返回包含结构的内容,则需要保存所有需要保留的重要属性,然后您只需在SaveViewState方法中再次对其进行充气。

这是第一个狡猾的技巧出现的地方。您应该使用某些数据类型来保存viewstate,并且不应该使用任何其他类型(因为其他类型的存储效率非常低)。可能对您最有用的类型有System.Web.UI.PairSystem.Web.UI.Triplet和我们的老朋友System.Collections.ArrayListSystem.Collections.Hashtable。 Pairs和Triplets只存储两个或三个LoadViewState类型的值; ArrayLists实际上是object

我想在你的情况下,你可能想要存储(1)一个布尔标志的ArrayList,存储你的radiobuttons的“checkedness”或者(2)一个字符串或整数的ArrayList,存储这些ID或检查的radiobuttons的索引。

在我前面提到的控件中,我只需要存储checkness和List<object>属性,因此我的TextLoadViewState方法看起来像这样:

SaveViewState

同样,如果这不是第一次工作,你几乎肯定想要逐步执行代码或将内容扔进Trace中。重要的是,您可能希望避免从这些方法中抛出异常,以防您的视图状态损坏或不存在或者某些东西。

进一步阅读viewstate

当我搞乱viewstate时,我会留下一些非常有用的文章。第一个解释了为什么你应该只在视图状态中存储某些类型(比如使用protected override void LoadViewState(object savedState) { Pair state = savedState as Pair; if (state != null) { _isChecked = state.First as Nullable<bool> ?? false; this.Text = state.Second as string; } } protected override object SaveViewState() { return new Pair(_isChecked, this.Text); } ArrayList,而不是HashtableList<T>),第二个是好的深入解释所有这些视图状态实际上是如何工作的。

  1. Don't let the BinaryFormatter get at it!
  2. Truly understanding ViewState
  3. 我希望这一切都有助于解决您的问题。