Asp.net mvc 3 Asp.net Mvc3 webgrid和分页

Asp.net mvc 3 Asp.net Mvc3 webgrid和分页,asp.net-mvc-3,webgrid,Asp.net Mvc 3,Webgrid,我正在努力学习Asp.NETMVC。我知道它不同于形式,我可能需要改变我的思维方式。我的问题是关于webgrid的。当我将webgrid添加到我的页面并用Post点击搜索按钮时,它会用寻呼机呈现表格,等等。但寻呼机上的链接并不是发布表单,它们只是链接,我丢失了表单的所有数据 控制器有两种索引方法,一种用于get,另一种用于post。对于get,我什么都不做,我只是在本例中创建了新的viewmodel搜索类,并将其设置为view。对于我的post方法,我抓取我的视图模型进行搜索,并将填充的view

我正在努力学习Asp.NETMVC。我知道它不同于形式,我可能需要改变我的思维方式。我的问题是关于webgrid的。当我将webgrid添加到我的页面并用Post点击搜索按钮时,它会用寻呼机呈现表格,等等。但寻呼机上的链接并不是发布表单,它们只是链接,我丢失了表单的所有数据

控制器有两种索引方法,一种用于get,另一种用于post。对于get,我什么都不做,我只是在本例中创建了新的viewmodel搜索类,并将其设置为view。对于我的post方法,我抓取我的视图模型进行搜索,并将填充的viewmodel设置为view

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

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

视图:

搜索模型类类似于:

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>();
    }
}
公共类搜索
{
公共整数年{get;set;}
公共字符串名称{get;set;}
公共IList结果{get;set;}
公开检索()
{
结果=新列表();
}
}

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

因此,首先在
搜索
视图模型上添加一个
页面
可为空的整数属性,并在表单中添加一个相应的隐藏字段,该字段将包含所选页码:

@Html.HiddenFor(x => x.Page, new { id = "page" })
然后,您只需在页面中插入一个小javascript片段,即可订阅。单击寻呼机链接的事件:

$(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;
    });
});

这里有一个不使用JavaScript的变通方法

在我看来,问题在于,分页链接没有收到任何必须保留的路由信息,比如搜索过滤器。依我看,这是公然的疏忽!在这里多考虑一点就可以省去很多头痛

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

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

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

New我刚刚用Ajax版本更新了助手。我是一个有剃须刀助手的小n00b,所以我不知道如何重新考虑它以使用一个通用模板;有人吗?重要的额外细节是传入
AjaxOptions
,并确保使用
POST
作为动词,否则可能无法使用正确的控制器方法

助手(应用程序代码/LocalHelpers.cshtml):

@helper-DoPager(System.Web.Mvc.HtmlHelper-hh,string-pageActionName,WebGrid-grid,int-maxPageLinks,object-rvd){
第@页(grid.PageIndex+1)共@grid.PageCount
@如果(grid.PageCount>1){
  • @{RouteValueDictionary rvdp1=新的RouteValueDictionary(rvd); rvdp1.添加(“第1页”); } @hh.ActionLink(“>”,pageActionName,rvdpX)
} } @helper DoAjaxPager(System.Web.Mvc.AjaxHelper aa、System.Web.Mvc.Ajax.AjaxOptions aopts、System.Web.Mvc.HtmlHelper hh、字符串pageActionName、WebGrid网格、int-maxPageLinks、对象rvd){ 第@页(grid.PageIndex+1)共@grid.PageCount @如果(grid.PageCount>1){
  • @{RouteValueDictionary rvdp1=新的RouteValueDictionary(rvd); rvdp1.添加(“第1页”); } @aa.ActionLink(“>”,pageActionName,rvdpX,aopts)
} }
视图:


@DoPager(Html,“索引”,网格,10,新的{CurrentFilter=ViewBag.CurrentFilter})
@表格(
表样式:“centerit”,
列:grid.columns(
grid.Column(格式:@@Html.ActionLink(“编辑”、“编辑”、新建{id=item.id})|@Html.ActionLink(“详细信息”、“详细信息”、新建{id=item.id})|@Html.ActionLink(“删除”、“删除”、新建{id=item.id})),
网格栏(“零件号”、“零件号”),
网格栏(“说明”、“说明”),
网格列(“正则表达式”、“正则表达式”)
)
)
@DoPager(Html,“索引”,网格,10,新的{CurrentFilter=ViewBag.CurrentFilter})

在我看来,我是在循环使用“CurrentFilter”来知道要过滤什么。这将连接到控制器操作(未显示)。

正常。我有一个更优雅的解决方案,它使用AJAX和局部视图,应该可以一劳永逸地解决这个问题

这是我的模型:

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

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

我的答案是让您的搜索保持在会话中,仅此而已。 这个解决方案很好,因为您可以根据实际情况调整它,并且不需要特定的类或JQuery

这个魔术发生在索引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);
    }
因此,这将是您的默认操作结果。它将验证请求是否由WebGrid分页或排序事件调用,以确定返回的是过滤结果还是正常行为结果

下一步是搜索帖子操作结果:

    [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);
    }
就这样。cshtml没有任何技巧。只需向ActionResult索引发送一个SearchForm,并将我的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,并将命中您的索引GET ActionResult。但这是一个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>
@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);
        }
}
    [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);
    }
    [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);
    }
$('#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')