2009-06-09 6 views
1

J'ai travaillé sur ma première page Web qui servira de guide de dépannage basé sur une série de questions. Les questions sont déterminées par la réponse à la question précédente, de sorte qu'il se transforme en "choisissez votre propre aventure". Heureusement, on m'a donné un diagramme de décision montrant tous les chemins possibles, mais cela ressemble à la carte du métro de Tokyo. J'ai d'abord créé une série de panneaux, chacun contenant la question et un contrôle liste déroulante contenant la réponse que le texte et l'ID du panneau, il devrait précéder. Ensuite, j'ai créé une classe pour organiser tous les panneaux dans une structure graphique. Avec cette classe, je suis capable de connaître l'ordre dans lequel les panneaux sont sélectionnés, quels panneaux n'ont pas été sélectionnés et il est facile de modifier le flux de décision. Ci-dessous est un exemple de la façon dont j'utilise la classe dans l'événement pageload et ci-dessous qui est la classe réelle. Comme je ne connais pas vraiment asp.net, je me demande simplement s'il existe de meilleures façons de résoudre ce problème et s'il y a des failles dans mon code. Mon code fonctionne, mais je suis sûr qu'il pourrait y avoir des améliorations.Création d'une page web de dépannage avec une série de? S dans asp.net. Diagramme dirigé

protected void Page_Load(object sender, EventArgs e) 
{ 

    DecisionGraph g = new DecisionGraph(this); 

    // Pass is root panel 
    g.BuildGraph("pnl1"); 

    // Refreshes graph and returns an obj containing 2 iterable objects 
    DecisionGraphEnumeration dgEnum = g.RefreshGraph(); 

    // Clear panel which will hold active panels 
    pnlMASTER.Controls.Clear(); 

    IEnumerator<Panel> iEnumOnPath = dgEnum.GetOnPathPanelEnumerator(); 
    while (iEnumOnPath.MoveNext()) 
    { 
     Panel p = (Panel)iEnumOnPath.Current; 
     p.Visible = true; 

     pnlMASTER.Controls.Add(p); 
    } 

    IEnumerator<Panel> iEnumOffPath = dgEnum.GetOffPathPanelEnumerator(); 

    while (iEnumOffPath.MoveNext()) 
    { 
     iEnumOffPath.Current.Visible = false; 
    } 
} 

Voici la classe

using System; 
using System.Data; 
using System.Configuration; 
using System.Web; 
using System.Web.Security; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.Web.UI.WebControls.WebParts; 
using System.Web.UI.HtmlControls; 
using System.Collections; 
using System.Collections.Generic; 


public class DecisionGraph 
{ 

    const String NULL_POINTER_NAME = "null"; 
    private Node root; 
    private Page webPage; 

    //constructor 
    public DecisionGraph(Page pg) 
    { 
     this.webPage = pg; 
     this.root = null; 
    } 

    // method creates a graph structure recursively starting 
    // with the parameter as root 
    public void BuildGraph(String pnlName) 
    { 
     // return the reference of the supplied panel 
     Panel p = GetPanel(pnlName); 

     // create root 
     root = new Node(p, GetDropDownList(p)); 

     // add children nodes to root 
     insert(root); 


     return; 
    } 

    // adds all child nodes to passed node 
    private void insert(Node n) 
    { 
     // if Panel has a DropDownList 
     if (n.dropDownList != null)// not leaf 
     { 
      // create an array of Nodes to hold references to children 
      n.children = new Node[n.dropDownList.Items.Count]; 

      int i = 0; 
      foreach (ListItem it in n.dropDownList.Items) 
      { 
       Panel childPanel = GetPanel(it.Value); 

       if (childPanel == null) 
       { 
        // Panel does not exit 
        n.children[i] = null; 
       } 
       else 
       { 

        Node childNode = GetNode(childPanel); 

        if (childNode == null)// Node doesn't exist in structure for chilePanel 
        { 
         // create child node 
         childNode = new Node(childPanel, GetDropDownList(childPanel)); 

         // add child node to arryay of children 
         n.children[i] = childNode; 

         // add the childs nodes of childNode to childNode 
         insert(n.children[i]); 
        } 
        else 
        { 
         // node had already been created, just add reference 
         n.children[i] = childNode; 
        } 



       } 

       i++; 
      } 
     } 

     return; 

    } 

    // returns an iterator of all active panels set as visible 
    // and sets all other panels as hidden 
    public DecisionGraphEnumeration RefreshGraph() 
    { 
     LinkedList<Panel> pathedPanels = new LinkedList<Panel>(); 
     LinkedList<Panel> nonPathedPanels = new LinkedList<Panel>(); 

     FindCurrentPath(root, pathedPanels); 

     HideNonPathedNodes(root, nonPathedPanels); 

     UnMarkAllNodes(root); 

     return new DecisionGraphEnumeration(pathedPanels.GetEnumerator(), nonPathedPanels.GetEnumerator()); 
    } 

    // marks each node as valid and saves reference inorder 
    private void FindCurrentPath(Node n, LinkedList<Panel> list) 
    { 
     if (n == null) 
      return; 

     n.visitedFlag = true; 
     list.AddLast(n.panel); 

     if (n.dropDownList == null) 
      return; 

     int index = n.dropDownList.SelectedIndex; 

     FindCurrentPath(n.children[index],list); 

     return; 

    } 

