下载mvc3编辑表单

时间:2011-01-28 01:25:18

标签: c# asp.net-mvc-3 razor html-helper

这可能很简单,但我似乎无法自己解决这个问题。 我创建了一个简单的数据库和实体模式,看起来像这样

enter image description here

我正在尝试创建一个允许我添加新订单的创建表单。我总共有3个表,所以我想要的是允许此人输入订单日期的表单,还有一个下拉列表,允许我从产品表中选择产品

我希望能够创建一个Add或Edit视图,允许我将OrderDate插入OrderTable,并将OrderID和选定的ProductID插入OrderProduct。

我需要在这做什么步骤。

我创建了一个OrderController并勾选了“添加操作”,然后添加了一个看起来像这样的创建视图

@model Test.OrderProduct

@{
    ViewBag.Title = "Create2";
}

    <h2>Create2</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>OrderProduct</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.OrderID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.OrderID)
            @Html.ValidationMessageFor(model => model.OrderID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ProductID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ProductID)
            @Html.ValidationMessageFor(model => model.ProductID)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

这将创建包含OrderID和ProductID文本框的视图,但不包含日期。

我的控制器CreatePost尚未更改

  [HttpPost]
    public ActionResult Create(FormCollection collection)
    {
        try
        {
            var data = collection;
            // TODO: Add insert logic here
          //  db.Orders.AddObject(collection);
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

我的问题是,

1.如何将ProductID文本框换成从Product填充的下拉列表 2.如何从FormCollection集合中获取数据?我只想到了一个foreach,但我不知道如何获得强类型名称

对新手的任何帮助都会非常有帮助。

谢谢!

3 个答案:

答案 0 :(得分:25)

首先,不要绑定到订单实体。永远不要绑定到EF对象,总是尝试使用 ViewModel 。使View的生活更简单,这就是目标。

所以,有一个像这样的ViewModel:

public class CreateOrderViewModel
{
   public int OrderId { get; set; }
   public DateTime OrderDate { get; set; }
   public int SelectedProductId { get; set; }
   public IEnumerable<SelectListItem> Products { get; set; }
}

现在就是这样。

[HttpGet]控制器操作中将其返回到您的视图:

[HttpGet]
public ActionResult Create()
{
   var model = new CreateOrderViewModel
   {
      Products = db.Products
                   .ToList() // this will fire a query, basically SELECT * FROM Products
                   .Select(x => new SelectListItem
                    {
                       Text = x.ProductName,
                       Value = x.ProductId
                    });
   };

   return View(model);
}

然后渲染出产品列表:(不包括基本HTML)

@model WebApplication.Models.CreateOrderViewModel

@Html.DropDownListFor(model => model.SelectedProductId, Model.Products)

我唯一不知道该怎么做的是绑定到DateTime字段。我猜你需要一个扩展方法(HTML Helper),它会渲染一个日期选择器或其他东西。对于此视图(创建新订单),只需默认为DateTime.Now

现在,进入[HttpPost]控制器操作:

[HttpPost]
public ActionResult Create(CreateOrderViewModel model)
{
   try
   {
      // TODO: this manual stitching should be replaced with AutoMapper
      var newOrder = new Order
      {
         OrderDate = DateTime.Now,
         OrderProduct = new OrderProduct
         {
            ProductId = SelectedProductId
         }
      };

      db.Orders.AddObject(newOrder);
      return RedirectToAction("Index");
   }
   catch
   {
      return View();
   }
}

现在,我也认为您的EF模型需要工作。

对我来说(以英语说),产品可以有很多订单,而订单可以有很多产品。

所以,它应该是多对多的。目前,这是一个带有冗余连接表的1-1。你是从DB生成的吗?如果是这样,您的DB可能需要工作。

您应该在订单实体上拥有一个名为产品的导航属性,该属性引用产品的集合,通过静默连接实现到多对多的连接表。

这也意味着你不再拥有DropDownList,而是MultiSelectDropDownList。

答案 1 :(得分:2)

谢谢克雷格。你在MVC的几天(截至发布时)已经解决了我几天试图从DropDownListFor获取所选值的问题。

我在创建视图中获取DDLF的选定值没有问题,但编辑视图是完全不同的事情 - 我尝试的任何内容都不会在Post中获得所选值。我注意到所选的值潜伏在ModelState的AttemptedValue中,所以Dr.Google在这里引用了我。

我认为这是

    @Html.DropDownList(model => model.ContentKeyID, Model.ContentKeys, Model.ContentKeyName)

其中ContentKeys是通过ViewModel从DB填充的SelectList,而ContentKeyName是选择的名称。

奇怪的是,我在视图中以相同的方式填充了另一个DDL。这个工作。为什么,我不知道。它是表格上的第二个DDL,但我看不出它有所作为。

我在其他地方读到可能是因为我使用Guids作为Id,但这似乎没有什么区别 - 我改为Int32,但不认为我必须 - 我认为这是枚举不同意DDLF。 Nullables似乎没有任何区别。

现在我已将表单集合添加到Post ActionResult,并使用

获取所选值

-view

    @Html.DropDownList("ContentKey", Model.ContentKeys)

-in controller(Post)

    contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue); 
一切都很好,我可以继续做更多令人兴奋的事情。为什么最简单的事情会让你忍受这么久?

答案 2 :(得分:1)

在过去的一天左右,我一直在努力解决这个问题。我将分享我有限的知识,希望它能帮助别人。

请注意,我使用带有预填充列表的单例来保持我的示例应用程序较小(即没有EF或DB交互)。

要显示ProductList,您需要具有包含ProductList的ViewBag或ViewData项。 您可以使用类似

的内容在Controller中进行设置
    ViewData["ProductList"] = new SelectList(Models.MVCProduct.Instance.ProductList, "Id", "Name", 1);

然后将您的视图更新为:

    <div class="editor-field">@Html.DropDownList("ProductList")</div>

对于发布/创建/更新步骤,您需要查看FormCollection以获取结果。阅读其他帖子听起来像曾经是这里的一个错误,但现在已经修复,所以确保你有最新的。对于我的示例,我有一个DropDownList for Product,所以我只获得所选的Id,然后在我的列表中搜索该产品。

    [HttpPost]
    public ActionResult Create(FormCollection form )//Models.MVCOrder newOrder)
    {

        MVC.Models.MVCOrder ord = Models.MVCOrder.Instance.CreateBlankOrder();
        //Update order with simple types (e.g. Quantity)
        if (TryUpdateModel<MVC.Models.MVCOrder>(ord, form.ToValueProvider()))
        {
            ord.Product = Models.MVCProduct.Instance.ProductList.Find(p => p.Id == int.Parse(form.GetValue("ProductList").AttemptedValue));
            ord.Attribute = Models.MVCAttribute.Instance.AttributeList.Find(a => a.Id == int.Parse(form.GetValue("attributeId").AttemptedValue));
            UpdateModel(ord);
            return RedirectToAction("Index");
        }
        else
        {
            return View(ord);
        }
    }

我过去几天才开始研究MVC3,所以对任何有关改进上述内容的建议都表示赞赏。