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; }
在这个时候我想到了,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; }