在FormView控件中嵌套数据绑定控件的问题,以及从一个对象中反射获取属性值的简单办法

最近研究Entity Framework 4 + ObjectDataSource + FormView的组合。

问题在于下面这段代码:

1 <EditItemTemplate>
2 <sc:NetCheckPolicyDropDownList ID="ddlNetCheckPolicy" runat="server"
3 SelectedValue='<%#Bind("OverrideNetCheckPolicyID") %>' >
4 </sc:NetCheckPolicyDropDownList>
5  </EditItemTemplate>

在FormView控件的EditItemTemplate模板中,我使用了自定义DropDownList控件,这些DropDownList控件通过调用自己的DataBind方法完成数据绑定加载。同时,利用标准的“Bind”方式设置DropDownList控件的SelectedValue属性,以谋求对DropDownList的双向绑定。

看上去没什么不妥,但是在运行时报错:

Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control

就经过艰苦卓绝地Google和各种分析,原来问题在于,简单地说,执行DropDownList的DataBind时,那个“<%#Bind ... %> ”被当作这个绑定的一部分执行了,但它本来应该是FormView控件绑定时才需要做的。可惜我们能分出来,ASP.NET分不出来。解决的方法有2个:

1. DropDownList不要采用默认的DataBind方法加载数据,而采用自定义的数据加载。

2. 手工在FormView的ItemCreated (或者DataBound?)事件中为DropDownList的SelectedValue赋值,并在FormView执行插入或更新的操作时再手工把DropDownList值取出来。

我采用了第一种方式,在我的DropDownList中加入了新的数据加载方法,基本上套用了反射出来的标准DropDownList控件具体执行绑定数据的操作(代码仅供参考):

public void DataPopulate()
{
    DataPopulate(false);
}
 
/// <summary>
/// Populate the DropDownList control.
/// </summary>
/// <param name="usingDataBind">gets or sets a value indicating whether to use the standard DataBind mechanism</param>
public void DataPopulate(bool usingDataBind)
{
    Items.Clear();
    DataSource = CreateDataSource();
    if (DataSource == null)
        return;
    if (usingDataBind)
    {
        DataBind();
        return;
    }
 
    IEnumerable source = DataSource as IEnumerable;
    if (source == null)
        throw new InvalidCastException("DataSource must be of type \"IEnumerable\"");
 
    if (DataTextField.Length == 0)
        throw new ArgumentNullException("DataTextField");
    if (DataValueField.Length == 0)
        DataValueField = DataTextField;
 
    ICollection sourceCollection = DataSource as ICollection;
    if (sourceCollection != null)
        Items.Capacity = sourceCollection.Count + Items.Count;
 
    ListItem li;
    foreach (object item in source)
    {
        li = new ListItem();
        li.Text = DataBinder.GetPropertyValue(item, DataTextField, DataTextFormatString);
        li.Value = DataBinder.GetPropertyValue(item, DataValueField, null);
        Items.Add(li);
    }
    OnDataBound(EventArgs.Empty);
}
 
/// <summary>
/// create a data source object used by DropDownList control
/// </summary>
/// <returns>a data source object</returns>
protected virtual object CreateDataSource()
{
    return null;
}

注意,System.Web.UI.DataBinder类,用这个类可以方便的从一个对象中反射出属性的值,省却了我们自己反射的麻烦。

最后这也给了我一个启示,对于这种可能将来作为绑定控件内再绑定的自定义控件,还是尽量不要用默认的绑定机制吧,省得出现这种问题。

posted on   零度的火  阅读(543)  评论(0编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
历史上的今天:
2009-04-22 发布一个IE8的加速器,解决非超链接的URL地址浏览问题

导航

< 2011年4月 >
27 28 29 30 31 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
1 2 3 4 5 6 7
点击右上角即可分享
微信分享提示