【问题标题】:Populate a model from posted form values in asp.net MVC从 asp.net MVC 中发布的表单值填充模型
【发布时间】:2012-08-07 15:55:20
【问题描述】:

我有一个 SearchViewModel:

public class SearchViewModel
{
    [Required]
    public DateTime From { get; set; }
    [Required]
    public int Days { get; set; }
    public long DealerID { get; set; }
    public IQueryable<TypesAvail> TypesAvails { get; set; }
}

IQueryable TypesAvails 是另一个类,它包含可从 DealerID 以及 SearchviewModel 类的 From 和 Days 属性之间获得的 CarTypes 列表 - 它还用于在视图中生成下拉列表:

public class TypesAvail
{
    public String TypeNme { get; set; }
    public long TypeID { get; set; }
    public int NumSelected { get; set; }
    public int TypeCount { get; set; }
    public IEnumerable<SelectListItem> CarsAvail 
    {
        get
        {
            return new SelectList(
                    Enumerable.Range(0, TypeCount+1)
                    .OrderBy(typecount => typecount)
                    .Select(typecount => new SelectListItem
                    {
                        Value = typecount.ToString(),
                        Text = typecount.ToString()
                    }), "Value", "Text");
        }
    } 
}

我的控制器是:(编辑:添加控制器以显示访问数据的代码)

  public ActionResult Avail(SearchViewModel model, string id)
    {
        if (ModelState.IsValid)
        {
            var dteFrom = model.From;
            var dteTo = model.From.AddDays(model.Days);

            var prebookedCars = db.Cars
                .Where(car=> car.Rentals.Any(rental =>
                    (model.DealerID == rental.Dealerid) && (
                    (dteFrom >= rental.dateout && dteFrom < rental.datein )
                    ||
                    (dteTo > rental.dateout && dteTo <= rental.datein )
                    ||
                    (dteFrom <= rental.dateout && dteTo >= rental.datein )
                )));


            model.TypesAvails = db.Cars
                .Where(r => r.Dealerid == model.DealerID)
                .Except(prebookedCars)
                .GroupBy(p => p.CarType)
                .Select(g => new TypesAvail
                {
                    TypeNme = g.Key.type_name,
                    TypeID = g.Key.type_id,
                    TypeCount = g.Count(),
                    NumSelected = 0
                }
                );

            return View(model);
        }
        else
        {
            return View(model);
        }
    }

逻辑(我有待纠正)如下:

  1. SearchViewModel 发送到针对 TypesAvail 为 null 的视图
  2. 当 Post 发生时,控制器将 From、Days 和 DealerID 直接填充回模型中,使用:

    [HttpPost]
    public ActionResult Avail(SearchViewModel model)

  3. 在控制器中,它还会填充 TypesAvail IQueryable

所以现在 ViewModel 具有搜索日期、天数和 TypesAvailable 列表,其中包括选择列表。

这在视图中重新填充,如下所示:

@model ebm2.ViewModels.SearchViewModel

@using (Html.BeginForm()) 
{
    @Html.ValidationSummary()

    <ul data-role="listview" data-inset="true">
        <li data-role="list-divider">Check Availability</li>
        <li data-role="fieldcontain">
            @Html.LabelFor(m => m.From)
            @Html.TextBoxFor(m => m.From, new { @type = "date", data_role = "datebox", data_options = "{\"mode\":\"slidebox\", \"overrideDateFormat\":\"%A %d %b %Y\"}" })    
            @Html.ValidationMessageFor(m => m.From)    
        </li>           
        <li data-role="fieldcontain">
            @Html.LabelFor(m => m.Days)
            @Html.TextBoxFor(m => m.Days, new { @type = "range", min = 1, max = 30 })            
            @Html.ValidationMessageFor(m => m.Days)    
        </li>
        <li data-role="fieldcontain">
            <input type="submit" value="Search" />
        </li>
    </ul>
    @Html.HiddenFor(m => m.DealerID)

    if (Model.TypesAvails != null)
    {
        <ul data-role="listview" data-inset="true">
            <li data-role="list-divider">Book</li>
            @foreach (var item in Model.TypesAvails)
            {
                <li data-role="fieldcontain">      
                    @Html.HiddenFor(modelItem => item.TypeID) ->
                    @Html.DisplayFor(modelItem => item.NumSelected) ->
                    @Html.DropDownListFor(modelItem => item.NumSelected, item.CarsAvail)
                </li>
            }
        </ul>
    }
}

返回服务器的第二个 POST 显示:

