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

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

这一切都有效,除了我现在在我希望能够读取每个radiobutton的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之后失去了它的检查值,而我只是试图解决它。 如果有人能指出我正确的方向,我将不胜感激。

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

手动处理回发

LoadPostData接受一个字符串postDataKey和一个NameValueCollection postCollection并返回一个bool指示该值是否因回发而发生了变化。 你不需要像.Net最初想要的那样实现它,例如我创建了一个控件,它有几个单选按钮(由于这里不重要的原因不能简单地成为RadioButtonList控件),所以确保它们都是由属性string GroupName命名并检查该string GroupNamepostCollection

 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 ; 这是因为postCollection只包含与ASP.Net认为你的控件应该关心的HttpRequest.Form的子集。 正如您在此处构建复合控件一样,您可能也希望这样做。

如果这不能在第一轮工作,请不要担心; 值得逐步介绍在调试模式下传递给此方法的内容(或者将内容输出到HttpContext.Trace ,我经常会发现它更容易),看看为什么你的代码不是你需要的。

一个快速警告

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

 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(" />"); } 

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

手动处理视图状态

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

要手动处理viewstate,您只需要覆盖两个调用的方法,显然就是LoadViewStateSaveViewState 。 第一个使viewstate的object膨胀,另一个返回相同的object结构。 如果你使SaveViewState覆盖返回包含需要保存所有需要持久化的重要属性的结构的东西,那么你只需在LoadViewState方法中再次膨胀它。

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

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

在我前面提到的控件中,我只需要存储checkedness和Text属性,因此我的LoadViewStateSaveViewState方法如下所示:

 protected override void LoadViewState(object savedState) { Pair state = savedState as Pair; if (state != null) { _isChecked = state.First as Nullable ?? false; this.Text = state.Second as string; } } protected override object SaveViewState() { return new Pair(_isChecked, this.Text); } 

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

进一步阅读viewstate

当我搞乱viewstate时,有一些非常有用的文章我会留下书签。 第一个解释了为什么你应该只在viewstate中存储某些类型(比如使用ArrayListHashtable ,而不是ListDictionary ),第二个是对所有这些如何进行深入的解释viewstate东西实际上工作。

  1. 不要让BinaryFormatter得到它!
  2. 真正了解ViewState

我希望这一切都有助于解决您的问题。