如何将自定义模型对象从剃刀视图传递到ASP.NET MVC 5中的控制器操作

时间:2022-11-30 17:56:43

I'm writing my first production application in mvc 5. I'm trying to pass a custom object as a parameter to a http post action in my controller. Basically, I have a view wrapped in my CustomerReport View Model, in that, I have a partial that creates a modal with the option of selecting items from the model and I want to save the selections through a controller action passing the view model (or properties of the view model) as a parameter.

我正在mvc 5中编写我的第一个生产应用程序。我正在尝试将自定义对象作为参数传递给我的控制器中的http post动作。基本上,我有一个包含在我的CustomerReport视图模型中的视图,其中,我有一个部分创建一个模态,可以选择从模型中选择项目,我想通过控制器操作传递视图模型来保存选择(或者视图模型的属性)作为参数。

My Report View Model

我的报告视图模型

public class CustomerReport
{
    public User User { get; set; }
    public List<NewEnterprise> Enterprises { get; set; }
    public NewEnterpriseRepository EnterpriseRepository { get; set; }
    public NewCustomerRepository CustomerRepository { get; set; }
    public NewProgramRepository ProgramRepository { get; set; }
    public List<NewCustomer> Customers { get; set; }
    public List<NewProgram> Programs { get; set; }
    public List<InvoiceItem> InvoiceItems { get; set; }
    public List<ReportSelectionItem> ReportSelectionItems { get; set; }
    public List<ReportSelectionItem> FilteredSelectionItems { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public string Start { get; set; }
    public string End { get; set; }
    public string ReportType { get; set; }
    public NewReports Reports { get; set; }

    public CustomerReport()
    {
        User = HttpContext.Current.GetUser();
        Enterprises = new List<NewEnterprise>();
        Customers = new List<NewCustomer>();
        Programs = new List<NewProgram>();
        InvoiceItems = new List<InvoiceItem>();
        ReportSelectionItems = new List<ReportSelectionItem>();
    }

    public CustomerReport(User user)
    {
        User = user;
        Enterprises = new List<NewEnterprise>();
        Customers = new List<NewCustomer>();
        Programs = new List<NewProgram>();
        InvoiceItems = new List<InvoiceItem>();
        ReportSelectionItems = new List<ReportSelectionItem>();
        Start = Code.StringExtensions.InputDate(new DateTime(2016, 01, 01)).ToString();
        End = Code.StringExtensions.InputDate(DateTime.Today).ToString();
    }

    public CustomerReport(User user, List<NewEnterprise> enterprises, List<NewCustomer> customers, List<NewProgram> programs)
    {
        User = user;
        Enterprises = enterprises;
        Customers = customers;
        Programs = programs;
    }

    public List<ReportSelectionItem> GetAllReportSelectionItems()
    {
        var items = new List<ReportSelectionItem>();
        foreach (var ent in Enterprises)
        {
            var item = new ReportSelectionItem(ent);
            items.Add(item);
        }
        foreach (var cust in Customers)
        {
            var item = new ReportSelectionItem(cust);
            items.Add(item);
        }
        foreach (var so in Programs)
        {
            var item = new ReportSelectionItem(so);
            items.Add(item);
        }

        return items;
    }

    public List<ReportSelectionItem> ReportSelectionItemsSearch(string search)
    {
        var items = GetAllReportSelectionItems();
        var filteredItems = new List<ReportSelectionItem>();
        if (!String.IsNullOrWhiteSpace(search))
        {
            filteredItems = items.Where(i => i.DisplayName.ToLower().Contains(search.ToLower())).ToList();
            return filteredItems;
        }
        return items;
    }

    public List<ReportSelectionItem> ReportSelectionItemsFilter(List<ReportSelectionItem> items, string type)
    {
        var filteredItems = new List<ReportSelectionItem>();
        if (!type.ToLower().Equals("all"))
        {
            filteredItems = items.Where(i => i.Type.ToLower().Contains(type.ToLower())).ToList();
            return filteredItems;
        }
        return items;
    }

    public void SearchAndFilter(string search, string searchType)
    {
        if (!String.IsNullOrWhiteSpace(search))
        {
            this.FilteredSelectionItems = this.ReportSelectionItemsSearch(search);
        }
        if (!String.IsNullOrWhiteSpace(searchType))
        {
            this.FilteredSelectionItems = this.ReportSelectionItemsFilter(this.ReportSelectionItems, searchType);
        }
    }

    public void RemoveSlashFromDates(string start, string end)
    {
        if (start != null)
        {
            this.Start = start.Replace("/", "");
        }
        if (end != null)
        {
            this.End = end.Replace("/", "");
        }
    }
}

My class for list of items to select from

我的课程列表可供选择

public class ReportSelectionItem
 {
     public Guid ID { get; set; }
     public string Name { get; set; }
     public string DisplayName { get; set; }
     public string Number { get; set; }
     public string Type { get; set; }
     public string TypeDisplay => GetTypeDisplay(Type);
     public bool IsSelected { get; set; }

