将所有选定的 MultiSelectList 值传递给 MVC 控制器以便 EPPlus 导出到 Excel?

Pass all selected MultiSelectList values to MVC Controller for EPPlus Export to Excel?

我正在尝试使用 EPPlus 库向我的 MVC5 Code-First 应用程序添加 Export() 功能。在我的视图中,我有一个 MultiSelectList,其中包含我的主要模型属性的所有值:

@Html.ListBox("PropertyList", typeof(InventoryTracker.Models.INV_Assets).GetProperties().Select(p => new SelectListItem { Text = p.Name, Value = p.Name, Selected = false }), new { @Id = "exportListBox" })

这会呈现以下内容 HTML:

<select Id="exportListBox" id="PropertyList" multiple="multiple" name="PropertyList"><option value="Id">Id</option>
<option value="Model_Id">Model_Id</option>
<option value="Model">Model</option>
<option value="Manufacturer_Id">Manufacturer_Id</option>
<option value="Manufacturer">Manufacturer</option>
<option value="Type_Id">Type_Id</option>
<option value="Type">Type</option>
<option value="Location_Id">Location_Id</option>
<option value="Location">Location</option>
<option value="Vendor_Id">Vendor_Id</option>
<option value="Vendor">Vendor</option>
<option value="Status_Id">Status_Id</option>
<option value="Status">Status</option>
<option value="ip_address">ip_address</option>
<option value="mac_address">mac_address</option>
<option value="note">note</option>
<option value="owner">owner</option>
<option value="cost">cost</option>
<option value="po_number">po_number</option>
<option value="description">description</option>
<option value="invoice_number">invoice_number</option>
<option value="serial_number">serial_number</option>
<option value="asset_tag_number">asset_tag_number</option>
<option value="acquired_date">acquired_date</option>
<option value="disposed_date">disposed_date</option>
<option value="verified_date">verified_date</option>
<option value="created_date">created_date</option>
<option value="created_by">created_by</option>
<option value="modified_date">modified_date</option>
<option value="modified_by">modified_by</option>
</select>

这是我的 [Export] 按钮(超链接)的设置:

@*<a href="/Export/ExportUsingEPPlus" class="btn btn-default btn-sm noDecoration exportBtn"><span class="glyphicon glyphicon-export"> Export - EPPlus</span></a>*@
<a href="#" class="btn btn-default btn-sm noDecoration exportBtn"><span class="glyphicon glyphicon-export"> Export - EPPlus</span></a>

我现在想不通的是如何获取 MultiSelectList 中的所有选定值并将它们传递到我的控制器以指示应将哪些字段导出到 Excel。

@section Scripts {

    <script type="text/javascript">
        $(document).ready(function () {

            $("a.exportBtn").on("click", function (e) {
                e.preventDefault();
                alert("Export button clicked!");
                exportSelectedAssets();
            });

            function exportSelectedAssets() {

            }
        });
    </script>
}

这是我目前在我的控制器中使用 EPPlus 库的结果。目前,它只是在 [A1] 单元格中创建一个具有一个值的 .xlsx。将 MultiSelectList 中的值传递到此控制器后,我想遍历 Table 中所选字段的每个值并输出它们:

    public ActionResult ExportUsingEPPlus()
    {

        //FileInfo newExcelFile = new FileInfo(output);
        ExcelPackage package = new ExcelPackage();
        var ws = package.Workbook.Worksheets.Add("TestExport");
        ws.Cells["A1"].Value = "Sample Export 1";


        var memoryStream = new MemoryStream();
        package.SaveAs(memoryStream);

        string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        memoryStream.Position = 0;
        return File(memoryStream, contentType, fileName);

    }

我正在考虑 JSON 将所有选定的值发布到我的控制器,但我不确定这是否是针对这种情况的最佳途径?有经验的人可以考虑一下吗?


编辑:

尝试 Dawood's 建议,我创建了一个 ViewModel - ExportAssetsViewModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace InventoryTracker.Models
{
    public class ExportAssetsViewModel
    {
        public Dictionary<int, string> ListOfExportFields { get; set; }
        public int[] SelectedFields { get; set; }

        public ExportAssetsViewModel() {
            ListOfExportFields = new Dictionary<int, string>() {
                {1, "Model"},
                {2, "Manufacturer"},
                {3, "Type"},
                {4, "Location"},
                {5, "Vendor"},
                {6, "Status"},
                {7, "ip_address"},
                {8, "mac_address"},
                {9, "note"},
                {10, "owner"},
                {11, "cost"},
                {12, "po_number"},
                {13, "description"},
                {14, "invoice_number"},
                {15, "serial_number"},
                {16, "asset_tag_number"},
                {17, "acquired_date"},
                {18, "disposed_date"},
                {19, "verified_date"},
                {20, "created_date"},
                {21, "created_by"},
                {22, "modified_date"},
                {23, "modified_by"},
            };
        }
    }
}

然后我将 MultiSelectList 放在我的 ExportController - Index 视图上 HTML.BeginForm():

@using (Html.BeginForm())
{
    @Html.ListBox("PropertyList", typeof(InventoryTracker.Models.INV_Assets).GetProperties().Select(p => new SelectListItem { Text = p.Name, Value = p.Name, Selected = false }), new { @Id = "exportListBox" })
    <input type="submit" value="ExportUsingEPPlus" />
}

