ASP.NET Web Forms (4.5) Strongly Typed Model Binding - DropDownList in InsertItemTemplate of ListView
Asked Answered
T

1

8

Note: This is ASP.NET Web Forms Model Binding in .NET 4.5 and NOT MVC.

I am using the new Strongly Typed Model Binding features of ASP.NET Web Forms (4.5) to produce a list of items that can be edited. This is working fine for viewing the initial list, editing an item and deleting an item. I am however having a problem with the insertion of a new item.

Specifically, within my EditItemTemplate and InsertItemTemplate I have a DropDownList (well, actually it is a custom control derived from DropDownList but for the purposes of this question it is a DropDownList). The control is defined within the markup as follows...

<agp:ClientStatusDropDownList ID="ClientStatusID" runat="server"
SelectedValue="<%#: BindItem.ClientStatusID %>" />

Within the EditItemTemplate, this is fine however within the InsertItemTemplate this generates an error upon running the page: Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.

As such, I removed the section SelectedValue="<%#: BindItem.ClientStatusID %>" from the InsertItemTemplate and tried again. This time no error message, however when the ListView.InsertMethod is called, the ClientStatusID property on the model is not set to the value of the DropDownList (whereas the rest of the properties are set correctly).

The ListView.InsertMethod:

public void ListView_InsertMethod(int ID) {

  Model model = this.DbContext.Models.Create();
  if (this.TryUpdateModel(model)) {
    this.DbContext.SaveChanges();
    this.ListView.DataBind();
  }

}

The Model class:

public class Model{

  public Int32 ID { get; set; }
  public String Description { get; set; }
  public Boolean IsScheduleFollowUp { get; set; }
  public Nullable<Int32> ClientStatusID { get; set; }

}

The EditItemTemplate:

<EditItemTemplate>
  <tr>
    <td>
      <asp:TextBox ID="Description" runat="server" Text="<%#: BindItem.Description %>" />
    </td>
    <td>
      <asp:CheckBox ID="IsScheduleFollowUp" runat="server" Checked="<%# BindItem.IsScheduleFollowUp %>" />
    </td>
    <td>
      <agp:ClientStatusDropDownList ID="ClientStatusID" runat="server" SelectedValue="<%#: BindItem.ClientStatusID %>" />
    </td>
    <td>
      <asp:Button ID="Update" runat="server" ClientIDMode="Static" CommandName="Update" Text="Update" />
      <asp:Button ID="Cancel" runat="server" ClientIDMode="Static" CommandName="Cancel" Text="Cancel" />
    </td>
  </tr>
</EditItemTemplate>

The InsertItemTemplate:

<InsertItemTemplate>
  <tr>
    <td>
      <asp:TextBox ID="Description" runat="server" Text="<%#: BindItem.Description %>" />
    </td>
    <td>
      <asp:CheckBox ID="IsScheduleFollowUp" runat="server" Checked="<%# BindItem.IsScheduleFollowUp %>" />
    </td>
    <td>
      <agp:ClientStatusDropDownList ID="ClientStatusID" runat="server" />
    </td>
    <td>
      <asp:Button ID="Insert" runat="server" ClientIDMode="Static" CommandName="Insert" Text="Add" />
    </td>
  </tr>
</InsertItemTemplate>

I had originally thought that it was the ID of the control that was used to determine the property on the model that the value would be passed to (i.e. where the TextBox was called "Description", the value would be passed to the "Description" property of the model). Clearly this is not the case and it is instead controlled by the "<%# BindItem.Description %>", however as you can see from the rest of this question I am unable to use this syntax in the "InsertItemTemplate". I cannot believe that the DropDownList is not supported in this scenario, but I cannot find any examples of a DropDownList being used with the 4.5 model bindings using Google or Bing (in fact, there are very few examples of the new model binding in ASP.NET 4.5 using anything other than a couple of TextBox controls).

Can anybody shed any further light on the issue (and preferably tell me what needs to be done)?

Other questions on SO that I have looked at...

All of these use the older style binding methods and not the new methods in 4.5

Thanks.

Tried answered 18/2, 2013 at 10:9 Comment(1)
Just for reference; I have also tried binding to an alternate model where the ClientStatusID is not nullable (this is the code-behind, not the markup). No difference, the property is still not set. This (in my mind) rules out any potential issues in the property being nullable.Tried
N
6

I've been working on something similar and have been able to get a sample to work, so I figured I would post what I have and see if this helps you.

