Asp.net Mvc3 webgrid和分页

时间:2011-06-14 13:08:46

标签: asp.net-mvc-3 webgrid

我正在努力学习Asp.net mvc。我知道它与形式不同,我需要改变我的思维方式。我的问题是关于webgrid。当我将webgrid添加到我的页面并点击搜索按钮时,使用Postr呈现带有寻呼机的表格,依此类推。但是寻呼机上的链接不是张贴形式,它们只是链接,我丢失了所有表格的数据。

Controller有两种索引方法,一种是get,另一种是post。为了让我什么都不做,我只是在这种情况下创建新的viewmodel Search类并将其设置为view。对于我的post方法,我抓住我的视图模型进行搜索并设置填充的viewmodel进行查看。

问题:webgrid将寻呼机呈现为链接,因此它将进入索引以获取,但由于它不是发布请求,因此我没有填写任何表单字段,并且我的搜索不会提供完全相同的结果集。

也许示例代码可以更好地解释它。

查看:

<form action="" method="post">

Esas no : @Html.TextBoxFor(x=>x.Name)
Yil : @Html.TextBoxFor(x=>x.Year)

<input type="submit" value="Search" />

<hr />
@ViewBag.Message
<hr />

@{ var grid = new WebGrid(Model.Results,rowsPerPage:5);}

@grid.GetHtml(tableStyle:"table",htmlAttributes:new {id="tbl"} )

</form>

这是我的控制器:搜索在Index Post方法中发生,它只有我的viewmodel类。

    private ISearchContext _sc;

    public  MyController(ISearchContext sc)
    {
        _dc = dc;
    }

    //
    // GET: /Dava/

    public ActionResult Index()
    {
        var search = new Search();
        ViewBag.Message = "";
        return View(search);
    }

    [HttpPost]
    public ActionResult Index(Search search)
    {

        Search sres = _dc.SearchFromRepository(search);
        ViewBag.Message = String.Format("Count:{0} ",sres.Results.Count);
        return View(sres);
    }

搜索模型类就像:

public class Search
{
    public int Year { get; set; }
    public string Name { get; set; }


    public IList<Item> Results { get; set; }

    public Search()
    {
        Results = new List<Item>();
    }
}

4 个答案:

答案 0 :(得分:9)

解决此问题的一种方法是使用javascript并订阅任何寻呼机链接的点击事件,然后获取所需页面的值,将其注入表单上的隐藏字段并将表单提交给服务器,以便发送其他两个值。

首先,在Page视图模型上添加Search可空整数属性,并在表单中添加相应的隐藏字段,其中包含所选页码:

@Html.HiddenFor(x => x.Page, new { id = "page" })

然后你只需要一个小的javascript片段进入页面来订阅寻呼机链接的.click事件:

$(function () {
    $('tfoot a').click(function () {
        // when the user clicks on any of the pager links
        // try to extract the page number from the link and
        // set the value of the hidden field
        var page = this.href.match(/page=([0-9])+/)[1];
        $('#page').val(page);

        // submit the form so that the POST action is invoked
        // passing along the search criteria (Name and Year) along
        // with the page hidden field value to the Index action
        $('form').submit();

        // cancel the default action of the link which is to simply redirect
        // to the Index action using a GET verb.
        return false;
    });
});

答案 1 :(得分:5)

这是一种不使用JavaScript的解决方法。

我看到的问题是,分页链接不会收到任何必须保留的路由信息​​,例如搜索过滤器。 IMO这是一个公然的疏忽!这里有一点额外的想法可以省去很多头痛!

这种技术“抛弃”WebGrid的内置分页,并使用Helper生成分页链接以及我们想要的宝贵路由数据。

完成后,您只需将WebGrid呈现为网格,并使用Helper创建分页链接。这里的一个优点是你可以把它们放在顶部和底部,我们喜欢这样做。

我试图将类似的CSS用于NuGet为您的解决方案提供的Pager.css中提供的内容。对于你们中的一些人来说,助手应该足够完整,但很容易扩展。

New New New 我刚刚使用Ajax版本更新了帮助程序。我对Razor助手有点n00b,所以我无法弄清楚如何重新考虑使用普通模板;有人请?有一个重要的额外细节是传递AjaxOptions并确保使用POST作为动词,否则你可能不会以正确的控制器方法结束。

助手(App_Code / LocalHelpers.cshtml):

