首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在MVC2强类型HTML Helpers中使用ViewModel模式

在MVC2强类型HTML Helpers中使用ViewModel模式
EN

Stack Overflow用户
提问于 2010-01-29 13:53:25
回答 5查看 6.1K关注 0票数 18

我正在使用ASP.NET MVC2 RC,但不知道如何让TextBoxforViewModel pattern一起工作。在编辑页面上使用时,在控制器中调用UpdateModel()时不会保存数据。我从NerdDinner应用程序中选取了以下代码示例。

Edit.aspx

<%@ Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.DinnerFormViewModel>" %>
...
<p>
    // This works when saving in controller (MVC 1)
    <label for="Title">Dinner Title:</label>
    <%= Html.TextBox("Title", Model.Dinner.Title) %>
    <%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
    // This does not work when saving in the controller (MVC 2)
    <label for="Title">Dinner Title:</label>
    <%= Html.TextBoxFor(model => model.Dinner.Title) %>
    <%= Html.ValidationMessageFor(model=> model.Dinner.Title) %>
</p>

DinnerController

// POST: /Dinners/Edit/5

[HttpPost, Authorize]
public ActionResult Edit(int id, FormCollection collection) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (!dinner.IsHostedBy(User.Identity.Name))
        return View("InvalidOwner");

    try {
        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch {
        ModelState.AddModelErrors(dinner.GetRuleViolations());

        return View(new DinnerFormViewModel(dinner));
    }
}

当使用原始帮助器样式(Http.TextBox)时,UpdateModel(晚餐)调用将按预期工作,并保存新值。

当使用新的(MVC2)帮助器样式(Http.TextBoxFor)时,UpdateModel(晚餐)调用不会更新值。是,当前值在加载时加载到编辑页面中。

还有什么需要添加到控制器代码中才能正常工作吗?如果我只是使用模型而不是ViewModel模式,那么新的helper工作得很好。

谢谢。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-02-01 02:20:24

这里的问题是,您的Edit form对DinnerFormViewModel类型使用了强类型的helper,但您在晚餐类型上调用了UpdateModel。

当您对类型使用强类型帮助器时,帮助器会创建表单字段,假设这就是您要发布的类型。当类型不匹配时,就有问题了。

然而,这很容易修复。您可以为UpdateModel提供一个前缀,表明您不是在试图编辑整个模型,而是在尝试编辑模型的一个属性,在本例中是一个晚餐。

UpdateModel(dinner, "Dinner");

另一种方法是在实际的ViewModel上调用UpdateModel。

var viewModel = new DinnerFormViewModel();
viewModel.Dinner = repository.GetDinner(id);
UpdateModel(viewModel);

我认为第一种方法要好得多。

票数 19
EN

Stack Overflow用户

发布于 2010-11-27 22:28:20

"Wrox专业版MVC 2"一书的第90页上,代码如下所示:

if (TryUpdateModel(dinner)) {
     dinnerRepository.Save();

     redirectToAction("Details", new { id=dinner.DinnerID });

但它应该是:

if (TryUpdateModel(dinner, "Dinner")) {
     dinnerRepository.Save();

     redirectToAction("Details", new { id=dinner.DinnerID });

此方法重载将尝试使用控制器的值提供程序中的值来更新指定的模型晚餐,而不是默认的ViewModel。基本上,它所做的就是在提供程序中查找所有值时为它们添加一个前缀。

因此,当模型更新它的Title属性时,它将查找Dinner.Title,而不仅仅是控制器的值提供者中的Title。

在调试时,查看Edit ActionResult方法并检查FormCollection输入参数。当您深入研究它的条目数组时,您将发现所有键都以您在视图中引用的属性对象的前缀开头,在本例中为Edit View,如下所示:

<%: Html.TextBoxFor(model => model.Dinner.Title, new {size=50, @class="prettyForm" })%>
票数 2
EN

Stack Overflow用户

发布于 2010-01-29 18:05:38

我不是100%确定,但似乎强类型的帮助器创建的ids/名称是"Dinner.Title“而不仅仅是"Title”,因此- UpdateModel不能绑定它。

不幸的是,我自己没有使用过UpdateModel方法,所以我不知道解决方案。

你能添加为这两种方法呈现的html吗?

玩着自动取款机的反射器。

这是我发现的:

protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel: class
{
    if (model == null)
    {
        throw new ArgumentNullException("model");
    }
    if (valueProvider == null)
    {
        throw new ArgumentNullException("valueProvider");
    }
    Predicate<string> predicate = delegate (string propertyName) {
        return BindAttribute.IsPropertyAllowed(propertyName, base.includeProperties, base.excludeProperties);
    };
    IModelBinder binder = this.Binders.GetBinder(typeof(TModel));
    ModelBindingContext context2 = new ModelBindingContext();
    context2.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(delegate {
        return base.model;
    }, typeof(TModel));
    context2.ModelName = prefix;
    context2.ModelState = this.ModelState;
    context2.PropertyFilter = predicate;
    context2.ValueProvider = valueProvider;
    ModelBindingContext bindingContext = context2;
    binder.BindModel(base.ControllerContext, bindingContext);
    return this.ModelState.IsValid;
}

前缀要更新的模型实例。在值provider.中查找值时要使用的前缀

因此,您可以尝试使用UpdateModel<T>(T model, string prefix)重载并传递“晚餐”或“晚餐”。作为前缀参数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2160171

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档