检索绑定到 gridview 控件的复杂对象的值

发布于 2024-11-25 19:26:31 字数 4375 浏览 1 评论 0原文

gridview 控件使复杂对象的数据绑定变得相当容易。在我的场景中,gridview 控件绑定到一个 Customer 对象,该对象具有一些“平面”属性和一个采用 Address 类型对象的复杂属性。网格按预期显示数据。问题是我没有找到方法来访问代码后面的 Address 属性的值。例如,将 DataKeyNames 集合设置为 DataKeyNames="Id, Address.Id" 会导致错误:

DataBinding: System.Data.Entity.DynamicProxies.Customer_95531162E60920A5C3C02043F6564873913B91785C856624301E8B6E89906BF6 不包含名为 Address.Id 的属性。

在代码后面访问 Address.Id 字段的值的正确方法是什么?理想情况下,我想做这样的事情:

    protected void CustomerDetailsObjectDataSource_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
    if (CustomersGridView.SelectedIndex < 0) return;        

    // Retrieving the Customer's id works:
    e.InputParameters["id"] = Convert.ToString(CustomersGridView.DataKeys[CustomersGridView.SelectedIndex].Value);        

    // Retrieving the Address id doesn work:
    e.InputParameters["id"] = Convert.ToString(CustomersGridView.DataKeys[CustomersGridView.SelectedIndex].Values["Address.Id"].ToString());        
}

这是 asp 代码:

<ContentTemplate>

        <asp:GridView ID="CustomersGridView" runat="server" AutoGenerateColumns="False" DataSourceID="CustomersObjectDataSource"
                      onselectedindexchanged="CustomersGridView_SelectedIndexChanged" DataKeyNames="Id,Address.Id" ondatabound="CustomersGridView_DataBound">
            <Columns>
                <asp:TemplateField HeaderText="Aktion">
                    <ItemTemplate>
                        <asp:LinkButton runat="server" ID="SelectCustomerButton" Text="Auswählen" CommandName="Select" /> <br/>                         
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText="Kunde" SortExpression="LastName" ItemStyle-VerticalAlign="Top" >
                    <ItemTemplate>
                        <asp:Label ID="NumberLabel" runat="server" Text='<%#"GpNr: " + Eval("Number")%>'></asp:Label><br/>
                        <asp:Label ID="SalutationLabel" runat="server" Text='<%#Eval("Salutation")%>'></asp:Label>
                        <asp:Label ID="TitleLabel" runat="server" Text='<%#Eval("Title")%>'></asp:Label>
                        <asp:Label ID="FirstNameLabel" runat="server" Text='<%#Eval("FirstName")%>'></asp:Label>
                        <asp:Label ID="LastNameLabel" runat="server" Text='<%#Eval("LastName")%>'></asp:Label><br/>
                        <asp:Label ID="NameContactPersonLabel" runat="server" Text='<%#"Kontakt: " + Eval("NameContactPerson")%>'></asp:Label>
                    </ItemTemplate>
                    <ItemStyle VerticalAlign="Top" />
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Adresse" SortExpression="Address.PostalCode" ItemStyle-VerticalAlign="Top" >
                    <ItemTemplate>                            
                        <asp:Label ID="AddressIdLabel" runat="server" Text = '<%#Eval("Address.Id") %>'></asp:Label>
                        <asp:Label ID="AddressStreetLabel" runat="server" Text='<%#Eval("Address.Street")%>'></asp:Label>
                        <asp:Label ID="AddressHouseNumberLabel" runat="server" Text='<%#Eval("Address.HouseNumber")%>'></asp:Label>
                        <asp:Label ID="AddressHouseNumberExtensionLabel" runat="server" Text='<%#Eval("Address.HouseNumberExtension")%>'></asp:Label>
                        <asp:Label ID="AddressDoorNumberLabel" runat="server" Text='<%#Eval("Address.DoorNumber")%>'></asp:Label><br/>
                        <asp:Label ID="AddressPostalCodeLabel" runat="server" Text='<%#Eval("Address.PostalCode")%>'></asp:Label>
                        <asp:Label ID="AddressCityLabel" runat="server" Text='<%#Eval("Address.City")%>'></asp:Label><br/>
                        <asp:Label ID="AddressCountryLabel" runat="server" Text='<%#Eval("Address.Country")%>'></asp:Label>
                    </ItemTemplate>

谢谢!!

The gridview control makes databinding of complex objects rather easy. In my scenario a gridview control gets bound to a Customer object which has a few 'flat' properties and one complex property that takes an object of the type Address. The grid displays the data as expected. The problem is that I have found no way to access the values of the Address properties in code behind. For example, setting the DataKeyNames collection to DataKeyNames="Id, Address.Id" results in an error:

DataBinding: System.Data.Entity.DynamicProxies.Customer_95531162E60920A5C3C02043F6564873913B91785C856624301E8B6E89906BF6 does not contain a property with the name Address.Id.

What is the proper way to access the value of the Address.Id field in code behind? Ideally I'd like to do something like:

    protected void CustomerDetailsObjectDataSource_Selecting(object sender, ObjectDataSourceSelectingEventArgs e)
{
    if (CustomersGridView.SelectedIndex < 0) return;        

    // Retrieving the Customer's id works:
    e.InputParameters["id"] = Convert.ToString(CustomersGridView.DataKeys[CustomersGridView.SelectedIndex].Value);        

    // Retrieving the Address id doesn work:
    e.InputParameters["id"] = Convert.ToString(CustomersGridView.DataKeys[CustomersGridView.SelectedIndex].Values["Address.Id"].ToString());        
}

