ASP.NET Web Forms 4.5 模型绑定,其中模型包含一个集合 [英] ASP.NET Web Forms 4.5 model binding where the model contains a collection

查看:38
本文介绍了ASP.NET Web Forms 4.5 模型绑定,其中模型包含一个集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试更新旧的 Web 窗体应用程序以使用 4.5 中添加的新模型绑定功能,类似于 MVC 绑定功能.

我在制作一个可编辑的 FormView 时遇到了问题,该 FormView 呈现单个模型,该模型包含简单的成员以及作为其他模型集合的成员.我需要用户能够编辑父对象的简单属性和子集合的属性.

问题在于,当代码尝试更新模型时,子集合 (ProductChoice.Extras) 在模型绑定后始终为 null.

这是我的模型:

[可序列化]公共类产品选择{公共产品选择(){Extras = new List();}公共整数数量{得到;放;}公共 int ProductId { 获取;放;}公共列表额外的{得到;放;}}[可序列化]公共类 ProductChoiceExtra{公共 int ExtraProductId { 获取;放;}公共字符串 ExtraName { 获取;放;}公共 int ExtraQuantity { 获取;放;}}

还有我的用户控制代码:

public 部分类 ProductDetails : System.Web.UI.UserControl{私人 Models.ProductChoice _productChoice;protected void Page_Load(object sender, EventArgs e){_productChoice = new Models.ProductChoice(){数量 = 1,产品 ID = 1};_productChoice.Extras.Add(new Models.ProductChoiceExtra(){ExtraProductId = 101,ExtraName = "可乐",额外数量 = 1});_productChoice.Extras.Add(new Models.ProductChoiceExtra(){ExtraProductId = 104,ExtraName = "精灵",额外数量 = 2});}公共 Models.ProductChoice GetProduct(){返回_productChoice;}public void UpdateProduct(Models.ProductChoice 模型){/* model.Extras 在这里始终为空,它应该包含两个 ProductChoiceExtra 对象 */if (TryUpdateModel(_productChoice) == true){}}}

我的控件标记:

<asp:FormView runat="server" ID="fvProductSelection" DefaultMode="编辑"ItemType="Models.ProductChoice"选择方法=获取产品"UpdateMethod="UpdateProduct" ><EditItemTemplate><asp:linkbutton id="UpdateButton" text="Update" commandname="Update" runat="server"/><asp:HiddenField runat="server" ID="ProductId" Value="<%# BindItem.ProductId %>"/><asp:TextBox Text="<%# BindItem.Quantity %>"ID="数量" runat="服务器"/><asp:Repeater ID="Extras" ItemType="Models.ProductChoiceExtra" DataSource="<%# BindItem.Extras %>"runat="服务器"><项目模板><asp:HiddenField Value="<%# BindItem.ExtraProductId %>"ID="ExtraProductId" runat="服务器"/><asp:Label Text="<%# BindItem.ExtraName %>"ID="名称" runat="服务器"/><asp:TextBox Text="<%# BindItem.ExtraQuantity %>"ID="数量" runat="服务器"/></ItemTemplate></asp:中继器></EditItemTemplate></asp:FormView>

我尝试将 Extras 属性设为 BindingList 而不是 List 但它没有任何区别,UpdateProduct 方法中未绑定 Extras 集合.

解决方案

深入 System.Web.ModelBinding 揭示了 CollectionModelBinder 期望传递给 FormValueProvider 的值将采用与 MVC 相同的格式,即是:MyCollection[i]

public static string CreateIndexModelName(string parentName, string index){if (parentName.Length != 0){return (parentName + "[" + index + "]");}return ("[" + 索引 + "]");}

不幸的是,您的中继器的元素名称不符合该条件.

虽然肯定是非正统的,但您仍然可以通过编写非服务器文本框来实现这一点,然后为它们命名,以您的数据列表命名容器开头,后跟索引.多亏了Request.Unvalidated"(也在 4.5 中引入),您可以将数据绑定到这些数据,即使它没有由服务器端控件表示.

