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

C# Asp复合控件子控件(单选按钮)丢失选中值,c#,asp.net,composite-controls,C#,Asp.net,Composite Controls,我正在asp.net中使用动态创建的问题和选项开发测验控件。 主控件基本上是一个容纳所有问题的容器。 在“设计”视图中,用户可以通过自定义集合编辑器添加问题。 每次我向集合编辑器列表添加问题时,它都会为我生成一个问题标签。 每个问题对象内部都有一个标签和n个继承Radiobutton控件的选项对象。每个选项对象依次表示用户可以为每个问题选择的选项 这一切工作,除了我现在的部分,我希望能够读取每个单选按钮的检查值。当我想在页面内实施此测验并检查问题时,我想在此页面中放置一个按钮并调用控件内的以下函

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

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

$

但是,一旦我选择一个单选按钮并单击submit按钮,所有选项的选中值都将变为false。 基本上,它在回发后失去了它的校验值,我只是被困在试图解决它。
如果有人能为我指出正确的方向,我将不胜感激。

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

手动处理回发
LoadPostData
获取一个字符串
postDataKey
和一个
postCollection
,并返回一个
bool
,指示值是否因回发而改变。您不需要按照.Net最初的意图来实现它,例如,我创建了一个包含多个单选按钮的控件(出于此处不重要的原因,它不能只是一个
RadioButtonList
控件)因此,请确保它们都是由属性
字符串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
只包含
HttpRequest.Form
的子集,对应于ASP.Net认为控件应该关心的内容。当您在这里构建复合控件时,您可能也希望这样做

如果这在第一次不起作用,不要担心;在调试模式下(或者将内容输出到
HttpContext.Trace
,我经常发现这更容易)单步了解一下为什么您的代码不是您所需要的

快速警告 最后一件事:
LoadPostData
仅在发布表单包含名称与控件的
UniqueID
匹配的字段时调用。由于您的控件是复合控件,您可能希望稍微简化此操作,如下所示:

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 如果手动处理回发无法解决您的问题,则可能需要处理控件的viewstate。别担心,只要你遵循一些简单的规则,这远没有看上去那么可怕

要手动处理viewstate,您只需覆盖两个方法,显然,这两个方法分别是
LoadViewState
SaveViewState
。第一个将viewstate的
对象
充气,另一个返回相同的
对象
结构。如果使
SaveViewState
覆盖返回包含保存所有需要持久化的重要属性所需结构的内容,则只需在
LoadViewState
方法中再次充气即可

这里是第一个狡猾的把戏出现的地方。保存viewstate时应该使用某些数据类型,并且永远不要使用任何其他类型(因为其他类型的存储效率非常低)。可能对你最有用的类型是,以及我们的老朋友和朋友。成对和三元组只存储两个或三个类型为
object
的值;ArrayList实际上是一个
列表

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

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

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);
}
protected override void LoadViewState(对象保存状态)
{
Pair state=将数据状态保存为Pair;
如果(状态!=null)
{
_isChecked=状态。首先为可空??false;
this.Text=state.Second作为字符串;
}
}
受保护的覆盖对象SaveViewState()
{
返回新的对(_已选中,this.Text);
}
同样,如果这在第一次不起作用,您几乎肯定希望逐步完成代码或将内容放入跟踪中。重要的是,您可能希望避免从这些方法引发异常,以防viewstate损坏或不存在或其他情况

进一步阅读viewstate 当我在处理viewstate时,有几篇非常有用的文章会被我保留在书签中。第一个解释了为什么应该只在viewstate中存储某些类型(比如使用
ArrayList
Hashtable
,而不是
List
Dictionary
),第二个解释了所有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);
    }