Using MVP and ObjectContainerDataSource with complex Objects

Topics: Web Client Software Factory
Feb 14, 2007 at 2:03 PM
I'm trying to wrap my head around using the MVP pattern and the ObjectContainerDataSource to bind my view's controls to complex business entities that have hierarchy within them. All of the Reference Implementation and Quickstart code is dealing with simple, "single record" type data which isn't reflective of real word scenarios.

Here is a VERY Simple Example:

class Order
{
int OrderID;
DateTime OrderDate;
List<OrderDetail> Details;
}
class OrderDetail
{
int OrderID;
int ItemID;
int Quantity;
decimal Price;
}

I want to bind a single Order in a DetailsView control, and I want to nest a Datalist control in a Templated column to bind to the OrderDetails. The DetailsView control will have a button to Update the Order.
I'm using ObjectContainerDataSource control to perform the two-way binding for my DetailsView. Here is a stripped down version of my code for demonstration purposes:

<asp:DetailsView ID="DetailsView1" DataSourceID="dsOrder" DefaultMode="Edit" DataKeyNames="OrderID">
<Fields>
<asp:TemplateField HeaderText="OrderID" Visible="False">
<EditItemTemplate>
<asp:Label ID="Label1" Text='<%# Bind("OrderID") %>'></asp:Label>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Order Date">
<EditItemTemplate>
<asp:Label ID="Label2" Text='<%# Bind("OrderDate") %>'></asp:Label>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Details">
<EditItemTemplate>
<asp:DataList ID="dlDetails" DataSource='<%# Bind("Details") %>' runat="server">
<ItemTemplate>
<asp:Label ID="lblItemID" Text='<%# Bind("ItemID") %>'></asp:Label>
<asp:TextBox ID="txtQuantity" Text='<%# Bind("Quantity") %>'></asp:TextBox>
</ItemTemplate>
</asp:DataList>
</EditItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowCancelButton="False" ShowEditButton="True" UpdateText="Update Quantity" />
</Fields>
</asp:DetailsView>
<pp:ObjectContainerDataSource ID="dsOrder" runat="server" DataObjectTypeName="Order" OnUpdated="dsOrder_Updated" />


The problem is that when the Update button is pressed in my DetailsView, the Details property of my Order object is null. Is there a different way to do the binding that will allow my view code to pass on a single instance of my Order object like this?

protected void dsOrder_Updated(object sender, Microsoft.Practices.Web.UI.WebControls.ObjectContainerDataSourceStatusEventArgs e)
{
_presenter.UpdateOrder((Order)e.Instance);
}



Developer
Feb 16, 2007 at 10:04 PM
Hi,
The ObjectContainerDataSource control uses the data sent by the associated data bound control to create data objects. When dealing with hierarchical data, data bound controls that support two-way data binding don’t send the nested data, they treat objects as ‘flat’ objects. That’s why you get nulls. To see that data sent by data bound controls in its original format and before being processed by the ObjectContainerDataSource control, handle the Updating event of the ObjectContainerDataSource control and check the NewValues collection. This collection contains all the values gathered by the data bound control when you submitted the page.

Having said this, I suggest you to use a different approach for your scenario. For example, you could have the DetailsView display only the first level properties of the Order and use a separate data bound control (not nested), like a GridView, to display/edit the order details.

PS: Please note that the DataList control supports one-way data binding only, so you should not use Bind() within a DataList.

For more information regarding Hierarchical Data Binding in ASP.NET, see:
http://msdn2.microsoft.com/en-us/library/aa478959.aspx

Cheers,
Mariano Szklanny
http://staff.southworks.net/mariano
Feb 17, 2007 at 12:18 AM
Hi,

Thanks for the response. First...I didn't know that the Datalist only supported one-way binding. Thanks for the heads up.

The example I posted was a "dumbed down" version of my real scenerio. I have multiple levels of hierarchy, so each item in my DataList(will change to a GridView for two-way binding) will have another level beneath it and so on. I don't think I can represent it by moving the "nested" controls to be outside of the containing control.

