自定义控件子控件未持久保存到 ASP.NET 4.0 中的 ViewState
我们刚刚将 ASP.NET Web 应用程序中的目标框架从 3.5 切换到 4.0。我们遇到了以下问题:
我们有几个自定义控件在 3.5 中运行良好,但现在在 4.0 中它们不再保留在 ViewState 中,其中一个基本上是继承 Label 类和 aspx 代码的其他控件的包装器看起来像这样:
<fsc:FormLabel ID="l_purchaserNo" runat="server" CssClass="label" Text="Purchaser">
<asp:TextBox ID="tb_purchaserNo" runat="server" CssClass="textBox" MaxLength="50" />
</fsc:FormLabel>
生成的 html 是:
<span id="l_purchaserNo" class="label">
<label class="header" for="tb_purchaserNo">Purchaser</label>
<span class="valueContainer">
<input name="tb_purchaserNo" type="text" id="tb_purchaserNo" class="textBox" />
</span>
</span>
所以该控件基本上只是添加了一些 span 标签和一个连接到文本框的标签。
回发后,4.0 中的 html 代码是:
<span id="l_purchaserNo" class="label"></span>
即外部包装器中的所有内容都消失了,并且无法从后面的代码中检索文本框中输入的任何内容。
下面您可以找到 FormLabel 类的代码。
我们发现,通过在自定义控件 fsc:FormLabel 上设置 ViewStateMode=Disabled 并在 asp:TextBox 上设置 ViewStateMode=Enabled,内部控件会保留 ViewState,但同时我们会在包装器上丢失 ViewState,因为我们将文本翻译为包装标签,我们也需要 viewstate (实际上,我们尝试了每种组合,并且在 fsc:FormLabel 上设置 ViewStateMode=Enabled 没有帮助,无论我们如何在 页)。 EnableViewState 在所有级别上均为 true。
有人可以告诉我们如何让 ViewState 在 3.5 中像以前一样在所有控件(包装器以及包装控件)上工作吗?
谢谢克里斯蒂安
、泽利科、乔纳斯
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace FormLabel
{
public class FormLabel : Label
{
private bool HasChildren
{
get
{
return Controls.Count > 0;
}
}
public override string Text
{
get
{
if (!HasChildren)
{
return base.Text;
}
var text = ViewState[ID + "Text"] as String;
if (text != null)
{
((LiteralControl)Controls[0]).Text = text;
}
return ((LiteralControl)Controls[0]).Text;
}
set
{
if (!HasChildren)
{
base.Text = value;
return;
}
((LiteralControl)Controls[0]).Text = value;
}
}
public void SetText(string text)
{
((LiteralControl)Controls[0]).Text = text;
ViewState[ID + "Text"] = text;
}
public bool IndicateRequired
{
get
{
object state = ViewState[String.Format("{0}_IR", ID)];
return state != null && (bool)state;
}
set
{
ViewState[String.Format("{0}_IR", ID)] = value;
}
}
protected override void OnLoad(EventArgs e)
{
ViewState[ID + "Text"] = Text;
base.OnLoad(e);
}
protected override void Render(HtmlTextWriter writer)
{
if (HasChildren)
{
List<Control> controls = Controls.GetControls();
List<BaseValidator> validators = Controls.GetValidators();
WriteLabelControl(writer);
WriteRequiredIndicator(writer);
WriteControlHeader(writer, validators, this.GetFirstControl());
WriteInnerControls(writer, controls);
WriteLabelEndControl(writer);
return;
}
base.Render(writer);
}
private void WriteLabelControl(HtmlTextWriter writer)
{
writer.WriteBeginTag("span");
writer.WriteAttribute("id", ClientID);
writer.WriteAttribute("class", CssClass);
foreach (string attributeKey in Attributes.Keys)
{
writer.WriteAttribute(attributeKey, Attributes[attributeKey]);
}
writer.Write(HtmlTextWriter.TagRightChar);
}
private void WriteRequiredIndicator(HtmlTextWriter writer)
{
if (IndicateRequired)
{
writer.WriteBeginTag("span");
writer.WriteAttribute("class", "requiredIndicator");
writer.Write(HtmlTextWriter.TagRightChar);
writer.WriteEndTag("span");
}
}
private void WriteControlHeader(HtmlTextWriter writer, IEnumerable<BaseValidator> validators, Control userControl)
{
writer.WriteBeginTag("label");
writer.WriteAttribute("class", "header");
if (userControl != null)
{
writer.WriteAttribute("for", userControl.ClientID);
}
writer.Write(HtmlTextWriter.TagRightChar);
writer.Write(Text);
foreach (BaseValidator validator in validators)
{
validator.CssClass = "Error";
validator.RenderControl(writer);
}
writer.WriteEndTag("label");
}
private static void WriteInnerControls(HtmlTextWriter writer, IList<Control> controls)
{
writer.WriteBeginTag("span");
writer.WriteAttribute("class", "valueContainer");
writer.Write(HtmlTextWriter.TagRightChar);
for (int i = 1; i < controls.Count; i++)
{
controls[i].RenderControl(writer);
}
writer.WriteEndTag("span");
}
private static void WriteLabelEndControl(HtmlTextWriter writer)
{
writer.WriteEndTag("span");
}
}
#region Nested type: Extensions
public static class Extensions
{
public static List<BaseValidator> GetValidators(this ControlCollection controls)
{
var validators = new List<BaseValidator>();
foreach (Control c in controls)
{
if (c is BaseValidator)
{
validators.Add(c as BaseValidator);
}
}
return validators;
}
public static List<Control> GetControls(this ControlCollection controls)
{
var listcontrols = new List<Control>();
foreach (Control c in controls)
{
if (!(c is BaseValidator))
{
listcontrols.Add(c as Control);
}
}
return listcontrols;
}
public static Control GetFirstControl(this Control container)
{
return (new InputControlFinder().FindFirstInputControl(container));
}
private class InputControlFinder
{
public Control FindFirstInputControl(Control control)
{
Control input = null;
foreach (Control child in control.Controls)
{
if (child is TextBox || child is DropDownList || child is CheckBox)
{
input = child;
}
else
{
input = FindFirstInputControl(child);
}
if (input != null)
{
return input;
}
}
return input;
}
}
}
#endregion
}
We just switched target framework in our ASP.NET web application from 3.5 to 4.0. We ran into the following problem:
We have a couple of custom controls that worked fine in 3.5 but now with 4.0 they are not persisted in ViewState, one of them is basically a wrapper for other controls that inherits the Label class and the aspx-code looks like this:
<fsc:FormLabel ID="l_purchaserNo" runat="server" CssClass="label" Text="Purchaser">
<asp:TextBox ID="tb_purchaserNo" runat="server" CssClass="textBox" MaxLength="50" />
</fsc:FormLabel>
and the resulting html is:
<span id="l_purchaserNo" class="label">
<label class="header" for="tb_purchaserNo">Purchaser</label>
<span class="valueContainer">
<input name="tb_purchaserNo" type="text" id="tb_purchaserNo" class="textBox" />
</span>
</span>
So the control basically just adds a few span-tags and a label that is connected to the textbox.
After postback the html-code in 4.0 was:
<span id="l_purchaserNo" class="label"></span>
i.e. everything within the outer wrapper was gone and anything entered in the textbox could not be retreived from code behind.
Below you find the code for our FormLabel class.
We found that by setting ViewStateMode=Disabled on our custom control fsc:FormLabel and ViewStateMode=Enabled on the asp:TextBox the inner controls where persisted to ViewState but at the same time we lost ViewState on the wrapper and since we translate the text on the wrapper label we need viewstate for this as well (actually we tried every combination and setting ViewStateMode=Enabled on fsc:FormLabel did not help, regardless of how we set the ViewStateMode on the page). EnableViewState is true on all levels.
Could someone tell us how to get ViewState to work as before in 3.5, on ALL controls - wrapper as well as wrapped controls?
Thanks
Christian, Zeljko, Jonas
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace FormLabel
{
public class FormLabel : Label
{
private bool HasChildren
{
get
{
return Controls.Count > 0;
}
}
public override string Text
{
get
{
if (!HasChildren)
{
return base.Text;
}
var text = ViewState[ID + "Text"] as String;
if (text != null)
{
((LiteralControl)Controls[0]).Text = text;
}
return ((LiteralControl)Controls[0]).Text;
}
set
{
if (!HasChildren)
{
base.Text = value;
return;
}
((LiteralControl)Controls[0]).Text = value;
}
}
public void SetText(string text)
{
((LiteralControl)Controls[0]).Text = text;
ViewState[ID + "Text"] = text;
}
public bool IndicateRequired
{
get
{
object state = ViewState[String.Format("{0}_IR", ID)];
return state != null && (bool)state;
}
set
{
ViewState[String.Format("{0}_IR", ID)] = value;
}
}
protected override void OnLoad(EventArgs e)
{
ViewState[ID + "Text"] = Text;
base.OnLoad(e);
}
protected override void Render(HtmlTextWriter writer)
{
if (HasChildren)
{
List<Control> controls = Controls.GetControls();
List<BaseValidator> validators = Controls.GetValidators();
WriteLabelControl(writer);
WriteRequiredIndicator(writer);
WriteControlHeader(writer, validators, this.GetFirstControl());
WriteInnerControls(writer, controls);
WriteLabelEndControl(writer);
return;
}
base.Render(writer);
}
private void WriteLabelControl(HtmlTextWriter writer)
{
writer.WriteBeginTag("span");
writer.WriteAttribute("id", ClientID);
writer.WriteAttribute("class", CssClass);
foreach (string attributeKey in Attributes.Keys)
{
writer.WriteAttribute(attributeKey, Attributes[attributeKey]);
}
writer.Write(HtmlTextWriter.TagRightChar);
}
private void WriteRequiredIndicator(HtmlTextWriter writer)
{
if (IndicateRequired)
{
writer.WriteBeginTag("span");
writer.WriteAttribute("class", "requiredIndicator");
writer.Write(HtmlTextWriter.TagRightChar);
writer.WriteEndTag("span");
}
}
private void WriteControlHeader(HtmlTextWriter writer, IEnumerable<BaseValidator> validators, Control userControl)
{
writer.WriteBeginTag("label");
writer.WriteAttribute("class", "header");
if (userControl != null)
{
writer.WriteAttribute("for", userControl.ClientID);
}
writer.Write(HtmlTextWriter.TagRightChar);
writer.Write(Text);
foreach (BaseValidator validator in validators)
{
validator.CssClass = "Error";
validator.RenderControl(writer);
}
writer.WriteEndTag("label");
}
private static void WriteInnerControls(HtmlTextWriter writer, IList<Control> controls)
{
writer.WriteBeginTag("span");
writer.WriteAttribute("class", "valueContainer");
writer.Write(HtmlTextWriter.TagRightChar);
for (int i = 1; i < controls.Count; i++)
{
controls[i].RenderControl(writer);
}
writer.WriteEndTag("span");
}
private static void WriteLabelEndControl(HtmlTextWriter writer)
{
writer.WriteEndTag("span");
}
}
#region Nested type: Extensions
public static class Extensions
{
public static List<BaseValidator> GetValidators(this ControlCollection controls)
{
var validators = new List<BaseValidator>();
foreach (Control c in controls)
{
if (c is BaseValidator)
{
validators.Add(c as BaseValidator);
}
}
return validators;
}
public static List<Control> GetControls(this ControlCollection controls)
{
var listcontrols = new List<Control>();
foreach (Control c in controls)
{
if (!(c is BaseValidator))
{
listcontrols.Add(c as Control);
}
}
return listcontrols;
}
public static Control GetFirstControl(this Control container)
{
return (new InputControlFinder().FindFirstInputControl(container));
}
private class InputControlFinder
{
public Control FindFirstInputControl(Control control)
{
Control input = null;
foreach (Control child in control.Controls)
{
if (child is TextBox || child is DropDownList || child is CheckBox)
{
input = child;
}
else
{
input = FindFirstInputControl(child);
}
if (input != null)
{
return input;
}
}
return input;
}
}
}
#endregion
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论