我正在使用动态创建的问题和选项在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之后失去了它的检查值,而我只是试图解决它。 如果有人能指出我正确的方向,我将不胜感激。
答案 0 :(得分:4)
IPostBackDataHandler
。这需要您实现两种方法LoadPostData
和RaisePostDataChangedEvent
。在我的第一次猜测中,第一个可能是你问题的根源。
LoadPostData
使用字符串postDataKey
和NameValueCollection
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.Pair
,System.Web.UI.Triplet
和我们的老朋友System.Collections.ArrayList
和System.Collections.Hashtable
。 Pairs和Triplets只存储两个或三个LoadViewState
类型的值; ArrayLists实际上是object
。
我想在你的情况下,你可能想要存储(1)一个布尔标志的ArrayList,存储你的radiobuttons的“checkedness”或者(2)一个字符串或整数的ArrayList,存储这些ID或检查的radiobuttons的索引。
在我前面提到的控件中,我只需要存储checkness和List<object>
属性,因此我的Text
和LoadViewState
方法看起来像这样:
SaveViewState
同样,如果这不是第一次工作,你几乎肯定想要逐步执行代码或将内容扔进Trace中。重要的是,您可能希望避免从这些方法中抛出异常,以防您的视图状态损坏或不存在或者某些东西。
当我搞乱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
,而不是Hashtable
和List<T>
),第二个是好的深入解释所有这些视图状态实际上是如何工作的。
我希望这一切都有助于解决您的问题。