For the sake of the discussion though, lets say I only had two levels and that I take your advice and not nest the decendant controls. My View would have a property that accepted my rich Hierachical object. I could set the ObjectContainerDataSource for my DetailsView control using the object itself(only binding my top-level properties), and set the second ObjectContainerDataSource control DataSource to be Object.ChildProperty. I get that.

My question would be, how would I be able to react to one button click's event(presumably a CommandField button in the Details view) to reassemble my complex object from two different ObjectContainerDataSource controls and pass them back in a single call back to my presenter for processing?

This is the crux of the problem, right?

I can't imagine that people that are going to go through the trouble of implementing MVP pattern, and all the other nice aspects of the Web Client Software Factory are going to be dealing with only flat, single-level objects.

I really do appreciate you taking the time to respond.

Nate

Jan 1, 2008 at 6:18 AM
I have similar set of problems. I have a complex object(hierarchical) which i am displaying across various controls inside another master control(as a tabbed view). I want to use my service to retrieve the data and set in a ObjectContainerDataSource in the master control(which has 3 controls) and then bind various set of controls to the properties. Is this achievable?

To begin with am not really worried for 2-way data binding. As data will be read-only in all the controls except for the first one. I would also like to know how to achieve pageflow in the same. Thats another huge hurdle for me.

Thanks in advance.
Wali.




icnatejackson wrote:
Hi,

Thanks for the response. First...I didn't know that the Datalist only supported one-way binding. Thanks for the heads up.

The example I posted was a "dumbed down" version of my real scenerio. I have multiple levels of hierarchy, so each item in my DataList(will change to a GridView for two-way binding) will have another level beneath it and so on. I don't think I can represent it by moving the "nested" controls to be outside of the containing control.

For the sake of the discussion though, lets say I only had two levels and that I take your advice and not nest the decendant controls. My View would have a property that accepted my rich Hierachical object. I could set the ObjectContainerDataSource for my DetailsView control using the object itself(only binding my top-level properties), and set the second ObjectContainerDataSource control DataSource to be Object.ChildProperty. I get that.

My question would be, how would I be able to react to one button click's event(presumably a CommandField button in the Details view) to reassemble my complex object from two different ObjectContainerDataSource controls and pass them back in a single call back to my presenter for processing?

This is the crux of the problem, right?

I can't imagine that people that are going to go through the trouble of implementing MVP pattern, and all the other nice aspects of the Web Client Software Factory are going to be dealing with only flat, single-level objects.

I really do appreciate you taking the time to respond.

Nate



Jan 16, 2008 at 2:55 PM
Edited Jan 16, 2008 at 7:23 PM
Hi all,

I also have the similar problem with the ObjectContainerDataSource. My data class structure is as follows:

Interface IDocument
{
}

class SimpleDocument : IDocument
{
}

class ComplexDocument: IDocument
{
}

When I set the ObjectDataSourceDataType to IDocument and try to load both SimpleDocument and ComplexDocument, the operation fails.
The error message explains that the ObjectContainerDataSource was expected an IDocument instead of a SimpleDocument or ComplexDocument.

Therefore, how can I use the ObjectContainerDataSource with related Objects?

Thank you

Bob


PS As an additional note: I tried using an abstract class instead of a interface and the same error occurred.

PSS Solved problem or I should say this issue solved it.

http://www.codeplex.com/websf/WorkItem/View.aspx?WorkItemId=12490

Thanks guys

Bob
Jul 31, 2008 at 7:13 AM
Hi folks.

Sorry for bringing up this old post, but I would need to know if someone has solved that issue, and has some sample code for data bind complex objects to a DetailsView control

Thanks in advance.

Sergio.
Aug 6, 2008 at 2:49 PM
Somewhat theoretical question/comment to original poster's language.

Does binding have anything to do with the MVP pattern and this framework?

My understanding is that the MVP and this framework implementation are aimed at aiding decoupling of UI layer from your model. The MVP pattern does not depend on how you implement your UI layer.

We chose to let our developers use whatever they feel most comfortable during UI development, as long as MVP principles are enforced.