8

Ho una vista parziale in un progetto MVC 4, che è fortemente digitato. Prende una collezione IEnumerable di una tabella di un database. In quella tabella ci sono ID, Nomi e ParentID per memorizzare la connessione gerarchica tra i record. Il punto di vista che chiama la vista parziale è anche fortemente tipizzato, ci vuole l'intero database come il modello, e passa la tabella Categorie per la vista parziale, come una raccolta enumerabile:ASP.NET MVC 4 che genera una vista ad albero con vista parziale ricorsiva

@Html.Partial("_TreeCategories", @Model.Categories.ToList()) 

E in vista parziale, I voglio prima prendere i nodi radice, così posso estendere l'intero albero in modo ricorsivo. Nella tabella del database, tutti i record sono considerati come nodi radice con un ParentID == null.
Quindi in generale, il mio modo di fare questo sarà simile:

@model IEnumerable<TreeCollections.OpenAccess.Category> 

@if (Model.ToList().Count >= 0) 
    { 
    @if (Model.ToList()[0].Parent_id == null) 
    { 
     <text><ul id="navigation"></text> 
    } 

    @foreach (var node in @Model) 
    { 
     <li><a href="[email protected]">@node.Name</a> 
      @foreach (var subNode in @Model.Where(s => s.Parent_id == node.Id)) 
      { 
       @Html.Partial("_TreeCategories", subNode) 
      } 
     </li> 
    } 
    @if (Model.ToList()[0].Parent_id == null) 
    { 
     </ul> 
    } 
} 

Così ho verificare se ParentID del primo elemento del modello è nullo, e se lo è, allora dovrebbe creare un < ul> tag con l'id "navigazione", quindi il plugin jquery può riconoscere che è pensato per essere un controllo ad albero. Quindi crea un tag lista con una chiamata ricorsiva all'interno. La vista parziale chiamata in modo ricorsivo prende i figli del nodo come modello. Infine, se siamo arrivati ​​alla fine del rendering della vista parziale, e siamo al "livello radice", dovremmo scrivere un tag 01>
Ci sono alcuni problemi, tuttavia. Innanzitutto, alla fine, quel tag di elenco non ordinato di chiusura è sbagliato, VS non riesce a trovare il tag di inizio corrispondente per quello. In secondo luogo, non so perché, ma nella parte superiore, posso inserire l'avviatore < tra tag e non posso farlo nel tag di chiusura di seguito. Ma non sono nemmeno sicuro di questi tag < ul, anche quelli mi sembrano sbagliati.

Per favore, aiutami, sono bloccato con questo per giorni ora.

risposta

15

uomo, hai un po 'di casino qui. sento il tuo dolore nel rimanere bloccato

vedere se questo fa galleggiare la vostra barca.

è necessario un valore di inizializzazione per tenere traccia di ciò che si sta cercando nell'elenco quando si esegue la ricorsione sulla stessa lista. è meglio fare una mappatura dei figli genitori nella classe, ma questo è stato divertente da fare data la tua struttura e dovrebbe fare il trucco.

modelle

namespace trash.Models 
{ 
    public class Category 
    { 
     public int ID { get; set; } 
     public int? Parent_ID { get; set; } 
     public string Name {get; set;} 
    } 

    public class SeededCategories 
    { 
     public int? Seed { get; set; } 
     public IList<Category> Categories { get; set; } 
    } 
} 

Controller (NOTA: si inizia la catena di ricorsione impostando la proprietà Seed su null, che raccoglierà tutti i genitori nulli)

namespace trash.Controllers 
{ 
    public class HomeController : Controller 
    { 
     public ActionResult Index() 
     { 
      IList<trash.Models.Category> categories = new List<trash.Models.Category>(); 
      categories.Add(new trash.Models.Category { ID = 1, Parent_ID = null, Name = "Top1" }); 
      categories.Add(new trash.Models.Category { ID = 2, Parent_ID = null, Name = "Top2" }); 
      categories.Add(new trash.Models.Category { ID = 3, Parent_ID = 1, Name = "Top1Ring1" }); 
      categories.Add(new trash.Models.Category { ID = 4, Parent_ID = 1, Name = "Top1Ring2" }); 

      trash.Models.SeededCategories model = new Models.SeededCategories { Seed = null, Categories = categories }; 
      return View(model); 
     } 
    } 
} 

Visualizzazioni Indice

@model trash.Models.SeededCategories 

Here's a list 
@Html.Partial("_TreeCategories", Model) 

Partial (your _TreeCategories. NOTA: imposta il seme al corrente ID nodo e Volia ricorsione)

@model trash.Models.SeededCategories 

@if (Model.Categories.Where(s => s.Parent_ID == Model.Seed).Any()) 
{ 
    <ul> 
     @foreach (var node in Model.Categories) 
     { 
      if (node.Parent_ID == Model.Seed) 
      { 
       trash.Models.SeededCategories inner = new trash.Models.SeededCategories { Seed = node.ID, Categories = Model.Categories }; 
      <li><a href="[email protected]">@node.Name</a> 
       @Html.Partial("_TreeCategories", inner) 
      </li> 
      } 
     } 
    </ul> 
} 
+0

Grazie, è così chiaro, eppure, ero confuso per giorni ... Ho appena reinstallato l'intero sistema sul mio computer, ci vuole del tempo prima di scaricare e installare nuovamente Visual Studio per provare questo fuori, ma almeno vedo lo schema ora! Grazie mille! – user2082422

+0

è così che è il più delle volte, felice di aiutare –

+0

A proposito, che tipo di mappatura genitori-figli mi consigliate? Ho scelto questo metodo "ID - ParentID" perché questo è un modo per implementare la struttura gerarchica dei dati in una datamodel relazionale, come un database. Nell'ID della tabella Categorie è la chiave primaria, ParentID è una chiave esterna che fa riferimento a Categories.ID. – user2082422

1

Si può provare Shield UI ricorsiva TreeView for ASP.NET MVC.

Consente di specificare tutti gli elementi TreeView utilizzando un oggetto RecursiveDataSource, che può essere impostato per recuperare i dati per un elemento dell'albero da un endpoint remoto o da un'origine locale "pigramente", ogni volta che l'elemento viene espanso.

RecursiveDataSource è un wrapper attorno a un widget di JavaScript DS, che introduce la necessità di alcuni codici JS, oltre all'aggiornamento del codice server che fornirà i dati (implementando un servizio Web o inserendo i dati in un JS variabile nella tua vista).

+0

Un collegamento a una potenziale soluzione è sempre il benvenuto, ma per favore [aggiungi contesto intorno al link] (// meta.stackoverflow.com/a/8259) in modo che i tuoi utenti possano avere un'idea di cosa sia e perché è lì. Citare sempre la parte più rilevante di un link importante, nel caso in cui il sito target non sia raggiungibile o sia permanentemente offline. Considera che essere _barely più di un link a un sito esterno_ è una possibile ragione per [Perché e come vengono eliminate alcune risposte?] (// stackoverflow.com/help/deleted-answers). – FrankerZ

+0

Aggiornamento della risposta –