@helper DoPager(System.Web.Mvc.HtmlHelper hh, string pageActionName, WebGrid grid, int maxPageLinks, object rvd) {
<div class="pager">
<div class="pageof">Page <b>@(grid.PageIndex + 1)</b> of <b>@grid.PageCount</b></div>
@if (grid.PageCount > 1) {
<ul>
<li>
@{ RouteValueDictionary rvdp1 = new RouteValueDictionary(rvd);
   rvdp1.Add("Page", 1);
}
@hh.ActionLink("<<", pageActionName, rvdp1)
</li>
@{ int start = Math.Max(0, grid.PageIndex - maxPageLinks / 2); }
@for (int ix = 0; ix + start < grid.PageCount; ix++) {
    int pageno = start + ix + 1;
    var css = hh.Raw(pageno - 1 == grid.PageIndex ? " class=\"highlighted\"" : "");
    RouteValueDictionary rvdp = new RouteValueDictionary(rvd);
    rvdp.Add("Page", pageno);
<li@css>
@hh.ActionLink(pageno.ToString(), pageActionName, rvdp)
</li>
    if (ix >= maxPageLinks) { break; }
}
<li>
@{ RouteValueDictionary rvdpX = new RouteValueDictionary(rvd);
   rvdpX.Add("Page", grid.PageCount);
}
@hh.ActionLink(">>", pageActionName, rvdpX)
</li>
</ul>
}
</div>
}
@helper DoAjaxPager(System.Web.Mvc.AjaxHelper aa, System.Web.Mvc.Ajax.AjaxOptions aopts, System.Web.Mvc.HtmlHelper hh, string pageActionName, WebGrid grid, int maxPageLinks, object rvd) {
<div class="pager">
<div class="pageof">Page <b>@(grid.PageIndex + 1)</b> of <b>@grid.PageCount</b></div>
@if (grid.PageCount > 1) {
<ul>
<li>
@{ RouteValueDictionary rvdp1 = new RouteValueDictionary(rvd);
   rvdp1.Add("Page", 1);
}
@aa.ActionLink("<<", pageActionName, rvdp1, aopts)
</li>
@{ int start = Math.Max(0, grid.PageIndex - maxPageLinks / 2); }
@for (int ix = 0; ix + start < grid.PageCount; ix++) {
    int pageno = start + ix + 1;
    var css = hh.Raw(pageno - 1 == grid.PageIndex ? " class=\"highlighted\"" : "");
    RouteValueDictionary rvdp = new RouteValueDictionary(rvd);
    rvdp.Add("Page", pageno);
<li@css>
@aa.ActionLink(pageno.ToString(), pageActionName, rvdp, aopts)
</li>
    if (ix >= maxPageLinks) { break; }
}
<li>
@{ RouteValueDictionary rvdpX = new RouteValueDictionary(rvd);
   rvdpX.Add("Page", grid.PageCount);
}
@aa.ActionLink(">>", pageActionName, rvdpX, aopts)
</li>
</ul>
}
</div>
}

查看:

<center>
@LocalHelpers.DoPager(Html, "Index", grid, 10, new { CurrentFilter = ViewBag.CurrentFilter })
</center>
@grid.Table(
    tableStyle: "centerit",
    columns: grid.Columns(
        grid.Column(format: @<span>@Html.ActionLink("Edit", "Edit", new { id = item.ID }) | @Html.ActionLink("Details", "Details", new { id = item.ID }) | @Html.ActionLink("Delete", "Delete", new { id = item.ID })</span>),
            grid.Column("PartNumber", "Part Number"),
            grid.Column("Description", "Description"),
            grid.Column("Regex", "Regex")
            )
        )
<center>
@LocalHelpers.DoPager(Html, "Index", grid, 10, new { CurrentFilter = ViewBag.CurrentFilter })
</center>

在我看来,我正在回收“CurrentFilter”以了解要过滤的内容。这连接到Controller Action(未图示)。

答案 2 :(得分:3)

确定。我有一个更优雅的解决方案,使用AJAX和部分视图,应该一劳永逸地解决这个问题

这是我的模特:

public class SearchResultModel
{
        public string SearchText{ get; set; }
        public List<YourObject> Results { get; set; }
        public int TotalResults { get; set; }
}

搜索视图的结构如下:

@model SearchResultModel
@using (Ajax.BeginForm("SearchAction", "SearchController", new AjaxOptions{UpdateTargetId = "data-grid", HttpMethod="Post"}))
{
        @Html.TextBoxFor(m => m.SearchText)
        <input class="myButton" type="submit" value="Search" />
}
<br />
<div id="data-grid">
       @Html.Partial("SearchResults", new SearchResultModel())
</div>

SearchResults局部视图是:

@model SearchResultModel
@{
    if (Model.Results != null && Model.Results.Count > 0)
    {
            var grid = new WebGrid(canPage: true, rowsPerPage: 10, canSort: true, ajaxUpdateContainerId: "grid");
            grid.Bind(Model.Results, rowCount: Model.TotalResults, autoSortAndPage: false);
            grid.Pager(WebGridPagerModes.All);

            @grid.GetHtml(htmlAttributes: new { id = "grid" },
            columns: grid.Columns(
                grid.Column("YourColumn1"),
                grid.Column("YourColumn2"),
                grid.Column("YourColumn3")
            ),
            tableStyle: "datatable",
                rowStyle: "datatable-normal",
                    alternatingRowStyle: "datatable-alt"
            );
    }
    else
    {
    <span>No Results</span>
    }
}

最后,控制器是:

public class SearchController
{
        public ActionResult SearchAction(SearchResultModel model)
        {
            return RedirectToAction("SearchResults", new { id = model.SearchText });
        }

        public ActionResult SearchResults(string id)
        {
            string searchText = id;
            int page = 1;
            if(Request["page"] != null)
                int.TryParse(Request["page"], out page);

            SearchResultModel model = new SearchResultModel();
            //Populate model according to search text and page number
            //........
            //........
            return PartialView(model);
        }
}

希望这有助于节省一些时间和焦虑!

答案 3 :(得分:0)

我的回答包括保持您对Session的搜索,仅此而已。 解决方案很好,因为您可以根据您的实际情况调整它,并且不需要特定的类或JQuery。

神奇的技巧发生在你的Index ActionResult(或你的默认ActionResult,它将使网格页面呈现其默认行为)。

代码示例:

    [HttpGet]
    public ActionResult Index()//My default action result that will render the grid at its default situation
    {
        SearchViewModel model = new SearchViewModel(); 

        if (Request.IsAjaxRequest()) //First trick is here, this verification will tell you that someone sorted or paged the grid.
        {
            if (Session["SearchViewModel"] != null) //If session is not empty, you will get the last filtred values from it.
                model = (SearchViewModel)Session["SearchViewModel"];
        }
        else // If it is not an AjaxRequest, you have to clear your Session, so new requests to Index with default behavior won't display filtred values.
        {
            Session["SearchViewModel"] = null;
        }

        model.GridResult = ExecuteFilter(model); // OPITIONAL! This code dependes on how is your real world situation. Just remember that you need to return a default behavior grid if the request was not called by the WebGrid, or return filtred results if WebGrid requested.
        return View(model);
    }

所以,这将是你的默认ActionResult。它将验证WebGrid分页或排序事件是否调用了请求,以确定是返回filtred结果还是返回正常行为结果。

下一步是搜索POST ActionResult:

    [HttpPost]
    public ActionResult Index(SearchViewModel pesquisa) // IMPORTANT!! It is necessary to be the SAME NAME of your GET ActionResult. The reason for that I know, but won't discuss here because it goes out of the question.
    {
        SearchViewModel model = new SearchViewModel();
        model.GridResult = ExecuteFilter(pesquisa); // Execute your filter
        Session["SearchViewModel"] = model; //Save your filter parameters on Session.
        return View("Index", model);
    }

多数民众赞成。 Index.cshtml没有任何技巧。只是一个SearchForm到ActionResult索引,将我的SearchViewModel作为参数传递。

为什么这个解决方案有效?

好吧,当您单击以进行排序或分页时,WebGrid会执行类似于此的JavaScript:

$('#yourGrid').load('it pass the url used to display your current Page, and some paging or sorting parameters, but those are used by the WebGrid')

由于它执行.load()方法,因此请求将是GET,并且将命中您的Index GET ActionResult。但它是一个AJAX调用,所以我们的魔术技巧将使用你在Session上保存的参数再次执行过滤器。

我提醒的唯一细节是关于您的默认网格行为。 GET索引ActionResult必须返回有效的网格结果,无论是否有会话过滤器。