I'm trying to update an old Web Forms application to use the new model binding features added in 4.5, similar to the MVC binding features.

I'm having trouble making an editable FormView that presents a single model that contains simple members plus a member that is a collection of other models. I need the user to be able to edit the simple properties of the parent object and the properties of the child collection.

The problem is that the child collection (ProductChoice.Extras) is always null after model binding when the code is trying to update the model.

Here are my models:

[Serializable]
public class ProductChoice
{
    public ProductChoice()
    {
        Extras = new List<ProductChoiceExtra>();
    }

    public int Quantity { get; set; }
    public int ProductId { get; set; }
    public List<ProductChoiceExtra> Extras { get; set; }
}

[Serializable]
public class ProductChoiceExtra
{
    public int ExtraProductId { get; set; }
    public string ExtraName { get; set; }
    public int ExtraQuantity { get; set; }
}

And my user control code behind:

public partial class ProductDetails : System.Web.UI.UserControl
{
    private Models.ProductChoice _productChoice;

    protected void Page_Load(object sender, EventArgs e)
    {
        _productChoice = new Models.ProductChoice()
        {
            Quantity = 1,
            ProductId = 1
        };
        _productChoice.Extras.Add(new Models.ProductChoiceExtra()
        {
            ExtraProductId = 101,
            ExtraName = "coke",
            ExtraQuantity = 1
        });
        _productChoice.Extras.Add(new Models.ProductChoiceExtra()
        {
            ExtraProductId = 104,
            ExtraName = "sprite",
            ExtraQuantity = 2
        });

    }

    public Models.ProductChoice GetProduct()
    {
        return _productChoice;
    }

    public void UpdateProduct(Models.ProductChoice model)
    {
        /* model.Extras is always null here, it should contain two ProductChoiceExtra objects */

        if (TryUpdateModel(_productChoice) == true)
        {
        }
    }
}

My control markup:

<div id="selectOptions">
    <asp:FormView runat="server" ID="fvProductSelection" DefaultMode="Edit"
        ItemType="Models.ProductChoice"
        SelectMethod="GetProduct"
        UpdateMethod="UpdateProduct" >

        <EditItemTemplate>
            <asp:linkbutton id="UpdateButton" text="Update" commandname="Update" runat="server"/>
            <asp:HiddenField runat="server" ID="ProductId" Value="<%# BindItem.ProductId %>" />
            <asp:TextBox Text ="<%# BindItem.Quantity %>" ID="Quantity" runat="server" />

            <asp:Repeater ID="Extras" ItemType="Models.ProductChoiceExtra" DataSource="<%# BindItem.Extras %>" runat="server">
                <ItemTemplate>
                    <asp:HiddenField Value="<%# BindItem.ExtraProductId %>" ID="ExtraProductId" runat="server"  />
                    <asp:Label Text="<%# BindItem.ExtraName %>" ID="Name" runat="server" />
                    <asp:TextBox Text="<%# BindItem.ExtraQuantity %>" ID="Quantity"  runat="server" />
                </ItemTemplate>
            </asp:Repeater>
        </EditItemTemplate>
    </asp:FormView>
</div>

I have tried making the Extras property a BindingList rather than a List but it didn't make any difference, the Extras collection isn't bound in the UpdateProduct method.

解决方案

Digging into System.Web.ModelBinding reveals that the CollectionModelBinder expects that values passed in to the FormValueProvider would be in the same format as they would be for MVC, that is: MyCollection[i]

public static string CreateIndexModelName(string parentName, string index)
{
    if (parentName.Length != 0)
    {
        return (parentName + "[" + index + "]");
    }
    return ("[" + index + "]");
}

Unfortunately, your repeater's element names will not match that criteria.

While certainly unorthodox, you could still achieve this by writing non-server textboxes, and then giving them a name starting with your datalist naming container, followed by the index. And thanks to "Request.Unvalidated" (also introduced in 4.5), you have the ability to databind to this data even though it's not represented by server-side controls.

这篇关于ASP.NET Web Forms 4.5 模型绑定,其中模型包含一个集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