如何将 ViewBag 中的一些 objects 传递给 Action? - 保留搜索、排序和分页选项
How can I pass some objects in ViewBag to the Action? - Preserve search, sort and paging options
我有一个显示搜索结果并在分页列表中排序的视图。我将列 headers 添加为链接,以使用户能够以这种方式基于列进行排序:
<tr>
<th>
@Html.ActionLink("Reference No", "Index",
new { sortOrder = ViewBag.RefNoSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
@Html.ActionLink("Category", "Index",
new { sortOrder = ViewBag.CatSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
... Some other columns
</tr>
我还用这种方式添加了寻呼机:
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
@Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
我使用的动作是这样的:
private Registry_fssEntities db = new Registry_fssEntities();
public ActionResult Index(string sortOrder, SearchTransacModel searchModel, SearchTransacModel currentFilter, int? page)
{
var model = from c in db.TRANSACs
select c;
ViewBag.CurrentSort = sortOrder;
ViewBag.DispDateSortParm = String.IsNullOrEmpty(sortOrder) ? "DispDate" : "";
ViewBag.RefNoSortParm = sortOrder == "RefNo" ? "RefNo_desc" : "RefNo";
ViewBag.CatSortParm = sortOrder == "Cat" ? "Cat_desc" : "Cat";
if (searchModel.DATEDISPFROM != null || searchModel.DATEDISPTO != null || searchModel.DATEDISPFROM != null || searchModel.OFFICERNAME != null || searchModel.APPNAME != null || searchModel.REFNO != null || searchModel.PROCNAME != null)
{
page = 1;
}
else
{
searchModel = currentFilter;
}
if (searchModel != null)
{
if (!String.IsNullOrEmpty(searchModel.DATEDISPFROM))
{
ViewBag.DispFrom = searchModel.DATEDISPFROM.ToString();
}
else
{
searchModel.DATEDISPFROM = "01/01/" + DateTime.Today.Year.ToString();
ViewBag.DispFrom = "01/01/" + DateTime.Today.Year.ToString();
}
if (!String.IsNullOrEmpty(searchModel.DATEDISPTO))
{
ViewBag.DispTo = searchModel.DATEDISPTO.ToString();
}
else
{
searchModel.DATEDISPTO = "31/12/" + DateTime.Today.Year.ToString();
ViewBag.DispTo = "31/12/" + DateTime.Today.Year.ToString();
}
}
if (searchModel != null)
{
var tRANSACs = new TransacBusinessLogic();
model = tRANSACs.GetTransacs(searchModel);
ViewBag.currentFilter = searchModel;
}
List<TransacViewModel> TransactionList = new List<TransacViewModel>();
foreach (var item in model)
{
TransactionList.Add(new TransacViewModel {
TRANSID = item.TRANSID,
REFNO = item?.REFNO,
PROCESS = item?.PROCESS,
//CATEGORY = item.PROCESS.CATEGORY,
DOCTYPE = item?.DOCTYPE,
DATEDEL = returnasdate(item.DATEDEL),
DATEDISP = returnasdate(item.DATEDISP),
APPNAME = item?.APPNAME,
OFFICER = item?.OFFICER,
DATEREG = item.DATEREG
});
}
switch (sortOrder)
{
case "DispDate":
TransactionList = TransactionList.OrderBy(x => x.DATEDISP).ToList();
break;
case "RefNo":
TransactionList = TransactionList.OrderBy(t => t.REFNO).ToList();
break;
case "RefNo_desc":
TransactionList = TransactionList.OrderByDescending(t => t.PROCESS.CATEGORY.DETAIL).ToList();
break;
case "Cat":
TransactionList = TransactionList.OrderBy(t => t.PROCESS.CATEGORY.DETAIL).ToList();
break;
case "Cat_desc":
TransactionList = TransactionList.OrderByDescending(t => t.REFNO).ToList();
break;
default:
TransactionList = TransactionList.OrderByDescending(t => t.DATEDISP).ToList();
break;
}
int pageSize = 6;
int pageNumber = (page ?? 1);
return View(TransactionList.ToPagedList(pageNumber, pageSize));
}
SearchTransacModel
是一个模型,用于在我将搜索参数传递给控制器时包含它们。
当我通过提交按钮提交搜索表单时它工作正常,并且我使用 ViewBag
将此搜索条件发送回视图,如下所示:ViewBag.currentFilter = searchModel;
但是当我单击任何排序操作链接时,我丢失了搜索参数。即当我到达控制器时 currentFilter
为空。
我将 currentFilter 作为查询字符串传递并为其分配搜索模型,就像在这种情况下一样:
@Html.ActionLink("Reference No", "Index", new { sortOrder = ViewBag.RefNoSortParm, currentFilter = ViewBag.CurrentFilter })
有人可以帮忙吗?顺便说一句,我是 MVC 的新手。
您无法将 viewbag 中的值传回控制器。
相反,您应该在视图中使用模型绑定将信息传递给您的 post 方法。
您可以在从viewbag 读取后在querystring 中传递过滤值。假设您的 SearchTransacModel
class 具有 DATEDISPFROM
和 OFFICERNAME
属性,
public class SearchTransacModel
{
public string DATEDISPFROM { set; get; }
public string OFFICERNAME { set; get; }
}
您可以将值作为路由值发送,其中键将是 属性 名称(属于 SearchTransacModel class),值将是您拥有的值。
@{
var filter = ViewBag.CurrentFilter as SearchTransacModel;
}
@Html.ActionLink("Reference No", "Index", new { sortOrder = ViewBag.RefNoSortParm,
DATEDISPFROM = filter!=null? filter.DATEDISPFROM:"",
OFFICERNAME = filter != null ? filter.OFFICERNAME : "" })
模型绑定器将能够将查询字符串值映射到您的 currentFilter
对象。
我建议您不要使用相同类型的 2 个参数(currentFilter 和 searchModel)。
虽然 ViewBag 可用于实现您正在寻找的东西,但它仍然不是为此目的而设计的。
相反,您应该创建一个模型并使用它与您的控制器和视图进行通信。
更改并对齐您的 return 模型,使其更大一些。
public TransactionsViewModel
{
public SearchTransacModel SearchModel { get; set; }
public List<TransacViewModel> TransactionList { get; set; }
}
现在您可以放弃使用 ViewBag.currentFilter 并仅使用此模型。
您可以使用这样的操作:
public ActionResult Index(SearchModel searchModel, string sortColumn, string sortOrder)
{
ViewBag.SearchModel = searchModel;
ViewBag.SortColumn= sortColumn;
ViewBag.SortOrder = sortOrder;
var business = new BusinessLogic();
var model = business.Search(searchModel, sortColumn, sortOrder);
return View(model);
}
您可以通过这种方式简单地混合一些路由值。这样,搜索选项和排序选项将在请求之间保留:
@{
var routeValues = new RouteValueDictionary(ViewBag.SearchModel ?? new { });
routeValues["sortColumn"] = ViewBag.SortColumn;
routeValues["sortOrder"] = ViewBag.SortOrder;
}
@Html.ActionLink("Link Text", "Action", routeValues);
注:
根据这个答案中的想法,您可以简单地创建一个混合甚至 2 objects 的方法来为您创建路由值。
您还可以将排序选项封装在SortOption
class 中,然后将其放入ViewBag
并在模型绑定中使用它。
System.Linq.Dynamic
将帮助您获得更加动态和干净的排序代码。
要了解更多关于这种 SearchModel
和 BusinessLogic
技术的好处,请查看 Filter/Search using Multiple Fields - ASP.NET MVC
此要求的一个常见场景是,例如,寻呼机的页面链接或显示搜索和排序结果的网格的列链接。如果您在网格上使用此技术,分页链接应保留请求之间的搜索选项和排序选项。但是为了生成列 header 链接,对于每一列你应该使用不同的合适的排序顺序和排序列;同样对于其名称等于当前排序列的列,排序顺序应与当前排序顺序相反。此外,列 headers 还应保留页面索引。
我有一个显示搜索结果并在分页列表中排序的视图。我将列 headers 添加为链接,以使用户能够以这种方式基于列进行排序:
<tr>
<th>
@Html.ActionLink("Reference No", "Index",
new { sortOrder = ViewBag.RefNoSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
@Html.ActionLink("Category", "Index",
new { sortOrder = ViewBag.CatSortParm, currentFilter = ViewBag.CurrentFilter })
</th>
... Some other columns
</tr>
我还用这种方式添加了寻呼机:
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
@Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
我使用的动作是这样的:
private Registry_fssEntities db = new Registry_fssEntities();
public ActionResult Index(string sortOrder, SearchTransacModel searchModel, SearchTransacModel currentFilter, int? page)
{
var model = from c in db.TRANSACs
select c;
ViewBag.CurrentSort = sortOrder;
ViewBag.DispDateSortParm = String.IsNullOrEmpty(sortOrder) ? "DispDate" : "";
ViewBag.RefNoSortParm = sortOrder == "RefNo" ? "RefNo_desc" : "RefNo";
ViewBag.CatSortParm = sortOrder == "Cat" ? "Cat_desc" : "Cat";
if (searchModel.DATEDISPFROM != null || searchModel.DATEDISPTO != null || searchModel.DATEDISPFROM != null || searchModel.OFFICERNAME != null || searchModel.APPNAME != null || searchModel.REFNO != null || searchModel.PROCNAME != null)
{
page = 1;
}
else
{
searchModel = currentFilter;
}
if (searchModel != null)
{
if (!String.IsNullOrEmpty(searchModel.DATEDISPFROM))
{
ViewBag.DispFrom = searchModel.DATEDISPFROM.ToString();
}
else
{
searchModel.DATEDISPFROM = "01/01/" + DateTime.Today.Year.ToString();
ViewBag.DispFrom = "01/01/" + DateTime.Today.Year.ToString();
}
if (!String.IsNullOrEmpty(searchModel.DATEDISPTO))
{
ViewBag.DispTo = searchModel.DATEDISPTO.ToString();
}
else
{
searchModel.DATEDISPTO = "31/12/" + DateTime.Today.Year.ToString();
ViewBag.DispTo = "31/12/" + DateTime.Today.Year.ToString();
}
}
if (searchModel != null)
{
var tRANSACs = new TransacBusinessLogic();
model = tRANSACs.GetTransacs(searchModel);
ViewBag.currentFilter = searchModel;
}
List<TransacViewModel> TransactionList = new List<TransacViewModel>();
foreach (var item in model)
{
TransactionList.Add(new TransacViewModel {
TRANSID = item.TRANSID,
REFNO = item?.REFNO,
PROCESS = item?.PROCESS,
//CATEGORY = item.PROCESS.CATEGORY,
DOCTYPE = item?.DOCTYPE,
DATEDEL = returnasdate(item.DATEDEL),
DATEDISP = returnasdate(item.DATEDISP),
APPNAME = item?.APPNAME,
OFFICER = item?.OFFICER,
DATEREG = item.DATEREG
});
}
switch (sortOrder)
{
case "DispDate":
TransactionList = TransactionList.OrderBy(x => x.DATEDISP).ToList();
break;
case "RefNo":
TransactionList = TransactionList.OrderBy(t => t.REFNO).ToList();
break;
case "RefNo_desc":
TransactionList = TransactionList.OrderByDescending(t => t.PROCESS.CATEGORY.DETAIL).ToList();
break;
case "Cat":
TransactionList = TransactionList.OrderBy(t => t.PROCESS.CATEGORY.DETAIL).ToList();
break;
case "Cat_desc":
TransactionList = TransactionList.OrderByDescending(t => t.REFNO).ToList();
break;
default:
TransactionList = TransactionList.OrderByDescending(t => t.DATEDISP).ToList();
break;
}
int pageSize = 6;
int pageNumber = (page ?? 1);
return View(TransactionList.ToPagedList(pageNumber, pageSize));
}
SearchTransacModel
是一个模型,用于在我将搜索参数传递给控制器时包含它们。
当我通过提交按钮提交搜索表单时它工作正常,并且我使用 ViewBag
将此搜索条件发送回视图,如下所示:ViewBag.currentFilter = searchModel;
但是当我单击任何排序操作链接时,我丢失了搜索参数。即当我到达控制器时 currentFilter
为空。
我将 currentFilter 作为查询字符串传递并为其分配搜索模型,就像在这种情况下一样:
@Html.ActionLink("Reference No", "Index", new { sortOrder = ViewBag.RefNoSortParm, currentFilter = ViewBag.CurrentFilter })
有人可以帮忙吗?顺便说一句,我是 MVC 的新手。
您无法将 viewbag 中的值传回控制器。
相反,您应该在视图中使用模型绑定将信息传递给您的 post 方法。
您可以在从viewbag 读取后在querystring 中传递过滤值。假设您的 SearchTransacModel
class 具有 DATEDISPFROM
和 OFFICERNAME
属性,
public class SearchTransacModel
{
public string DATEDISPFROM { set; get; }
public string OFFICERNAME { set; get; }
}
您可以将值作为路由值发送,其中键将是 属性 名称(属于 SearchTransacModel class),值将是您拥有的值。
@{
var filter = ViewBag.CurrentFilter as SearchTransacModel;
}
@Html.ActionLink("Reference No", "Index", new { sortOrder = ViewBag.RefNoSortParm,
DATEDISPFROM = filter!=null? filter.DATEDISPFROM:"",
OFFICERNAME = filter != null ? filter.OFFICERNAME : "" })
模型绑定器将能够将查询字符串值映射到您的 currentFilter
对象。
我建议您不要使用相同类型的 2 个参数(currentFilter 和 searchModel)。
虽然 ViewBag 可用于实现您正在寻找的东西,但它仍然不是为此目的而设计的。
相反,您应该创建一个模型并使用它与您的控制器和视图进行通信。
更改并对齐您的 return 模型,使其更大一些。
public TransactionsViewModel
{
public SearchTransacModel SearchModel { get; set; }
public List<TransacViewModel> TransactionList { get; set; }
}
现在您可以放弃使用 ViewBag.currentFilter 并仅使用此模型。
您可以使用这样的操作:
public ActionResult Index(SearchModel searchModel, string sortColumn, string sortOrder)
{
ViewBag.SearchModel = searchModel;
ViewBag.SortColumn= sortColumn;
ViewBag.SortOrder = sortOrder;
var business = new BusinessLogic();
var model = business.Search(searchModel, sortColumn, sortOrder);
return View(model);
}
您可以通过这种方式简单地混合一些路由值。这样,搜索选项和排序选项将在请求之间保留:
@{
var routeValues = new RouteValueDictionary(ViewBag.SearchModel ?? new { });
routeValues["sortColumn"] = ViewBag.SortColumn;
routeValues["sortOrder"] = ViewBag.SortOrder;
}
@Html.ActionLink("Link Text", "Action", routeValues);
注:
根据这个答案中的想法,您可以简单地创建一个混合甚至 2 objects 的方法来为您创建路由值。
您还可以将排序选项封装在
SortOption
class 中,然后将其放入ViewBag
并在模型绑定中使用它。System.Linq.Dynamic
将帮助您获得更加动态和干净的排序代码。要了解更多关于这种
SearchModel
和BusinessLogic
技术的好处,请查看 Filter/Search using Multiple Fields - ASP.NET MVC此要求的一个常见场景是,例如,寻呼机的页面链接或显示搜索和排序结果的网格的列链接。如果您在网格上使用此技术,分页链接应保留请求之间的搜索选项和排序选项。但是为了生成列 header 链接,对于每一列你应该使用不同的合适的排序顺序和排序列;同样对于其名称等于当前排序列的列,排序顺序应与当前排序顺序相反。此外,列 headers 还应保留页面索引。