在我的 ExportUsingEPPlus() 操作中修改了它,如下所示:

    [HttpPost]
    public ActionResult ExportUsingEPPlus(ExportAssetsViewModel model)
    {
        var exportFields = new List<string>();
        foreach(var selectedField in model.SelectedFields)
        {
            exportFields.Add(model.ListOfExportFields.First(s => s.Key == selectedField).Value);
        }


        //FileInfo newExcelFile = new FileInfo(output);
        ExcelPackage package = new ExcelPackage();
        var ws = package.Workbook.Worksheets.Add("TestExport");
        ws.Cells["A1"].Value = "Sample Export 1";


        var memoryStream = new MemoryStream();
        package.SaveAs(memoryStream);

        string fileName = "Exported-InventoryAssets-" + DateTime.Now + ".xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        memoryStream.Position = 0;
        return File(memoryStream, contentType, fileName);

    }

然而,当我单击我的表单输入按钮时,我在 ExportUsingEPPlus() Controller Action 开始的断点没有被击中?所发生的只是页面似乎刷新了,我的选择从 MultiSelectList...?

中清除了

EDIT2:

Index 视图中的 @modelInventoryTracker.Models.INV_Assets 更改为 InventoryTracker.Models.ExportAssetsViewModel,但 [=40] 中的 m.SelectedFieldsModel.ListOfExportFields =] 被标记为不包含它们的定义的模型?

@using GridMvc.Html
@using System.Collections.Generic
@using System.Web.Mvc
@using MvcCheckBoxList.Model
@model  InventoryTracker.Models.ExportAssetsViewModel

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

<h2>Export</h2>

@using (Html.BeginForm("ExportUsingEPPlus", "Export", FormMethod.Post))
{
    @Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.LisOfExportFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" })
    <input type="submit" value="ExportUsingEPPlus" />
}

EDIT3:

我注意到当鼠标悬停在 ListBoxFor() 中的 m => m 上时,我的视图似乎认为它仍在使用模型 INV_Assets,即使我已经重新定义了 @model ] 为 InventoryTracker.Models.ExportAssetsViewModel。我重新输入了我的 @model 定义,现在 m 只显示为 (parameter) TModel m...?

自从我在之前尝试使用 ExportController 并通过 JS/AJAX 传递选定值的想法后创建了 ExportAssetsViewModel,我想我会基于 ExportAssetsViewModel。尝试这样做会导致以下错误:

现在 @Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.ListOfExportFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" }) 标记为:"The type arguments for method 'System.Web.Mvc.Html.SelectExtensions.ListBoxFor<.....> cannot be inferred from the usage. Try specifying the type arguments explicitly."

有人可以帮忙吗?


EDIT4:

忽略 EDIT3。我没有将 ExportAssetsViewModel 传递给 View。固定如下:

控制器 - 索引操作:

    public ActionResult Index()
    {
        //var assetList = _db.INV_Assets.ToList();
        //return View(assetList);
        ExportAssetsViewModel expViewMod = new ExportAssetsViewModel();
        return View(expViewMod);
    }

索引视图:

@using System.Collections.Generic
@using System.Web.Mvc
@model InventoryTracker.Models.ExportAssetsViewModel

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

<h2>Export</h2>

<p>Please select which Asset fields to Export to Excel:</p>

@using (Html.BeginForm("ExportUsingEPPlus", "Export", FormMethod.Post))
{
    @Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.ListOfExportFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" })
    <input type="submit" value="ExportUsingEPPlus" />
}

如果您不使用 Ajax,请执行以下操作:

创建一个 ViewModel(带有字段列表和一个数组来存储 selected 字段):

public class ViewModel
{

    public Dictionary<int, string> LisOfFields { get; set; }
    public int[] SelectedFields { get; set; }


    public ViewModel()
    {
        LisOfFields = new Dictionary<int, string>()
        {
        {1, "Field1"},
        {2, "Field2"},
        {3, "Field3"},
        };

    }
}

然后创建一个视图,用户可以在其中 select 字段

@using (Html.BeginForm())
{

    @Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.LisOfFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" })

    <input type="submit" value="Export" />
}

POST控制器中:(注意以下方法有语法错误)

[HttpPost]
public ActionResult Export(ViewModel model){
var exportFields = new List<string>();

foreach(var selectedfield in model.SelectedFields)
{
exportFields.Add(model.LisOfFields.First(s=> s.Key == selectedField).Value)

}

// EXPORT ALL in exportFields 

}

编辑: 将您的表格更改为:

@using (Html.BeginForm("ExportUsingEPPlus","Export", FormMethod.Post))
{
    @Html.ListBoxFor(m => m.SelectedFields, new MultiSelectList(Model.LisOfFields, "Key", "Value"), new { @class = "form-control", style = "height: 250px;" })
    <input type="submit" value="ExportUsingEPPlus" />
}

使用 ajax 你可以构建一个包含 selected 项目的数组,然后 post 它们 jquery:

function exportSelectedAssets() {
 var selectedValues = [];
 $("#exportListBox :selected").each(function() {
   selectedValues.push($(this).attr('value'));
 });

 $.post("/ExportUsingEPPlus/", { Ids: selectedValues  });
}

请注意,我必须删除您呈现的 ID 中的一个 select,因为它有两个。

然后您可以更改您的控制器操作以接受字符串值数组并用 [HttpPost]:

装饰它
[HttpPost]
public ActionResult ExportUsingEPPlus(string[] Ids)
{
   ...
}

jsFiddle [展示 selected 值]