使用Razor、ASP.NET MVC 3和.NET 4.0创建主从关系视图

6

我完全不懂.NET,请耐心一点,如果我犯了什么傻瓜错误,请您见谅。

我正在使用ASP.NET MVC 3和.NET 4.0

我想为一个有子模型的模型创建一个"创建"视图。这个视图应该包含子模型的部分"创建"视图。以下是一个简单的例子用于说明:

  • The Person model

    class Person
    {
        public string Name { get; set; }
        public Address { get; set; }
    }
    
  • The Address model

    class Address
    {
        public string City { get; set; }
        public string Zip { get; set; }
    
        //A List for creating a <select/> item in the view
        //containing cities fetched from the database.
        //The initialization is done in the controller action returning
        //the related partial view.
        public IEnumerable<SelectListItem> CityDropDown { get; set; } )
    }
    
  • The Controller Actions

        class MyController : Controller
        {
            public ViewResult Create()
            {
                var person = new Person();
                var address = new Address();
                // initialization of address.CityDropDown omitted
                person.Address = address;
                return View(MyViews.CreatePersonView, person);
            }
    
            [HttpPost]
            public ViewResult Create(Person person)
            {
                //persistance logic
            }
        }
    
  • The views hierarchy I want to have :

创建视图层次结构的人

我尝试过以下方法来实现此目标:

第一种方法:使用@Html.Partial(..)@{Html.RenderPartial(..)}


我的做法:

  • The Person view

    @model Person
    @using(Html.BeginForm()){
        @Html.EditorFor(m=>m.Name)
        @Html.Partial(MyViews.AddressPartialView, @Model.Address)
    }
    
  • The Address partial view

    @model Address
    @Html.EditorFor(m=>m.Zip)
    @Html.DropDownListFor(m=>m.City, @Model.CityDropDown)
    

问题:

提交表单时,person.Address为空。在谷歌上进行了一番搜索后,我发现为了使地址字段提交工作正常,生成的HTML标记必须如下所示(请注意前缀为Address_):

<form...>
    <input type=text id="Name" />
    <input type=text id="Address_Zip" />
    <select id="Address_City">
        <!-- options... -->
    </select>
</form>

不用说,在我的情况下生成的HTML标记不同,而是如下所示(缺少Address_前缀):

<form...>
    <input type=text id="Name" />
    <input type=text id="Zip" />
    <select id="City">
        <!-- options... -->
    </select>
</form>

第二种方法:使用Address模型的EditorTemplate


我所做的:

  • I moved the Address partial view to the folder View/Shared/EditorTemplates assuring that it has the same name as the Address property in the Person model, i.e Address.cshtml.

  • The Person view

    @model Person
    @using(Html.BeginForm()){
        @Html.EditorFor(m=>m.Name)
        @Html.EditorFor(@Model.Address) //will automatically find the Address 
                                 //partial view in the EditorTemplates folder
    }
    

问题:

使用这种方法生成的标记实际上具有正确的前缀(即 Address_ ),但是对于 Address.CityDropDown 属性,我得到一个“对象引用未设置为对象实例异常”,这告诉我在控制器操作中预初始化的 Address 对象由于某种原因没有传递到部分视图。

第三种方法:将所有地址字段放在 Person 模型中


这种方法没有任何问题,但是我不想使用它,因为如果我将来想要在另一个模型中拥有创建视图,则会产生冗余代码。

总结


我该怎么做才能拥有一个可重复使用的部分创建视图,可以在我的整个应用程序中使用?

1个回答

3
你对 EditorTemplates 的方法是正确的,但请记住你需要填充 CityDropDown。 因此,视图应该被传递如下:
Person model = new Person()
{
    Address = new Address
    {
        CityDropDown = new SelectListItem[]{
            new SelectListItem { Selected = true, Text = "Select one..." },
            new SelectListItem { Text = "Anywhere", Value = "Anywhere" },
            new SelectListItem { Text = "Somewhere", Value = "Somewhere" },
            new SelectListItem { Text = "Nowhere", Value = "Nowhere" }
        }
    }
};

那么,这个视图将只包含:
@Html.EditorForModel()

然后你的EditorTemplates将从这里开始:

~/Views/shared/EditorTemplates/Address.cshtml(注意:这是基于类型而不是属性名称)

@model MvcApplication.Models.Address
@Html.DropDownListFor(x => x.City, Model.CityDropDown)
@Html.EditorFor(x => x.Zip)

~/Views/Shared/EditorTemplates/Person.cshtml

@model MvcApplication.Models.Person
@using (Html.BeginForm())
{ 
    @Html.EditorFor(x => x.Name)
    @Html.EditorFor(x => x.Address)
    <input type="submit" value="Save" />
}

这三个视图会呈现出类似于以下的内容:
<form action="/" method="post">
  <input class="text-box single-line" id="Name" name="Name" type="text" value="" />
  <select id="Address_City" name="Address.City">
    <option selected="selected">Select one...</option>
    <option value="Anywhere">Anywhere</option>
    <option value="Somewhere">Somewhere</option>
    <option value="Nowhere">Nowhere</option>
  </select>
  <input class="text-box single-line" id="Address_Zip" name="Address.Zip" type="text" value="" />
  <input type="submit" value="Save" />

这里可以找到示例项目:https://github.com/bchristie/StackOverflow-Examples/tree/master/questions-19247958

非常感谢您创建整个项目作为答案,这非常慷慨。在我的情况下,我确实按照应该的方式填充了CityDropDown。奇怪的是,在调试时,我可以看到Model.Address已经正确初始化并且CityDropDown已经填充,但是当光标移到部分视图时,Model为空。这在您创建的项目中没有发生,只有在我的项目中出现了这种情况。 - snajahi
@K-SaMa:你在你的EditorTemplate(针对Address)中提供了@model指令吗? - Brad Christie
当然,我现在真的不知道问题到底是什么。 - snajahi
@K-SaMa:一定有某个配置选项。如果它在普通的MVC上运行正常,那么在你的项目中肯定是某些配置错误或未提供的东西。 - Brad Christie
@K-SaMa:如果你经常遇到这种情况,请在进行诊断之前清理解决方案(右键单击并选择“清理”)。很多时候,这可能是由于库引用不匹配或缓存依赖关系所致。 - Brad Christie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接