欢迎来到飞鸟慕鱼博客,开始您的技术之旅!
当前位置: 首页知识笔记正文

ListControl数据绑定存在的问题

墨初 知识笔记 87阅读

Recently, the data binding function of radio button list was used when developing network forms. Because the selected value attribute supports bidirectional data binding, the constraint method can be used for bidirectional binding. Although the selected value does not appear in the smart prompt of the visual studio, it can still be used. This can be proved by using a mirror or eells skin to view the selected value property of the list control (the radio button list is inherited from the ListControl).//systemweb.com. ui。 Web control. List controls [Bindable(true, BindingDirection .TwoWay), WebCategory('Behavior'), Browsable(false), DefaultValue ('), DesignerSerializationVisibility (DesignerSerializationVisibility). Hidden), Themeable(false), Websys Description ('list control _ selected value')] public virtual string selected value . So I created a data object for binding, as shown below [Serializable] public class CandidateReferee {

public System.String Email { get; set; } public Guid? RefereeApproach { get; set; } public System.String Name { get; set; } public System.String Address { get; set; } public System.String Telephone { get; set; } }

 

接下来我把RadioButtonList放到了GridView TemplateField的ItemTemplate中

 

<asp:RadioButtonList ID="radApproach" DataSourceID="DataSourceApproach" DataTextField="CodeName" DataValueField="CodeValue" RepeatDirection="Horizontal" runat="server" SelectedValue='<%# Bind("RefereeApproach")%>'>
</asp:RadioButtonList>

 

在数据绑定时我提供的RefereeApproach属性值为null, 但是在程序运行的时候却出现了ArgumentOutOfRangeException

后来经过深入的研究发现,使用ListControl时如果存在了DataSourceID属性的情况下,如果还没有运行到OnPreRender的步骤的话,无论设置什么SelectedValue都不会出错,只有在OnPreRender时调用数据绑定的方法时才去进行验证。而此时它会把SelectedValue的属性值存放在cachedSelectedValue这个field中。如下所示:

 

[Bindable(true, BindingDirection.TwoWay), WebCategory("Behavior"), Browsable(false), DefaultValue(""), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Themeable(false), WebSysDescription("ListControl_SelectedValue")]
public virtual string SelectedValue
{
	get
	{
		......
	}
	set
	{
		if (this.Items.Count != 0)
		{
			if (value == null || (base.DesignMode && value.Length == 0))
			{
				this.ClearSelection();
				return;
			}
			ListItem listItem = this.Items.FindByValue(value);
			bool flag = this.Page != null && this.Page.IsPostBack && this._stateLoaded;
			if (flag && listItem == null)
			{
				throw new ArgumentOutOfRangeException("value", SR.GetString("ListControl_SelectionOutOfRange", new object[]
				{
					this.ID, 
					"SelectedValue"
				}));
			}
			if (listItem != null)
			{
				this.ClearSelection();
				listItem.Selected = true;
			}
		}
		<strong>this.cachedSelectedValue = value;</strong>
	}
}
// System.Web.UI.WebControls.ListControl
protected internal override void PerformDataBinding(IEnumerable dataSource)
{
	......
	<strong>if (this.cachedSelectedValue == null)
	 {
		if (this.cachedSelectedIndex != -1)
		{
			this.SelectedIndex = this.cachedSelectedIndex;
			this.cachedSelectedIndex = -1;
		}
		return;
	 }</strong>
	int num = this.Items.FindByValueInternal(this.cachedSelectedValue, true);
	if (-1 == num)
	{
		throw new ArgumentOutOfRangeException("value", SR.GetString("ListControl_SelectionOutOfRange", new object[]
		{
			this.ID, 
			"SelectedValue"
		}));
	}
	if (this.cachedSelectedIndex != -1 && this.cachedSelectedIndex != num)
	{
		throw new ArgumentException(SR.GetString("Attributes_mutually_exclusive", new object[]
		{
			"SelectedIndex", 
			"SelectedValue"
		}));
	}
	this.SelectedIndex = num;
	this.cachedSelectedValue = null;
	this.cachedSelectedIndex = -1;
}
而且当设置的属性值为null时,无论在哪个方法中都会忽略并且执行ClearSelection()方法清除已选择的选项。而问题就在这个地方,为什么我使用null属性值进行双向绑定的时候却没有被忽略,而是抛出了ArgumentOutOfRangeException在我调试之后发现,RadioButtonList在调用Bind方法进行数据绑定之后,实际cachedSelectedValue的值并不是null, 而是string.Empty,这让我很是困惑。所以无奈之下只好继续深入研究,以寻找产生这个问题的根本原因。

 

在这个时候我想到了,asp.net页面第一次执行的时候都要进行预编译,而这个预编译过程中使用到的所有方法都在System.Web.Compilation命名空间下,所以只要在这个地方去寻找就应该能够结果。果然功夫不负有心人,最终发现在System.Web.Compilation.CodeDomUtility的GenerateConvertToString(CodeExpressionvalue)方法中发现编译的过程中将Bind方法转成调用Convert.ToString(object value, IFormatProvider provider),代码如下所示:

internal static CodeExpression GenerateConvertToString(CodeExpression value)
{
  CodeMethodInvokeExpression expression = new CodeMethodInvokeExpression {
    Method = { TargetObject = BuildGlobalCodeTypeReferenceExpression(typeof(Convert)), MethodName = "ToString" }
  };
  expression.Parameters.Add(value);
  expression.Parameters.Add(new CodePropertyReferenceExpression(BuildGlobalCodeTypeReferenceExpression(typeof(CultureInfo)), "CurrentCulture"));
  return expression;
}
 

而恰恰就是在Convert中将null转成了string.Empty而使ListControl无法对其进行忽略的。如下所示

public static string ToString(object value, IFormatProvider provider)
{
  IConvertible convertible = value as IConvertible;
  if (convertible != null) return convertible.ToString(provider);
  IFormattable formattable = value as IFormattable;
  if (formattable != null) return formattable.ToString(null, provider);
  if (value != null) return value.ToString();
  return string.Empty;
}
注:所有测试和研究均是在.net framework 4.0中进行,对其他版本的framework不知道是否也存在此问题。

标签:
声明:无特别说明,转载请标明本文来源!