Here's the asp code:

<ContentTemplate>

        <asp:GridView ID="CustomersGridView" runat="server" AutoGenerateColumns="False" DataSourceID="CustomersObjectDataSource"
                      onselectedindexchanged="CustomersGridView_SelectedIndexChanged" DataKeyNames="Id,Address.Id" ondatabound="CustomersGridView_DataBound">
            <Columns>
                <asp:TemplateField HeaderText="Aktion">
                    <ItemTemplate>
                        <asp:LinkButton runat="server" ID="SelectCustomerButton" Text="Auswählen" CommandName="Select" /> <br/>                         
                    </ItemTemplate>
                </asp:TemplateField>

                <asp:TemplateField HeaderText="Kunde" SortExpression="LastName" ItemStyle-VerticalAlign="Top" >
                    <ItemTemplate>
                        <asp:Label ID="NumberLabel" runat="server" Text='<%#"GpNr: " + Eval("Number")%>'></asp:Label><br/>
                        <asp:Label ID="SalutationLabel" runat="server" Text='<%#Eval("Salutation")%>'></asp:Label>
                        <asp:Label ID="TitleLabel" runat="server" Text='<%#Eval("Title")%>'></asp:Label>
                        <asp:Label ID="FirstNameLabel" runat="server" Text='<%#Eval("FirstName")%>'></asp:Label>
                        <asp:Label ID="LastNameLabel" runat="server" Text='<%#Eval("LastName")%>'></asp:Label><br/>
                        <asp:Label ID="NameContactPersonLabel" runat="server" Text='<%#"Kontakt: " + Eval("NameContactPerson")%>'></asp:Label>
                    </ItemTemplate>
                    <ItemStyle VerticalAlign="Top" />
                </asp:TemplateField>
                <asp:TemplateField HeaderText="Adresse" SortExpression="Address.PostalCode" ItemStyle-VerticalAlign="Top" >
                    <ItemTemplate>                            
                        <asp:Label ID="AddressIdLabel" runat="server" Text = '<%#Eval("Address.Id") %>'></asp:Label>
                        <asp:Label ID="AddressStreetLabel" runat="server" Text='<%#Eval("Address.Street")%>'></asp:Label>
                        <asp:Label ID="AddressHouseNumberLabel" runat="server" Text='<%#Eval("Address.HouseNumber")%>'></asp:Label>
                        <asp:Label ID="AddressHouseNumberExtensionLabel" runat="server" Text='<%#Eval("Address.HouseNumberExtension")%>'></asp:Label>
                        <asp:Label ID="AddressDoorNumberLabel" runat="server" Text='<%#Eval("Address.DoorNumber")%>'></asp:Label><br/>
                        <asp:Label ID="AddressPostalCodeLabel" runat="server" Text='<%#Eval("Address.PostalCode")%>'></asp:Label>
                        <asp:Label ID="AddressCityLabel" runat="server" Text='<%#Eval("Address.City")%>'></asp:Label><br/>
                        <asp:Label ID="AddressCountryLabel" runat="server" Text='<%#Eval("Address.Country")%>'></asp:Label>
                    </ItemTemplate>

Thanks!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

灵芸 2024-12-02 19:26:31

原因是 Gridview 将 datakeynames 作为属性名称,它在 CreateChildControls() 期间使用 DataBinder.GetPropertyValue() 来检索数据键值,而 DataBinder.Eval 支持多级属性(只要用点字符分隔)

示例:

object item = ...
DataBinder.Eval(item, "Address.Id"); //no problem
DataBinder.GetPropertyValue(item, "Address.Id"); //will throw exception

有几种解决方案可以解决您的问题:

  1. 派生您的自定义 gridview(覆盖 CreateChildControls()),它的数据键名支持多层表达式。您可以使用 Reflector 来参考默认实现。 (大量工作)
  2. 在 RowDataBound 事件期间将复杂的属性值存储到视图状态中(首选,我也使用:))

示例:

private void CustomersGridView_RowDataBound(object sender, EventArgs args)
{
    if(e.Row.RowType = DataControlRowType.DataRow)
    {
        object id = DataBinder.Eval(e.Row.DataItem, "Id");

        //DictionaryInViewState is a variable that will be stored into viewstate later
        DictionaryInViewState[id] = DataBinder.Eval(e.Row.DataItem, "Address.Id");
    }
}

参考文献:

http://www.telerik.com/forums/problem-with-a-complex-datakeynames-value

the reason is Gridview consider datakeynames as the property name, it is using DataBinder.GetPropertyValue() during CreateChildControls() to retrieve data key values, while DataBinder.Eval support multiple level property( as long as it is separated by dot character)

Example:

object item = ...
DataBinder.Eval(item, "Address.Id"); //no problem
DataBinder.GetPropertyValue(item, "Address.Id"); //will throw exception

there are several solution to solve your problem:

  1. derive your custom gridview(override the CreateChildControls()) that it's datakeynames support multi layer expression. You may refer the default implementation by using Reflector. (lots of work)
  2. store the complex property values into viewstate during RowDataBound event (prefered, and also used by me too :) )

Example:

private void CustomersGridView_RowDataBound(object sender, EventArgs args)
{
    if(e.Row.RowType = DataControlRowType.DataRow)
    {
        object id = DataBinder.Eval(e.Row.DataItem, "Id");

        //DictionaryInViewState is a variable that will be stored into viewstate later
        DictionaryInViewState[id] = DataBinder.Eval(e.Row.DataItem, "Address.Id");
    }
}

References:

http://www.telerik.com/forums/problem-with-a-complex-datakeynames-value

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文