簡體   English   中英

導出 Grid.MVC 數據到 Excel

[英]Exporting Grid.MVC data to Excel

我需要將Grid.MVC中的數據導出到Excel,我使用了這個鏈接中的方案。

http://www.codeproject.com/Articles/325103/MVC-Grid-to-Excel-file-download?msg=5161340#xx5161340xx

它正在工作,但我有 2 個問題。 首先它在 chrome 中工作,但在 IE 中不工作。 它在 IE 中給我一個錯誤(無法讀取文件)。 第二個問題是當我過濾網格時,Excel 中導出的數據仍然顯示所有數據而不是過濾后的數據。

如果這不是一個好的解決方案,請提供將 Grid.MVC 數據導出到 excel 的示例。

我有一個適合我的javascript / jquery解決方案。

當你使用grid.mvc時,它會向thead和tbody添加一些類,需要刪除這些類,以便在生成的excel文件上進行正確的導出/可視化。 我也在使用grid.mvc,這個代碼導出為ex​​cel,如果這對你有用,請告訴我。

 <script> $("#btnExport").click(function (e) { $('.grid-wrap').find('table').removeAttr('class'); $('.grid-header').removeAttr('class'); $('.grid-row').removeAttr('class'); $('.grid-cell').removeAttr('data-name'); $('.grid-cell').removeAttr('class'); window.open('data:application/vnd.ms-excel,' + $('.grid-wrap').html()); //MakeAnyFunctionToReloadThePageToGetTheClassesAgain(); e.preventDefault(); }); </script> 
 @Html.Grid(Model).Columns(columns => { columns.Add(foo => foo.Date).Sortable(true).Filterable(true); columns.Add(foo => foo.User).Sortable(true).Filterable(true); columns.Add(foo => foo.Controller).Sortable(true).Filterable(true); columns.Add(foo => foo.Action).Sortable(true).Filterable(true); columns.Add(foo => foo.ActionType).Sortable(true).Filterable(true); columns.Add(foo => foo.JsonObject).Sortable(true).Filterable(true); }).WithMultipleFilters() <button type="button" class="btn btn-danger" id="btnExport">export csv</button> 

你必須從url獲取參數。 然后在后端構建自己的服務,獲取參數並導出到excel

let params = new URLSearchParams(document.location.search);
let allParams = params.getAll('grid-filter');

這是服務器端解決方案

在這種情況下,客戶端組件並不重要。 您傳遞的任何數據用於導出,它將其導出到excel文件並下載。 當我想要導出數據時,我使用最新的過濾器並檢索顯示的相同數據。

我希望它對你有所幫助。

  • 我使用GridView來顯示我的數據。
  • 而且我還使用了一個簡單的數據表。 您可以從DataBase或任何地方檢索數據。
  • DataView只是幫助我過濾數據。
  • 您需要將ClosedXML添加到項目中。 使用此NuGet命令: Install-Package ClosedXML

ASPX

 <form id="form1" runat="server"> <div> <asp:TextBox ID="TextBox1" runat="server" placeholder="Name or Family" ></asp:TextBox> <asp:Button ID="ButtonFilter" runat="server" Text="Filter" OnClick="ButtonFilter_Click" /> <br /> <br /> <asp:GridView ID="GridView1" runat="server"> </asp:GridView> <br /> <br /> <asp:Button ID="ButtonExport" runat="server" Text="Export" OnClick="ButtonExport_Click" /> </div> </form> 

C#代碼

private DataTable dt = new DataTable();
private DataView dv;

private void Page_Load(object sender, System.EventArgs e)
{
    dt.Columns.Add("Id");
    dt.Columns.Add("EmployeeName");
    dt.Columns.Add("EmployeeFamily");

    for (int i = 0; i < 10; i++)
    {
        var r1 = dt.NewRow();
        r1["Id"] = i + 100;
        r1["EmployeeName"] = "Name " + i.ToString();
        r1["EmployeeFamily"] = "Family " + i.ToString();
        dt.Rows.Add(r1);
    }

    dv = new DataView(dt);

    GridView1.DataSource = dv;
    GridView1.DataBind();
}


private MemoryStream GetStream(XLWorkbook excelWorkbook)
{
    MemoryStream fs = new MemoryStream();
    excelWorkbook.SaveAs(fs);
    fs.Position = 0;
    return fs;
}


protected void ButtonFilter_Click(object sender, EventArgs e)
{
    dv.RowFilter = $"EmployeeName LIKE '%{TextBox1.Text}%' OR EmployeeFamily LIKE '%{TextBox1.Text}%'";

    GridView1.DataSource = dv;
    GridView1.DataBind();
}


protected void ButtonExport_Click(object sender, EventArgs e)
{
    dv = new DataView(dt);
    dv.RowFilter = $"EmployeeName LIKE '%{TextBox1.Text}%' OR EmployeeFamily LIKE '%{TextBox1.Text}%'";

    using (XLWorkbook wb = new XLWorkbook())
    {
        wb.Worksheets.Add(dv.ToTable(), "Employees");
        string myName = HttpContext.Current.Server.UrlEncode("Employees.xlsx");
        MemoryStream stream = GetStream(wb);
        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.Buffer = true;
        HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + myName);
        HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
        HttpContext.Current.Response.BinaryWrite(stream.ToArray());
        HttpContext.Current.Response.End();
    }
}






更新: GridMvc版本

在這個版本中,我使用了GridMvc但我仍然在服務器端制作Excel文件

ASPX

 @model IList<GridMvcExportToExcel.Controllers.EmployeeModel> @using GridMvc.Html @{ ViewBag.Title = "Home Page"; } <script type="text/javascript"> function exportToExcel() { debugger; var txtFilter = $('#txtFilter').val(); // get the textbox value var url = 'http://localhost:54312/Home/ExportToExcel?txtFilter=' + txtFilter; location.href = url; // redirect return false; // cancel default redirect }; </script> <div> @using (Html.BeginForm("Index", "Home")) { @Html.TextBox("txtFilter", "", new { id = "txtFilter" }) <button type="submit">Filter</button> } <br /> @Html.Grid(Model).Columns(c => { c.Add(x=>x.Id).Titled ("Employee Id"); c.Add(x=>x.Name).Titled ("First Name").Filterable(false); c.Add(x=>x.Family).Titled ("Last Name").Filterable(true); }).WithPaging(50) <input type="button" id="exportToExcel" value="Export to Excel" onclick="exportToExcel()" /> </div> 

C#

public class EmployeeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Family { get; set; }
}

public class HomeController : Controller
{
    private IList<EmployeeModel> employees = new List<EmployeeModel>();

    public HomeController()
    {
        for (int i = 0; i < 20; i++)
        {
            employees.Add(new EmployeeModel()
            {
                Id = i + 1,
                Name = "Name " + (i + 1).ToString(),
                Family = "Family " + (i + 1).ToString(),
            });
        }
    }

    public ActionResult Index(string txtFilter)
    {
        txtFilter = txtFilter ?? "";
        var result = employees.Where(x => x.Name.Contains(txtFilter) || x.Family.Contains(txtFilter) || x.Id.ToString() == txtFilter);
        return View(result.ToList());
    }

    public void ExportToExcel(string txtFilter)
    {
        txtFilter = txtFilter ?? "";
        var result = employees.Where(x => x.Name.Contains(txtFilter) || x.Family.Contains(txtFilter) || x.Id.ToString() == txtFilter).ToList();

        DataTable table = new DataTable();
        using (var reader = ObjectReader.Create(result))
        {
            table.Load(reader);
        }

        using (XLWorkbook wb = new XLWorkbook())
        {
            wb.Worksheets.Add(table, "Employees");
            string myName = HttpContext.Server.UrlEncode("Employees.xlsx");
            MemoryStream stream = GetStream(wb);
            HttpContext.Response.Clear();
            HttpContext.Response.Buffer = true;
            HttpContext.Response.AddHeader("content-disposition", "attachment; filename=" + myName);
            HttpContext.Response.ContentType = "application/vnd.ms-excel";
            HttpContext.Response.BinaryWrite(stream.ToArray());
            HttpContext.Response.End();
        }
    }

    private MemoryStream GetStream(XLWorkbook excelWorkbook)
    {
        MemoryStream fs = new MemoryStream();
        excelWorkbook.SaveAs(fs);
        fs.Position = 0;
        return fs;
    }
}

在響應中設置以下標題,將以適當的類型下載

數據:應用程序/ vnd.ms-Excel中

我可能會遲到,但我找到了一個解決方案,可以使用GridMvc插件的內置filtering選項。 此解決方案不需要任何客戶端操作或自定義過濾器應用。 你這是怎么go一下的。

安裝插件時,它會生成一個名為: _Grid.cshtmlpartial視圖,位於: ~/Views/Shared/_Grid.cshtml位置。

現在我觀察到,每次您在網格上調用一個事件時,都會調用這個局部視圖,然后我調試到流程中,發現有問題的Model具有不同的屬性,如RenderOptionsItemsToDisplay等。

所以我發現過濾后的數據也存儲了但沒有直接存儲在屬性中。 有一個名為: ItemsToDisplay的屬性,但不幸的是,如果您在網格上應用paging ,那么它只會存儲前n項目,其中n是分頁限制。

最后我不得不求助於reflection來獲取整個過濾列表,這會影響網格的性能但影響不大,但它會完成工作。

_網格.cshtml:

@using GridMvc.Columns
@using System.Reflection;
@model GridMvc.IGrid
@{ 
    try
    {
        Type t = typeof(GridMvc.Html.GridHtmlOptions<MyModel>);
        FieldInfo[] fi = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
        foreach (FieldInfo info in fi)
        {
            if (info.Name == "_source")
            {
                object _source = info.GetValue(Model);
                PropertyInfo gridItemsProperty = _source.GetType().GetProperty("GridItems");
                object gridItemsData = gridItemsProperty.GetValue(_source);
                //Set the filtered list here in Session
                Session["CurrentFilteredGridForExcelExport"] = (IEnumerable<MyModel>)(gridItemsData);
            }
        }
    }
    catch
    {

    }
}

@if (Model.RenderOptions.RenderRowsOnly)
{
    @RenderGridBody();
}
else
{
    <div class="grid-mvc" data-lang="@Model.Language" data-gridname="@Model.RenderOptions.GridName" data-selectable="@Model.RenderOptions.Selectable.ToString().ToLower()" data-multiplefilters="@Model.RenderOptions.AllowMultipleFilters.ToString().ToLower()">
        <div class="grid-wrap">
            <table class="table table-striped grid-table">
                @* Draw grid header *@
                <thead>
                    @RenderGridHeader()
                </thead>
                <tbody>
                    @RenderGridBody()
                    @RenderGridFooter()
                </tbody>
            </table>
            @RenderGridFooter()
        </div>
    </div>
}
@helper RenderGridBody()
{
    if (!Model.ItemsToDisplay.Any())
    {
        <tr class="grid-empty-text">
            <td colspan="@Model.Columns.Count()">
                @Model.EmptyGridText
            </td>
        </tr>
    }
    else
    {
        foreach (object item in Model.ItemsToDisplay)
        {
            <tr class="grid-row @Model.GetRowCssClasses(item)">
                @foreach (IGridColumn column in Model.Columns)
                {
                    @column.CellRenderer.Render(column, column.GetCell(item))
                }
            </tr>
        }
    }
}
@helper RenderGridHeader()
{
    if (Model.RenderOptions.ShowGridItemsCount)
    {
            <div class="grid-itemscount">
                <span class="grid-itemscount-label">@Model.RenderOptions.GridCountDisplayName:</span>
                <span class="grid-itemscount-caption">@Model.ItemsCount</span>
            </div>
    }

    <tr>
        @foreach (IGridColumn column in Model.Columns)
        {
            @column.HeaderRenderer.Render(column)
        }
    </tr>
}
@helper RenderGridFooter()
{
    <div class="grid-footer">
        @if (Model.EnablePaging && Model.Pager != null)
        {
            @Html.Partial(Model.Pager.TemplateName, Model.Pager)
        }
    </div>
}

最后,您可以像這樣在您的Controller端導出這個過濾后的網格:

public void ExportToExcel()
{
    List<MyModel> mymodel= new List<MyModel>();
    if(Session["CurrentFilteredGridForExcelExport"] != null)
    {
        var datasetFromSession = (IEnumerable<MyModel>)(Session["CurrentFilteredGridForExcelExport"]);
        mymodel = datasetFromSession.ToList();
    }
    
    //Use your export logic with this dataset   
}

希望這對仍在使用此網格插件的人有所幫助。 干杯!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM