Asp.net mvc 3 Asp.net Mvc3 webgrid和分页
我正在努力学习Asp.NETMVC。我知道它不同于形式,我可能需要改变我的思维方式。我的问题是关于webgrid的。当我将webgrid添加到我的页面并用Post点击搜索按钮时,它会用寻呼机呈现表格,等等。但寻呼机上的链接并不是发布表单,它们只是链接,我丢失了表单的所有数据 控制器有两种索引方法,一种用于get,另一种用于post。对于get,我什么都不做,我只是在本例中创建了新的viewmodel搜索类,并将其设置为view。对于我的post方法,我抓取我的视图模型进行搜索,并将填充的viewmodel设置为view 问题:webgrid将寻呼机呈现为链接,因此它将进入get的索引,但由于它不是post请求,我没有填写任何表单字段,并且我的搜索将不会提供完全相同的结果集 也许示例代码可以更好地解释它 视图: 搜索模型类类似于: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
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')