Asp 复合控件子控件(单选按钮)丢失选中值

发布于 2024-09-25 23:37:23 字数 898 浏览 2 评论 0原文

我正在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

落花随流水 2024-10-02 23:37:23

乍一看,我要检查两件事。首先,确保您正在实施 IPostBackDataHandler< /代码>。这需要您实现两个方法:LoadPostDataRaisePostDataChangedEvent。根据我的第一个猜测,第一个可能是您问题的根源。

手动处理回发

LoadPostData 需要一个字符串 postDataKey 和一个 NameValueCollection postCollection 并返回一个 bool 指示值是否已更改作为回发的结果。您不需要按照 .Net 最初的意图来实现这一点,例如,我创建了一个包含多个单选按钮的控件(由于此处不重要的原因,该按钮不能简单地是一个 < code>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 ;这是因为 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)

手动处理视图状态

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

要手动处理视图状态,您只需要重写两个方法,显然,这是 LoadViewStateSaveViewState。第一个需要视图状态的对象来膨胀,另一个返回相同的对象结构。如果您让 SaveViewState 重写返回包含保存所有需要持久化的重要属性所需的结构的内容,那么您只需在 LoadViewState 方法中再次对其进行膨胀即可。

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

我猜想,在您的情况下,您可能想要存储(1)布尔标志的 ArrayList,存储单选按钮的“检查性”或(2)字符串或整数的 ArrayList,存储 ID 或索引选中的单选按钮。

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

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);
}

同样,如果第一次不起作用,您几乎肯定想要单步执行代码或将内容放入跟踪中。重要的是,您可能希望避免从这些方法中抛出异常,以防您的视图状态损坏或不存在或其他情况。

关于 viewstate 的进一步阅读

当我搞乱 viewstate 时,我会为几篇非常有用的文章添加书签。第一个解释了为什么您应该只在视图状态中存储某些类型(例如使用 ArrayList 和 Hashtable,而不是 ListDictionary),第二个是对所有这些视图状态内容实际上如何工作的很好的深入解释。

  1. 不要让 BinaryFormatter 得逞!
  2. 真正理解ViewState

希望大家这有助于解决您的问题。

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 and RaisePostDataChangedEvent. At my first guess, the first one is probably the source of your problem.

Handling postback manually

LoadPostData takes a string postDataKey and a NameValueCollection postCollection and returns a bool 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 a RadioButtonList control) and so made sure they were all named by a property string GroupName and inspected the postCollection for that 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;
}

You'll notice that I'm redefining the postCollection here; this is because postCollection only contains a subset of the HttpRequest.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 the UniqueID of your control. As your control is a composite control, you might want to cowboy this slightly, like so:

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

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 and SaveViewState. The first takes an object of viewstate to inflate and the other returns that same object structure. If you make your SaveViewState override return something containing the structure you need to save all the important properties that need persisting, then you just inflate it again in your LoadViewState 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 friends System.Collections.ArrayList and System.Collections.Hashtable. Pairs and Triplets simply store two or three values of type object; ArrayLists are effectively a List<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 my LoadViewState and SaveViewState methods looked like this:

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);
}

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 and Hashtable, rather than List<T> and Dictionary<TKey, TValue>) and the second is a good in-depth explanation of how all this viewstate stuff actually works.

  1. Don't let the BinaryFormatter get at it!
  2. Truly understanding ViewState

I hope all this helps resolve your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文