2015-04-22 42 views
16

我有一个ViewModel,它有一个复杂对象作为其成员之一。复杂对象有4个属性(所有字符串)。我试图创建一个可重用的局部视图,我可以传入复杂的对象,并使用html助手为其属性生成html。这一切都很好。但是,当我提交表单时,模型联编程序没有将值映射回ViewModel的成员,所以我没有在服务器端返回任何东西。我如何读取用户输入到复杂对象的html助手中的值。从传递给局部视图的嵌套复杂对象中获取值

视图模型

public class MyViewModel 
{ 
    public string SomeProperty { get; set; } 
    public MyComplexModel ComplexModel { get; set; } 
} 

MyComplexModel

public class MyComplexModel 
{ 
    public int id { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 
    .... 
} 

控制器

public class MyController : Controller 
{ 
    public ActionResult Index() 
    { 
      MyViewModel model = new MyViewModel(); 
      model.ComplexModel = new MyComplexModel(); 
      model.ComplexModel.id = 15; 
      return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
      // model here never has my nested model populated in the partial view 
      return View(model); 
    } 
} 

查看

@using(Html.BeginForm("Index", "MyController", FormMethod.Post)) 
{ 
    .... 
    @Html.Partial("MyPartialView", Model.ComplexModel) 
} 

局部视图

@model my.path.to.namespace.MyComplexModel 
@Html.TextBoxFor(m => m.Name) 
... 

我怎么可以绑定表单提交这个数据,以便父模型包含了从局部视图Web表单中输入的数据?

感谢

编辑:“ComplexModel”我想通了,我需要预先设置在部分视图中的所有控件的名称(文本框),以便它映射到嵌套的对象,但我无法将ViewModel类型传递给部分视图以获取该额外图层,因为它需要是通用的以接受多个ViewModel类型。我可以用javascript重写name属性,但对我来说这似乎过分贫民窟。我还能如何做到这一点?编辑2:我可以静态设置新的名称属性{Name =“ComplexModel.Name”},所以我认为我在做生意,除非有人有更好的方法?

回答

21

可以使用

@Html.Partial("MyPartialView", Model.ComplexModel, 
    new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }}) 

将perpend前缀为您控制name属性,以便<input name="Name" ../>将成为<input name="ComplexModel.Name" ../>并正确绑定到的typeof MyViewModel上回发

通过前缀部分编辑

为了使它更容易一点,你可以封装在一个HTML帮手

public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName) 
{ 
    string name = ExpressionHelper.GetExpressionText(expression); 
    object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model; 
    var viewData = new ViewDataDictionary(helper.ViewData) 
    { 
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = name } 
    }; 
    return helper.Partial(partialViewName, model, viewData); 
} 

,并用它作为

@Html.PartialFor(m => m.ComplexModel, "MyPartialView") 
+0

这看起来很有希望。我已经离开了办公室,但是如果我回来并且将其标记为答案,那么明天就会给我一个机会。谢谢。 –

+0

这是完美的!非常感谢。 –

+0

嘘......我无法赞成它,因为它说我必须拥有15个声望。 +1为你虽然只要我得到15代表:) –

0

您可以尝试将ViewModel传递给partial。

@model my.path.to.namespace.MyViewModel 
@Html.TextBoxFor(m => m.ComplexModel.Name) 

编辑

可以创建示范基地,推动复杂的模型,在那里和基于模型传递到部分。

public class MyViewModel :BaseModel 
{ 
    public string SomeProperty { get; set; } 
} 

public class MyViewModel2 :BaseModel 
{ 
    public string SomeProperty2 { get; set; } 
} 

public class BaseModel 
{ 
    public MyComplexModel ComplexModel { get; set; } 
} 
public class MyComplexModel 
{ 
    public int id { get; set; } 
    public string Name { get; set; } 
    ... 
} 

那么你的部分会像下面:

@model my.path.to.namespace.BaseModel 
@Html.TextBoxFor(m => m.ComplexModel.Name) 

如果这不是一个可接受的解决方案,你可能不得不考虑在覆盖模型绑定的条款。你可以阅读关于here

+0

我不能那样做,因为它需要是通用的。将有几个父视图模型有自己的类型,将需要传入...请参阅我在OP中的第一个编辑。 –

0

我遇到同样的情况,并与这些信息的帖子的帮助是改变了我的部分代码,对由局部视图

产生输入元素生成的前缀

我已经使用Html.partial帮助器给出了ModelType的partialview名称和对象以及带有Html字段前缀的ViewDataDictionary对象的实例,以便构造Html.partial。

这会导致GET请求“主视图”的“xyz url”,并在其中使用带前缀的输入元素生成部分视图。现在名称=“标题”现在在各自的HTML元素中变为名称=“MySubType.Title”,并且对于表单输入元素的其余部分也是如此。

POST请求发送到“xyz url”时,发生问题,期望填入的表单被保存到我的数据库中。但是MVC Modelbinder没有绑定我的POST模型数据和填充的表单值,而且ModelState也丢失了。 viewdata中的模型也是空的。

最后,我尝试使用TryUppdateModel方法更新模型数据,该方法使用先前传递给部分视图的模型实例和html前缀,并且现在可以看到模型与值绑定并且模型状态也存在。

请让我知道这种方法是好还是有点多样化!

相关问题