您的位置:首页 > 其它

ListControl数据绑定时所出现的问题

2011-04-21 09:32 363 查看
最近在做webform开发的时候用到了RadioButtonList的数据绑定的功能。由于SelectedValue属性是支持TwoWay数据绑定的,所以可以使用Bind方法进行双向绑定。虽然在Visual Studio的智能提示中没有出现SelectedValue,但是仍然是可以使用的。在使用Reflector或者ILSpy查看ListControl(RadioButtonList继承自ListControl)的SelectedValue属性就可以证明这一点。

// System.Web.UI.WebControls.ListControl
[Bindable(true, BindingDirection.TwoWay), WebCategory("Behavior"), Browsable(false), DefaultValue(""), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Themeable(false), WebSysDescription("ListControl_SelectedValue")]
public virtual string SelectedValue
......


所以我创建了用于绑定的数据对象,如下所示

[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不知道是否也存在此问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