     public ReportSelectionItem()
     {
         ID = Guid.NewGuid();
         IsSelected = false;
     }

     public ReportSelectionItem(NewEnterprise ent) : this()
     {
         Name = ent.Name;
         DisplayName = ent.DisplayName;
         Number = ent.EnterpriseNumber.ToString();
         Type = ent.GetType().ToString();
     }

     public ReportSelectionItem(NewCustomer cust) : this()
     {
         Name = cust.Name;
         DisplayName = cust.DisplayName;
         Number = cust.Id.ToString();
         Type = cust.GetType().ToString();
     }

     public ReportSelectionItem(NewProgram so) : this()
     {
         Name = so.Description;
         DisplayName = so.DisplayName;
         Number = so.ServiceOrderNumber.ToString();
         Type = so.GetType().ToString();
     }

     public string GetTypeDisplay(string str)
     {
         if (str.ToLower().Contains("enterprise"))
         {
             return "Enterprise";
         }else if (str.ToLower().Contains("customer"))
         {
             return "Customer";
         }else if (str.ToLower().Contains("program"))
         {
             return "Program";
         }
         else return str;
     }
 }

A selection of my main view that houses the modal

我选择的主要视图包含模态

@using System.Activities.Statements
@model RecognitionReports.Web.ViewDataModels.CustomerReport

@{
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div class="row">
    <div class="col-xs-offset-1 col-xs-10">
        <div class="container">
            <div class="form-wrapper">
                <div class="search-form">
                    @using (Html.BeginForm("New", "CustomerReports", FormMethod.Get))
                    {
                        <form class="form">
                        <fieldset>
                                @Html.Label("Search:", new { @class = "form-label" })
                                <div class="form-group row">
                                    <div class="col-xs-offset-1 col-xs-10">
                                        <div class="input-group">
                                            @Html.TextBox("search", null, new { @class = "form-control", @placeholder = "Enter Selection Name or ID Number here..." })
                                            <span class="input-group-btn">
                                                <div class="btn-group">
                                                    <a href="#" class="btn btn-info dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-search"></span> Search:</a>
                                                   <ul class="dropdown-menu">
                                                        <li><input name="searchType" type="submit" id="all" value="All" class="form-control btn btn-info" /></li>
                                                        <li><input name="searchType" type="submit" id="ent" value="Enterprise" class="form-control btn btn-info" /></li>
                                                        <li><input name="searchType" type="submit" id="cust" value="Customer" class="form-control btn btn-info" /></li>
                                                        <li><input name="searchType" type="submit" id="so" value="Program" class="form-control btn btn-info" /></li>
                                                    </ul>
                                                </div>
                                            </span>
                                        </div>
                                    </div>
                                </div>
                            </fieldset>
                        </form>
                    }
                </div>

            <!-- Report Selection Modal -->
            @{ Html.RenderPartial("_ReportSelectionOptionsModal", Model);}
            <!-- Report Modal -->
            @{ Html.RenderPartial("_ReportModal", Model); }
        </div>
    </div>
</div>

My modal view

我的模态观点

@model RecognitionReports.Web.ViewDataModels.CustomerReport

<div id="selection-modal" class="modal fade" role="dialog">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal">&times;</button>
            <h4 class="modal-title">Report Selection Options</h4>
        </div>
        @using (Html.BeginForm("SaveSelections", "CustomerReports", FormMethod.Post))
        {

            <div class="modal-body">
                <table class="table table-condensed table-striped table-hover">
                    <caption>All Report Options: </caption>
                    <thead>
                        <tr>
                            <th>Display Name</th>
                            <th>Type</th>
                            <th>Manage</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (var item in Model.FilteredSelectionItems)
                        {
                            <tr>
                                <td><strong>@item.DisplayName</strong></td>
                                <td>@item.TypeDisplay</td>
                                <td>
                                    @Html.CheckBoxFor(i => item.IsSelected, new { @class = "check-box", Name=item.ID, id=item.ID })
                                </td>
                            </tr>
                        }
                    </tbody>
                </table>
            </div>
            <div class="modal-footer">
                <input type="submit" class="btn btn-success" name="action" value="Save"/>
                <button type="button" class="btn btn-info" data-dismiss="modal">Close</button>
            </div>
        }
    </div>
</div>

</div>

Possible ways I'd like to pass to the controller

我想传递给控制器​​的可能方法

        [HttpPost]
    public ActionResult SaveSelections(CustomerReport report)
    {
        //make sure selections are saved
        return View("New", report);
    }

or

        [HttpPost]
    public ActionResult SaveSelections(List<ReportSelectionItems> items)
    {
        //make sure selections are saved
        return View("New", report);
    }

I've tried a lot of things and it continues to pass the parameter as null. I know that razor turns the object properties into strings after the page renders, but I've seen people pass custom objects as parameters to controller actions... What am I doing wrong? Is there a better way to do this?

我已经尝试了很多东西,它继续将参数传递为null。我知道剃刀在页面渲染后将对象属性转换为字符串,但我看到人们将自定义对象作为参数传递给控制器​​操作......我做错了什么?有一个更好的方法吗?

Edit: Updated For loop in modal view to:

编辑:更新为模态视图中的循环:

@for (var i = 0; i < Model.FilteredSelectionItems.Count; i++)
  {
    <tr>
        <td><strong>@Model.FilteredSelectionItems[i].DisplayName</strong></td>
        <td>@Model.FilteredSelectionItems[i].TypeDisplay</td>
        <td>@Html.CheckBoxFor(x => Model.FilteredSelectionItems[i].IsSelected, new { @class = "check-box", Name = Model.FilteredSelectionItems[i].ID, id = Model.FilteredSelectionItems[i].ID})
            @Html.HiddenFor(x => Model.FilteredSelectionItems[i].ID)
        </td>
    </tr>
  }

1 个解决方案

#1


0  

The only field that you have in your form is a checkbox for each of the elements in the FilteredSelectionItems property. So that's the only information that will make it to your server. You might need to adjust a little bit the form:

表单中唯一的字段是FilteredSelectionItems属性中每个元素的复选框。这是唯一可以进入服务器的信息。您可能需要稍微调整一下形式:

Instead of this:

而不是这个:

@foreach (var item in Model.FilteredSelectionItems)
{
    <tr>
        <td><strong>@item.DisplayName</strong></td>
        <td>@item.TypeDisplay</td>
        <td>
            @Html.CheckBoxFor(i => item.IsSelected, new { @class = "check-box", Name=item.ID, id=item.ID })
        </td>
    </tr>
}

use this:

@for (var i = 0; i < Model.FilteredSelectionItems.Count; i++)
{
    <tr>
        <td><strong>@item.DisplayName</strong></td>
        <td>@item.TypeDisplay</td>
        <td>
            @Html.CheckBoxFor(x => model.FilteredSelectionItems[i].IsSelected, new { @class = "check-box", Name=item.ID, id=item.ID })
        </td>
    </tr>
}

Now your controller action will successfully bind to this:

现在您的控制器操作将成功绑定到此:

[HttpPost]
public ActionResult SaveSelections(CustomerReport report)
{
    // only report.FilteredSelectionItems collection will be available here
    // because that's the only thing you have input fields in the form
    ...
}

If you need the other fields populate as well, you could retrieve them from your database, the same way you retrieved them in your GET action. And then merge with the results of the FilteredSelectionItems collection that was populated by the user checkbox selections from the view.

如果您还需要填充其他字段,则可以从数据库中检索它们,就像在GET操作中检索它们一样。然后合并FilteredSelectionItems集合的结果,该集合由视图中的用户复选框选择填充。

#1


0  

The only field that you have in your form is a checkbox for each of the elements in the FilteredSelectionItems property. So that's the only information that will make it to your server. You might need to adjust a little bit the form:

表单中唯一的字段是FilteredSelectionItems属性中每个元素的复选框。这是唯一可以进入服务器的信息。您可能需要稍微调整一下形式:

Instead of this:

而不是这个:

@foreach (var item in Model.FilteredSelectionItems)
{
    <tr>
        <td><strong>@item.DisplayName</strong></td>
        <td>@item.TypeDisplay</td>
        <td>
            @Html.CheckBoxFor(i => item.IsSelected, new { @class = "check-box", Name=item.ID, id=item.ID })
        </td>
    </tr>
}

use this:

@for (var i = 0; i < Model.FilteredSelectionItems.Count; i++)
{
    <tr>
        <td><strong>@item.DisplayName</strong></td>
        <td>@item.TypeDisplay</td>
        <td>
            @Html.CheckBoxFor(x => model.FilteredSelectionItems[i].IsSelected, new { @class = "check-box", Name=item.ID, id=item.ID })
        </td>
    </tr>
}

Now your controller action will successfully bind to this:

现在您的控制器操作将成功绑定到此:

[HttpPost]
public ActionResult SaveSelections(CustomerReport report)
{
    // only report.FilteredSelectionItems collection will be available here
    // because that's the only thing you have input fields in the form
    ...
}

If you need the other fields populate as well, you could retrieve them from your database, the same way you retrieved them in your GET action. And then merge with the results of the FilteredSelectionItems collection that was populated by the user checkbox selections from the view.

如果您还需要填充其他字段,则可以从数据库中检索它们,就像在GET操作中检索它们一样。然后合并FilteredSelectionItems集合的结果,该集合由视图中的用户复选框选择填充。