如何将 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 具有 DATEDISPFROMOFFICERNAME 属性,

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 将帮助您获得更加动态和干净的排序代码。

  • 要了解更多关于这种 SearchModelBusinessLogic 技术的好处,请查看 Filter/Search using Multiple Fields - ASP.NET MVC

  • 此要求的一个常见场景是,例如,寻呼机的页面链接或显示搜索和排序结果的网格的列链接。如果您在网格上使用此技术,分页链接应保留请求之间的搜索选项和排序选项。但是为了生成列 header 链接,对于每一列你应该使用不同的合适的排序顺序和排序列;同样对于其名称等于当前排序列的列,排序顺序应与当前排序顺序相反。此外,列 headers 还应保留页面索引。