0

我喜欢将我的视图的一部分分解成多个局部视图,并且我喜欢只传递局部视图感兴趣的模型部分。通常我喜欢将一个专门用于局部视图的模型作为传递到主视图的模型上的属性。

但问题是我认为这会导致 html 帮助程序无法以模型绑定器可以正确将其重新组合在一起的方式呈现,因为它在部分中没有意识到它是另一个对象的属性。

我真的很喜欢这样做,因为它使代码更加有条理,对于经验不足的程序员来说,更难在我的代码中大便,因为一切都已经非常结构化了。到目前为止,这对我来说还不是问题,因为我要么不需要从 partials 获取表单输入,要么它是通过 ajax 调用处理的。这一次我想只使用常规的 DefaultBinder 并且想知道是否有一种方法可以使这项工作而不必将整个模型发送到所有部分视图中?

例子:

主视图中有这行代码:

@{ Html.RenderPartial("_Registrants", Model.Registrants); }

注册人部分如下所示:

@model Models.Order.RegistrantsModel

// stuff...

// important part:
@for(int i = 0; i < Model.Count(); i++)
{
    @Html.HiddenFor(o => o[i].Enabled)
    <ul class="frmRow@(Model[i].Enabled ? "" : " disabled")">
        <li>
            <span class="title">First Name</span>
            @Html.TextBoxFor(o => o[i].FirstName, new { @placeholder = "enter first name" })
            @Html.ValidationMessageFor(o => o[i].FirstName)
        </li>
        <li>
            <span class="title">Last Name</span>
            @Html.TextBoxFor(o => o[i].LastName, new { @placeholder = "enter last name" })
            @Html.ValidationMessageFor(o => o[i].LastName)
        </li>
        <li>
            <span class="title">Email Address</span>
            @Html.TextBoxFor(o => o.First().Email, new { @placeholder = "enter email address" })
            @Html.ValidationMessageFor(o => o[i].Email)
        </li>
    </ul>
}

主要模型如下所示:

public class CourseRegistrationModel
{
    public CourseRegistrationModel() { }

    public CourseRegistrationModel(RegistrationItemModel itemModel, PaymentModel paymentModel)
    {
        Item = itemModel;
        Payor = new PayorModel();
        Registrants = new RegistrantsModel();
        Shipping = new ShippingModel();
        Payment = paymentModel;
    }

    public RegistrationItemModel Item { get; set; }
    public PayorModel Payor { get; set; }
    public RegistrantsModel Registrants { get; set; }
    public ShippingModel Shipping { get; set; }
    public PaymentModel Payment { get; set; }
}

这里是 RegistrantsModel 和 RegistrantModel:

public class RegistrantsModel : IEnumerable<RegistrantModel>
{
    public RegistrantsModel()
    {
        _registrants = new List<RegistrantModel>();

        for(int i = 0; i < 5; i++)
            _registrants.Add(new RegistrantModel());

        _registrants.First().Enabled = true; // Show one registrant on form by default
    }

    List<RegistrantModel> _registrants { get; set; }
    public decimal PricePerPerson { get; set; }
    public int NoOfRegistrants { get; set; }

    public RegistrantModel this[int i]
    {
        get { return _registrants[i]; }
    }

    public IEnumerator<RegistrantModel> GetEnumerator() { return _registrants.GetEnumerator(); }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _registrants.GetEnumerator(); }
}

public class RegistrantModel: IEnabled
{
    [RequiredIfEnabled]
    public string FirstName { get; set; }

    [RequiredIfEnabled]
    public string LastName { get; set; }

    [RequiredIfEnabled]
    [EmailAddress(ErrorMessage = "Please Enter a Valid Email Address")]
    public string Email { get; set; }

    public bool Enabled { get; set; }
}
4

1 回答 1

1

您的部分正在生成具有与例如name集合相关的属性的表单控件RegistrantModel

<input name="[0].FirstName" ... />

这将绑定到带有参数的 POST 方法IList<RegistrantModel>。为了绑定到您的CourseRegistrationModel,您的输入需要是

<input name="Registrants[0].FirstName" ... />

有 2 个选项可以为name属性添加正确的前缀。

一种是通过AdditionalViewDataRenderPartial()方法中传递前缀来添加前缀

@{ Html.RenderPartial("_Registrants", Model.Registrants,
    new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "Registrants" }}); }

另请参阅从传递给局部视图的嵌套复杂对象中获取值,以获取可用于简化视图中代码的扩展方法

首选方法是使用EditorTemplatefor typeof RegistrantModel。您需要将部分命名为与类名相同(在您的情况下RegistrantModel.cshtml)并将其定位在/Views/Shared/EditorTemplates文件夹中(或者/Views/YourControllerName/EditorTemplates如果您想为不同的控制器使用不同的模板)。然后,您的模板将基于模型的单个实例

@model RegistrantModel

@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName, new { @placeholder = "enter first name" })
@Html.ValidationMessageFor(m => m.FirstName)
....

在主视图中,使用

@Html.EditorFor(m => m.Registrants)

EditorFor()方法具有同时接受单个Tand的重载IEnumerable<T>,并且在集合的情况下,这些方法为集合中的每个项目生成正确的 html。

于 2018-01-18T04:01:25.190 回答