    // finds all non pathed nodes and saves reference in no order 
    private void HideNonPathedNodes(Node n, LinkedList<Panel> list) 
    { 
     if (n == null) 
      return; 

     if (!n.visitedFlag) 
     { 

      n.ResetDropDownList(); 

      // add panel if not already added. 
      if (!list.Contains(n.panel)) 
       list.AddLast(n.panel); 
     } 

     if(n.children == null) 
      return; 

     foreach (Node childNode in n.children) 
      HideNonPathedNodes(childNode, list); 
    } 

    // unmarks n and sets all children of n as unmarked 
    private void UnMarkAllNodes(Node n) 
    { 
     if (n == null) 
      return; 

     n.visitedFlag = false; 

     if (n.children == null) 
     { 
      return; 
     } 
     else 
     { 
      foreach (Node childNode in n.children) 
       UnMarkAllNodes(childNode); 
     } 

    } 

    // returns node if a node already exists for p in structure, else returns null 
    private Node GetNode(Panel p) 
    { 
     Node n = getNode(root, p); 

     return n; 
    } 

    // recursive method call for GetNode 
    private Node getNode(Node n, Panel p) 
    { 
     if (n == null || p == null) 
      return null; 

     if (n.panel.Equals(p)) 
     { 
      return n; 
     } 
     else if (n.children != null) 
     { 
      Node x = null; 
      int i = 0; 

      while (x == null && i < n.children.Length) 
      { 
       x = getNode(n.children[i], p); 
       i++; 
      } 

      return x; 
     } 
     else 
     { 
      return null; 
     } 

    } 

    // returns a DropDownList from p 
    private DropDownList GetDropDownList(Panel p) 
    { 

     foreach (Control ctrl in p.Controls) 
     { 
      if (ctrl is DropDownList) 
      { 
       return (DropDownList) ctrl; 
      } 
     } 

     return null; 
    } 

    // returns a panel from webpage of contructor using the FindControl method 
    private Panel GetPanel(String panelName) 
    { 
     if(panelName.Equals(NULL_POINTER_NAME)) 
      return null; 

     Control ctrl = webPage.FindControl(panelName); 
     if (ctrl is Panel) 
     { 
      return (Panel)ctrl; 
     } 
     else 
     { 
      throw new ArgumentException(String.Format("{0} is not a Panel inside page {1}",panelName,webPage.Title.ToString())); 
     } 
    } 


    private class Node 
    { 
     public Panel panel; 
     public DropDownList dropDownList; 
     public Node[] children; 
     public bool pathedNode; 
     public bool visitedFlag; 

     #region Constructors 

     public Node() : this(null, null) { } 

     public Node(Panel p) : this(p, null) { } 

     public Node(Panel pnl, DropDownList d) 
     { 
      this.panel = pnl; 
      this.dropDownList = d; 
      this.children = null; 
      this.pathedNode = false; 
      this.visitedFlag = false; 
     } 

     #endregion 

     public void ResetDropDownList() 
     { 
      if (dropDownList == null) 
       return; 
      else 
       dropDownList.SelectedIndex = 0; 
     } 
    } 
} 


public class DecisionGraphEnumeration 
{ 
    private IEnumerator<Panel> onPathPanels; 
    private IEnumerator<Panel> offPathPanels; 

    internal DecisionGraphEnumeration(IEnumerator<Panel> active, IEnumerator<Panel> nonActive) 
    { 
     onPathPanels = active; 
     offPathPanels = nonActive; 
    } 

    public IEnumerator<Panel> GetOnPathPanelEnumerator() 
    { 
     return onPathPanels; 
    } 

    public IEnumerator<Panel> GetOffPathPanelEnumerator() 
    { 
     return offPathPanels; 
    } 


} 

Répondre

1

pas passé par votre code, mais basé sur l'idée de ce que vous voulez faire, je pense que vous pourriez vouloir enquêter sur l'utilisation du WizardControl http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.wizard.aspx qui permet hautement personnalisable Assistants à créer

Dans un premier temps, vous pouvez utiliser l'événement ActiveStepChanged pour choisir l'étape à suivre en fonction des réponses de l'utilisateur à chaque étape.

0

Je recommande fortement de ne pas référencer toute instance de System.Web.Page dans votre classe DecisionGraph. Il ne semble pas que vous utilisiez la référence pour quelque chose en ce moment et vous serez simplement tenté de l'utiliser sans le vouloir aussi longtemps que vous le laisserez là.

Il semble que vous construisiez le graphique entier pour chaque chargement de page - naviguez-vous dans la structure après les publications? Gardez à l'esprit que lorsque vous définissez la propriété visibility d'un panneau sur false, vous n'obtenez aucune sortie côté client. Toutefois, si vous définissez l'attribut de style CSS "display" sur "none", vous restituerez l'ensemble du graphe au client et pourrez réellement effectuer toute la navigation du côté client avec javascript.

+0

Je référence System.Web.Page lorsque j'effectue la méthode FindControl – Kevin

+0

Vous pouvez réellement appeler la fonction FindControl sur l'un de vos WebControls, tels que vos panneaux - en gardant à l'esprit que vous ne ferez que rechercher les enfants de ce contrôle particulier. Ce sera en fait plus rapide car vous ne cherchez pas toute la page. Cependant, j'ai remarqué que dans BuildGraph vous trouvez la référence à la chaîne "panel ID" que vous passez, donc vous pouvez envisager de passer dans la référence du panneau. – nvuono

Questions connexes