Here is my page code:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="listview-databind.aspx.cs"
    Inherits="test_listview_databind" Debug="true" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ListView ID="lv" runat="server" ItemType="DataModel" DataKeyNames="Id" SelectMethod="lv_GetData"
            InsertItemPosition="FirstItem" InsertMethod="lv_InsertItem" UpdateMethod="lv_UpdateItem">
            <LayoutTemplate>
                <table>
                    <tr id="itemPlaceholder" runat="server"></tr>
                </table>
            </LayoutTemplate>
            <ItemTemplate>
                <tr>
                    <td>
                        <asp:Literal ID="Description" runat="server" Text="<%# Item.Description %>" />
                    </td>
                    <td>
                        <asp:CheckBox ID="IsScheduleFollowUp" runat="server" Checked="<%# Item.IsScheduleFollowUp %>" />
                    </td>
                    <td>
                        <asp:Literal ID="ClientStatusId" runat="server" />
                    </td>
                    <td>
                        <asp:Button ID="Edit" runat="server" ClientIDMode="Static" CommandName="Edit"
                            Text="Edit" />
                    </td>
                </tr>
            </ItemTemplate>
            <InsertItemTemplate>
                <tr>
                    <td>
                        <asp:TextBox ID="Description" runat="server" Text="<%# BindItem.Description %>" />
                    </td>
                    <td>
                        <asp:CheckBox ID="IsScheduleFollowUp" runat="server" Checked="<%# BindItem.IsScheduleFollowUp %>" />
                    </td>
                    <td>
                        <asp:DropDownList ID="ClientStatusId" runat="server" SelectedValue="<%# BindItem.ClientStatusId %>">
                            <asp:ListItem>1</asp:ListItem>
                            <asp:ListItem>2</asp:ListItem>
                        </asp:DropDownList>
                    </td>
                    <td>
                        <asp:Button ID="Insert" runat="server" ClientIDMode="Static" CommandName="Insert"
                            Text="Add" />
                        <asp:Button ID="Cancel" runat="server" ClientIDMode="Static" CommandName="Cancel"
                            Text="Cancel" />
                    </td>
                </tr>
            </InsertItemTemplate>
            <EditItemTemplate>
                <tr>
                    <td>
                        <asp:TextBox ID="Description" runat="server" Text="<%# BindItem.Description %>" />
                    </td>
                    <td>
                        <asp:CheckBox ID="IsScheduleFollowUp" runat="server" Checked="<%# BindItem.IsScheduleFollowUp %>" />
                    </td>
                    <td>
                        <asp:DropDownList ID="ClientStatusId" runat="server" SelectedValue="<%# BindItem.ClientStatusId %>">
                            <asp:ListItem>1</asp:ListItem>
                            <asp:ListItem>2</asp:ListItem>
                        </asp:DropDownList>
                    </td>
                    <td>
                        <asp:Button ID="Update" runat="server" ClientIDMode="Static" CommandName="Update"
                            Text="Update" />
                        <asp:Button ID="Cancel" runat="server" ClientIDMode="Static" CommandName="Cancel"
                            Text="Cancel" />
                    </td>
                </tr>
            </EditItemTemplate>
        </asp:ListView>
    </form>
</body>
</html>

And my code behind:

using System.Collections.Generic;
using System.Linq;

public partial class test_listview_databind : System.Web.UI.Page
{
    public IQueryable<DataModel> lv_GetData()
    {
        var l = new List<DataModel>();
        l.Add(new DataModel() { Id = 1, Description = "Test 1", IsScheduleFollowUp = true, ClientStatusId = 1 });
        l.Add(new DataModel() { Id = 2, Description = "Test 2", IsScheduleFollowUp = false, ClientStatusId = 2 });
        return l.AsQueryable();
    }

    public void lv_InsertItem()
    {
        var item = new DataModel();
        TryUpdateModel(item);
        if (ModelState.IsValid)
        {
            Response.Write(item.ClientStatusId);
        }
    }
}

You didn't post your entire ListView sample, so I am taking a guess as to how you might have it set up. Please let me know if this helps and if/how this works for you, as your code looks workable and I'm curious as to what is causing your problem.

Narra answered 24/2, 2013 at 18:24 Comment(2)
Interesting; I was unable to use the BindItem syntax in my InsertItemTemplate yet you could. This made me think and revisit my implementation of the ClientStatusDropDownList where I found the problem - I was calling DataBind during OnLoad (where !PostBack) and this is why the binding context for the BindItem was invalid. Removing the DataBind call has resolved the problem. Though you did not provide the answer (as I had not provided enough first), you have helped me solve it so I am marking you as correct.Tried
Just for the record: ClientStatusDropDownList is an implementation of a DropDownList with the binding hard coded (derived from DropDownList) so that I could simply drop one on the page and not have to worry about the wiring.Tried

© 2022 - 2024 — McMap. All rights reserved.