Получить значение сложного объекта, привязанного к элементу управления gridview
Управление gridview делает привязку данных сложных объектов довольно простой. В моем сценарии элемент управления gridview привязывается к объекту Customer, который имеет несколько "плоских" свойств и одно сложное свойство, которое принимает объект типа Address. Сетка отображает данные, как и ожидалось. Проблема в том, что я не нашел способа получить доступ к значениям свойств адреса в коде позади. Например, задание для коллекции DataKeyNames значения DataKeyNames = "Id, Address.Id" приведет к ошибке:
Привязка данных: 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>
Спасибо!!
1 ответ
Причина в том, что Gridview рассматривает datakeynames как имя свойства, он использует DataBinder.GetPropertyValue() во время CreateChildControls() для получения значений ключа данных, в то время как DataBinder.Eval поддерживает многоуровневое свойство (если оно разделено символом точки)
Пример:
object item = ...
DataBinder.Eval(item, "Address.Id"); //no problem
DataBinder.GetPropertyValue(item, "Address.Id"); //will throw exception
Есть несколько решений для решения вашей проблемы:
- получить ваш пользовательский gridview(переопределить CreateChildControls()), что его datakeynames поддерживают многослойное выражение. Вы можете ссылаться на реализацию по умолчанию, используя Reflector. (много работы)
- сохранить значения комплексного свойства в viewstate во время события 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