Asp 复合控件子控件(单选按钮)丢失选中值
我正在 asp.net 中开发一个测验控件,其中包含动态创建的问题和选项。 主控件基本上是一个容纳所有问题的容器。 在设计视图中,用户可以通过自定义集合编辑器添加问题。 每次我向集合编辑器列表添加问题时,它都会为我生成一个问题标签。 每个问题对象内部都有一个标签和n 个继承Radiobutton 控件的Option 对象。这些 Option 对象中的每一个又代表用户可以为每个问题选择的选项。
这一切都有效,除了我现在处于我希望能够读取每个单选按钮的选中值的部分。当我想在页面内实现此测验并检查问题时,我想在此页面中放置一个按钮并调用控件内的以下函数:
$
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;
}
但是,一旦我选择单选按钮并单击提交按钮,检查值对于所有选项来说,结果总是错误的。 基本上,它在回发后失去了其检查值,我只是试图解决它。 如果有人能指出我正确的方向,我将不胜感激。
I am working on a quiz control in asp.net with dynamically created questions and options.
The main control is basically a container to hold all of the questions.
In design view users can add questions through a custom Collection Editor.
Everytime i add a question to the collection editor list it generates a question tag for me.
Inside each question object is a label and a n amount of Option objects that inherit the Radiobutton Control. Each of these Option objects in turn represent a option the user can select for each question.
This all works except i am now at the part where i want to be able to read the Checked value of each radiobutton. When i want to implement this quiz inside a page and check the questions i want to put a button in this page and call the following function that is inside the control:
$
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;
}
However once i select a radiobutton and click on the submit button the Checked value will always turn out false for all of the options.
Basically it is losing its checked value after a Postback and i am just stuck in trying to solve it.
Would appreciate it if anyone could point me in the right direction.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
乍一看,我要检查两件事。首先,确保您正在实施
IPostBackDataHandler< /代码>
。这需要您实现两个方法:
LoadPostData
和RaisePostDataChangedEvent
。根据我的第一个猜测,第一个可能是您问题的根源。手动处理回发
LoadPostData
需要一个字符串postDataKey
和一个NameValueCollection
postCollection
并返回一个bool
指示值是否已更改作为回发的结果。您不需要按照 .Net 最初的意图来实现这一点,例如,我创建了一个包含多个单选按钮的控件(由于此处不重要的原因,该按钮不能简单地是一个 < code>RadioButtonList 控件),因此确保它们全部由属性string GroupName
命名,并检查postCollection
中的GroupName
:您会注意到我在这里重新定义了
postCollection
;这是因为postCollection
仅包含与 ASP.Net 认为您的控件应该关心的内容相对应的HttpRequest.Form
的子集。由于您也在此处构建复合控件,因此您可能也想做同样的事情。如果第一次不起作用,请不要担心;值得在调试模式下逐步了解传递到此方法的内容(或将内容输出到
HttpContext.Trace
,我经常发现这更容易),以了解为什么您的代码不完全是您所需要的。快速警告
最后一件事:仅当发布的表单包含名称与控件的
UniqueID
匹配的字段时,才会调用LoadPostData
。由于您的控件是复合控件,因此您可能需要稍微牛仔一下,如下所示:这是一个肮脏的黑客,但它会起作用;o)
手动处理视图状态
如果手动处理回发不能解决您的问题,则可能是您需要弄乱控件的视图状态。别担心,只要您遵循一些简单的规则,这远没有看起来那么可怕。
要手动处理视图状态,您只需要重写两个方法,显然,这是
LoadViewState
和SaveViewState
。第一个需要视图状态的对象
来膨胀,另一个返回相同的对象
结构。如果您让SaveViewState
重写返回包含保存所有需要持久化的重要属性所需的结构的内容,那么您只需在LoadViewState
方法中再次对其进行膨胀即可。这就是第一个狡猾的伎俩出现的地方。您应该使用某些数据类型来保存视图状态,并且永远不应该使用任何其他类型(因为其他类型的存储效率非常低)。对您最有用的类型可能是
System.Web.UI.Pair
,System.Web.UI.Triplet
和我们的老朋友System.Collections.ArrayList
和System.Collections.Hashtable
。 Pairs 和 Triplets 只是存储两个或三个object
类型的值; ArrayList 实际上是一个List
我猜想,在您的情况下,您可能想要存储(1)布尔标志的 ArrayList,存储单选按钮的“检查性”或(2)字符串或整数的 ArrayList,存储 ID 或索引选中的单选按钮。
在我之前提到的控件中,我只需要存储选中状态和
Text
属性,因此我的LoadViewState
和SaveViewState
方法如下所示:同样,如果第一次不起作用,您几乎肯定想要单步执行代码或将内容放入跟踪中。重要的是,您可能希望避免从这些方法中抛出异常,以防您的视图状态损坏或不存在或其他情况。
关于 viewstate 的进一步阅读
当我搞乱 viewstate 时,我会为几篇非常有用的文章添加书签。第一个解释了为什么您应该只在视图状态中存储某些类型(例如使用 ArrayList 和 Hashtable,而不是 List和
Dictionary
),第二个是对所有这些视图状态内容实际上如何工作的很好的深入解释。希望大家这有助于解决您的问题。
At a first glance, there are two things I'd check. Firstly, make sure you're implementing
IPostBackDataHandler
. this requires you to implement two methods,LoadPostData
andRaisePostDataChangedEvent
. At my first guess, the first one is probably the source of your problem.Handling postback manually
LoadPostData
takes a stringpostDataKey
and aNameValueCollection
postCollection
and returns abool
indicating whether or not the value has changed as a result of the postback. You don't need to implement this the way .Net originally intends, for example I created a control that held several radio buttons (that for reasons that aren't important here couldn't simply be aRadioButtonList
control) and so made sure they were all named by a propertystring GroupName
and inspected thepostCollection
for thatGroupName
:You'll notice that I'm redefining the
postCollection
here; this is becausepostCollection
only contains a subset of theHttpRequest.Form
corresponding to what ASP.Net thinks your control should care about. As you're also building a composite control here, you probably want to do the same.Don't worry if this doesn't work first time round; it's worth stepping through what gets passed into this method in debug mode (or outputting things to the
HttpContext.Trace
, which I often find easier) to see why your code isn't quite what you need.A quick caveat
One last thing:
LoadPostData
is only called if the posted form contains a field with a name which matches theUniqueID
of your control. As your control is a composite control, you might want to cowboy this slightly, like so:It's a dirty hack, but it'll work ;o)
Handling viewstate manually
If handling the postback manually doesn't solve your problem, it might be that you need to mess with the viewstate of your control. Don't worry, this is nowhere near as scary as it seems, provided you follow a few simple rules.
To handle your viewstate manually, you just need to override two methods called, obviously enough,
LoadViewState
andSaveViewState
. The first takes anobject
of viewstate to inflate and the other returns that sameobject
structure. If you make yourSaveViewState
override return something containing the structure you need to save all the important properties that need persisting, then you just inflate it again in yourLoadViewState
method.Here's where the first of the cunning tricks comes up. There are certain datatypes that you should use for saving viewstate and you should never use any other type (because other types are stored really inefficiently). The types that will probably be most useful to you are
System.Web.UI.Pair
,System.Web.UI.Triplet
and our old friendsSystem.Collections.ArrayList
andSystem.Collections.Hashtable
. Pairs and Triplets simply store two or three values of typeobject
; ArrayLists are effectively aList<object>
.I'd guess that, in your circumstance, you probably want to store either (1) an ArrayList of boolean flags, storing the "checkedness" of your radiobuttons or (2) an ArrayList of strings or ints, storing the IDs or index of the checked radiobuttons.
In the control I mentioned earlier, I just needed to store the checkedness and the
Text
property, so myLoadViewState
andSaveViewState
methods looked like this:Again, if this doesn't work first time, you almost certainly want to step through the code or throw things into the Trace. Importantly, you probably want to avoid throwing Exceptions from these methods, in case your viewstate is corrupt or non-existent or something.
Further reading on viewstate
There are a couple of very useful articles I keep bookmarked for when I'm messing with viewstate. The first one explains about why you should only store certain types in the viewstate (like using
ArrayList
andHashtable
, rather thanList<T>
andDictionary<TKey, TValue>
) and the second is a good in-depth explanation of how all this viewstate stuff actually works.I hope all this helps resolve your problem.