From=07%2F08%2F2012+00%3A00%3A00& Nights=1 & DealerID=1 & 
item.TypeID=3059 & item.NumSelected=3 & 
item.TypeID=3103 & item.NumSelected=2 & 
item.TypeID=3170 & item.NumSelected=7 & 
item.TypeID=3212 & item.NumSelected=4

显示这些的 Razor 不会将 TypeID 分配给每个下拉列表:

@Html.HiddenFor(modelItem => item.TypeID)
@Html.DropDownListFor(modelItem => item.NumSelected, item.CarsAvail)

我的问题来自 POST 模型 - TypesAvail 显示为 NULL - 有没有办法在回发时直接进入 ViewModel 中表示下拉列表中的选定项目?

如果没有,我如何遍历 FORM 字段,以创建另一个模型 - 将具有:

From
Days
DealerID
{
    TypeID = 3059, NumSelected = 3,
    TypeID = 3103, NumSelected = 2,
    TypeID = 3170, NumSelected = 7,
    TypeID = 3212, NumSelected = 4
}

...然后我可以使用它向我的数据库添加记录(基本上是经销商想要在两个日期之间租用的汽车列表)。

或者我是否试图从一个表单中获取搜索日期,然后用多个下拉列表填充同一个表单,这样做太多了 - 有没有更好的方法:

  1. 从日期框和晚数搜索
  2. 然后显示符合搜索条件的选项列表
  3. 然后发布到服务器,并保存搜索数据(起始日期、天数、经销商 ID),以及选定的下拉列表,以及在每个列表中选择了什么?

谢谢你,马克

更新

在 Shyu 的帮助下,我取得了一些进展——我添加了一个编辑器模板:

@model ebm2.Models.TypesAvail
@Html.DropDownListFor(modelItem => modelItem.NumSelected, Model.CarsAvail)

...并在视图中渲染:

   @Html.EditorFor(model=>model.TypesAvails)

但是,当我将表单发布回控制器(添加 editorTemplate 之后)时,我收到以下消息:

[MissingMethodException: Cannot create an instance of an interface.]

我假设这意味着它不再识别模型 - 这是因为 EditorTemplate 吗?

我的回发方法是,然后将其添加到 ViewModel 是执行此操作的最佳方式,还是建议您使用 jQuery/Ajax 在客户端全部执行此操作 - 并且只有在我有的时候才最终回发到服务器我的模型的完整 JSON 对象?

我将不胜感激任何有关这方面的指导。

谢谢,马克

【问题讨论】:

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


    【解决方案1】:

    使用 EditorTemplate

    创建一个名为“EditorTemplates”的文件夹并创建一个名为TypesAvail.cshtml的视图(编辑器模板)

    现在将下面的代码添加到这个新视图中。

    @model TypesAvail
    <p>
       @Html.DropDownListFor(modelItem => item.NumSelected, item.CarsAvail)
    </p>
    

    现在在您的主视图中,使用Html.EditorFor HTML 辅助方法调用此编辑器模板

    @model ebm2.ViewModels.SearchViewModel
    <h2>CarList</h2>
    @using (Html.BeginForm())
    {
        <p>Put other elements also </p>
        @Html.EditorFor(x=>x.TypesAvails)
        <input type="submit" value="Save" />
    }
    

    【讨论】:

    • 嗨 - 谢谢 - 当我在视图中用你的 HTML Helper 替换我的 HTML Helper 时出现错误:“已经有一个打开的 DataReader 与此命令关联,必须先关闭。” - 谢谢,
    • @fixit :应该与您如何读取数据有关。确保在数据访问代码中关闭 DataReader。
    • 嗨@Shyju - 我没有使用任何东西来访问数据 - 只是开箱即用的代码。我已将控制器添加到原始帖子中。那是可能导致此错误的地方吗?谢谢你,马克
    【解决方案2】:

    试试

            Dim strcon As String = "Data Source=.\SQLEXPRESS;AttachDbFilename=D:\webarticles\App_Data\mydatabase.mdf;Integrated Security=True;User Instance=True"
            Dim con As New SqlConnection(strcon)
            con.Open()
    
    
            Dim da As SqlDataAdapter
            Dim ds As New DataSet
    
            Dim sqlstring As String = "SELECT * FROM tblstudent "
    
            da = New SqlDataAdapter(sqlstring, con)
            da.Fill(ds)
            FormView1.DataSource = ds.Tables(0)
            FormView1.DataBind()
            Label1.Text = "Formview is filled"
    
    
    
    
        Catch ex As Exception
            Label1.Text = "There is Some Error"
    
        End Try
    

    FormView 是另一个用于处理记录的 asp.net 控件,它使您能够处理来自数据源的单个记录,类似于 DetailsView 控件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多