2016-11-28 1 views
0

J'essaie d'implémenter le filtrage et la pagination dans un contrôleur MVC. Je transmets des informations à View en utilisant ViewBag.Passer le filtre de l'objet de la vue au contrôleur

Classe de filtre est le suivant:

public class Criteria 
{ 
    public int? SnapshotKey { get; set; } 
    public string Delq { get; set; } 

    public override string ToString() 
    { 
     string[] Ares = new string[2]; 
     if (SnapshotKey.HasValue) 
      Ares[0] = "SnapshotKey=" + SnapshotKey.ToString(); 
     if (!String.IsNullOrWhiteSpace(Delq)) 
      Ares[1] = "Delq=" + Delq; 

     return String.Join("&", Ares.Where(s => !string.IsNullOrWhiteSpace(s))); 
    } 
} 

Ma méthode de commande est comme ceci:

public ActionResult Search(Criteria filter, string filterString, 
          int pageNo = 1, int pageSize = 5) 
{ 
    using (DemoDBEntities db = new DemoDBEntities()) 
    { 
     var list = db.BMH.AsQueryable(); 
     if (filter != null) 
     { 
      if (filter.SnapshotKey.HasValue) 
       list = list.Where(r => r.SnapshotKey == filter.SnapshotKey.Value); 
      if (!String.IsNullOrWhiteSpace(filter.Delq)) 
       list = list.Where(r => r.Delq == filter.Delq); 
     } 
     list = list.OrderBy(r=>r.SnapshotKey).Skip((pageNo - 1) * pageSize).Take(pageSize); 
     ViewBag.Criteria = filter.ToString(); 
     ViewBag.CriteriaString = filterString; 
     ViewBag.PageNo = pageNo; 
     return View(list.ToList()); 
    } 
} 

AFAIK, je ne peux pas passer ViewBag comme un objet à un contrôleur, c'est pourquoi je filter.ToString () pour stocker le filtre actuel.

Dans la vue, j'ai ci-dessous le lien pour aller à la page spécifique, tout en préservant le filtre actuel. Donc, lorsque je reviens de View, j'obtiens le filtre actuel sous forme de chaîne. Maintenant, dans le contrôleur j'ai besoin de convertir la chaîne en classe Criteria. C'est faisable mais je cherche une façon plus décente de faire ce dont j'ai besoin.

+1

Pourquoi ne pas simplement 'nouveau {SnapshotKey = ViewBag.SnapshotKey, Delq = ViewBag.Delq, pageno = ViewBag.PageNo + 1 ....} '(et vous pouvez le simplifier encore plus en ajoutant' pageNo' et 'pageSize' à votre modèle de sorte que la méthode POST est juste' public ActionResult Search (filtre Criteria) ' –

+0

J'essaie de ne pas dépendre – FLICKER

+0

Si vous ajoutez un nouveau champ, alors vous devez mettre à jour la méthode '.ToString()' (c'est-à-dire si vous avez ajouté un nouveau champ à la classe Criteria). quelque chose doit être mis à jour).Vous pouvez toujours ajouter 'pageNo' et' pageSize' à votre modèle 'Criteria' et les inclure dans la méthode' ToString() ', puis générer simplement le lien en utilisant' Next Page ' –

Répondre

1

La valeur de filterString dans la méthode Search() sera une chaîne dans le format name=value&name=value... pour que vous puissiez en utilisant d'abord String.Split() (sur le caractère &) pour créer un tableau de name=value éléments, puis diviser à nouveau (sur le caractère =) pour obtenir les noms et les valeurs de la propriété, mais tout cela devient désordonné et il serait plus facile de simplement construire toute la chaîne de requête et de la lier directement à votre modèle Criteria.

changer le modèle pour inclure toutes les propriétés, y compris pageNo et pageSize`

public class Criteria 
{ 
    public Criteria() // perhaps add some defaults? 
    { 
     PageNo = 1; 
     PageSize = 5; 
    } 
    public int? SnapshotKey { get; set; } 
    public string Delq { get; set; } 
    public int PageNo { get; set; } 
    public int PageSize { get; set; } 
    .... // see method below 
} 

Ensuite, pour le rendre souple et vous permettre d'ajouter plus de propriétés « critères », la réflexion d'utiliser pour construire la chaîne de requête

public string ToQueryString(int pageIncrement) 
    { 
     List<string> propValues = new List<string>(); 
     foreach(var prop in GetType().GetProperties()) 
     { 
      var name = prop.Name; 
      var value = prop.GetValue(this); 
      if (name == "PageNo") 
      { 
       value == (int)value + pageIncrement; 
      } 
      if (value != null) 
      { 
       propValues .Add(String.Format("{0}={1}", name, value)); 
      } 
     } 
     return "?" + String.Join("&", propValues); 
    } 

le code dans le contrôleur sera alors

public ActionResult Search(Criteria filter) 
{ 
    using (DemoDBEntities db = new DemoDBEntities()) 
    { 
     var list = db.BMH.AsQueryable(); 
     if (filter != null) 
     { 
      if (filter.SnapshotKey.HasValue) 
       list = list.Where(r => r.SnapshotKey == filter.SnapshotKey.Value); 
      if (!String.IsNullOrWhiteSpace(filter.Delq)) 
       list = list.Where(r => r.Delq == filter.Delq); 
     } 
     list = list.OrderBy(r => r.SnapshotKey).Skip((filter.PageNo - 1) * pageSize).Take(filter.PageSize); 
     ViewBag.Criteria = filter; 
     return View(list.ToList()); 
    } 
} 

puis dans la vue

<a href="@Url.Action("Search")@ViewBag.Criteria.ToQueryString(-1)">Previous</a> 
<a href="@Url.Action("Search")@ViewBag.Criteria.ToQueryString(1)">Next</a> 

Notez également que vous pouvez simplement utiliser

@Html.ActionLink("Next", "Search", (yourAssembly.Criteria)ViewBag.Criteria) 

en supposant que Criteria ne contient que de simples propriétés, ce qui signifie la méthode ToQueryString() n'est pas nécessaire. Cependant, vous devrez augmenter/diminuer la valeur de la propriété PageNo avant d'utiliser ActionLink(), par exemple

@{ var criteria = (yourAssembly.Criteria)ViewBag.Criteria; } 
@{ criteria.PageNo = @criteria.PageNo - 1; } 
@Html.ActionLink("Previous", "Search", criteria) 
@{ criteria.PageNo = @criteria.PageNo + 2; } 
@Html.ActionLink("Next", "Search", criteria) 
+0

Bien fait, merci! – FLICKER