contactmatt contactmatt - 2 months ago 44
ASP.NET (C#) Question

ASP.NET two-way bind a nested listview with a variable amount of items

I'm trying to figure out how to two-way databind a ListView. Coming from MVC to a Web Forms application, I'm struggling on how to do so.

I've created a view model structure that represents the nested hiearchy in the SharePoint application. I'm looking to have the two-way binding work against my view model, which I can then transpose into my SharePoint data source:


Line of Business
Solution Line
Product Code (user can "check" if the product code should be applied)



View Model Hierarchy:

public class AddCustomerViewModel
{
public IList<LineOfBusinessViewModel> LinesOfBusiness { get; set; }

public AddCustomerViewModel()
{
LinesOfBusiness = new List<LineOfBusinessViewModel>();
}
}

public class LineOfBusinessViewModel
{
public string Title { get; set; }
public IList<SolutionLineViewModel> SolutionLines { get; set; }

public LineOfBusinessViewModel()
{
SolutionLines = new List<SolutionLineViewModel>();
}
}

public class SolutionLineViewModel
{
public string Title { get; set; }
public IList<ProductCodeViewModel> ProductCodes { get; set; }

public SolutionLineViewModel()
{
ProductCodes = new List<ProductCodeViewModel>();
}
}

public class ProductCodeViewModel
{
public string Title { get; set; }
public bool IsChecked { get; set; }
}


ASPX Page:

<asp:ListView ID="LineOfBusinessListView" ClientIDMode="Static" runat="server" ItemType="ViewModel.AddCustomer.LineOfBusinessViewModel" ItemPlaceholderID="lobPlaceHolderId">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server" ID="lobPlaceHolderId"></asp:PlaceHolder>
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<%# Item.Title %>
<asp:ListView ID="SolutionLinesView" ClientIDMode="Static" runat="server" DataSource="<%# Item.SolutionLines %>" ItemType="ViewModel.AddCustomer.SolutionLineViewModel" ItemPlaceholderID="solutionLinePlaceHolderId">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server" ID="solutionLinePlaceHolderId"></asp:PlaceHolder>
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<%# Item.Title %>
<asp:ListView ID="ProductCodeView" ClientIDMode="Static" runat="server" DataSource="<%# Item.ProductCodes %>" ItemType="ViewModel.AddCustomer.ProductCodeViewModel" ItemPlaceholderID="productCodePlaceHolderId" OnDataBinding="ProductCodeView_DataBinding">
<LayoutTemplate>
<ul>
<asp:PlaceHolder runat="server" ID="productCodePlaceHolderId"></asp:PlaceHolder>
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<%# Item.Title %>
<asp:CheckBox ID="productCode" Checked="<%# BindItem.IsChecked %>" runat="server" />
</li>
</ItemTemplate>
</asp:ListView>
</li>
</ItemTemplate>
</asp:ListView>
</li>
</ItemTemplate>




Code Behind:

protected AddCustomerViewModel AddCustomerViewModel { get; set; }

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
AddCustomerViewModel = new AddCustomerViewModel();

// Construct view model heiarchy...

LineOfBusinessListView.DataSource = AddCustomerViewModel.LinesOfBusiness;
LineOfBusinessListView.DataBind();
}
}


How can I properly two-way bind the view model to the nested ListViews (one-way binding is working), and how can I retrieve these bound values on post-back/form-submission?

Edit:
One awkward thing I noticed, was that in order to use
BindItem
for the checkbox element, I needed to define an ID. However, the items are dynamic, so defining a "static" ID won't do, and I'm unsure how to dynamically set a ID.

ASP.NET Web Forms 4.5, c#

Answer

I could not find a straight forward answer to this. It is possible to parse the Request.form.Allkeys to get the posted name/value pairs, but this gets incredibly hairy, pretty quick.

For our solution, since this was a "green" project, we ended up switching up our server-side network calls to .NET Web API 2, which really simplified binding.