Заполните WinForms TreeView от DataTable

Под выполнением приложения я подразумеваю, что пользователь использует элемент управления рейтингом, чтобы дать значение. Я вижу, что это ноль, нарушая выполнение и проверку.

Я решил проблему довольно не элегантно. Но поверьте, я понимаю причину. Я разрешаю Swift читать в файле JSON, как указано выше "init? (Json: Data)". Это работает хорошо, так как на самом деле есть несколько деталей файла JSON, не включенных в приведенный выше пример. Это экономит на написании полной логики JSON - особенно для обработки нулей. Однако нулевые значения могут привести к сбою чтения. Поэтому пользовательский рейтинг (который будет нулевым) отсутствует в файле JSON. Следовательно, структура Stats не инициализируется в чтении. И, очевидно, он не может быть инициализирован позже, когда это необходимо. (После того, как пользователь дает оценку обратной связи.)

Мое решение состояло в том, чтобы добавить необязательное свойство «код» в структуру, как показано ниже:

  struct Stats: Codable {
        var code: String
        var rating: Double?
        var time: TimeInterval?
    }

Затем в JSON я добавляю: [115 ]

   "userStats": {
        "code":  "user"
    },

В настоящее время я не использую код свойства, но моя структура для userStats инициализируется с оценкой как ноль. Затем я могу позже добавить значение для рейтинга, когда это необходимо.

14
задан Axarydax 12 March 2012 в 14:42
поделиться

1 ответ

Чтобы попытаться решить эту проблему, я создал образец формы Windows и написал следующий код. Я представлял проект с датами следующим образом:

 NoteID  NoteName  ParentNoteID
   "1"    "One"        null
   "2"    "Two"        "1"
   "3"    "Three"      "2"
   "4"    "Four"       null
...

Это должно создать дерево как ( извините, я не очень хорошо разбираюсь в искусстве ASCII! ):

One
 |
 ——Two
 |
 ————Three
 |
Four

Псевдокод выглядит следующим образом:

  1. Итерировать через все строки в таблице данных.
  2. Для каждой строки создайте TreeNode и установите его свойства. Рекурсивно повторите процесс для всех строк, у которых ParentNodeID соответствует идентификатору этой строки.
  3. Каждая полная итерация возвращает узел, который будет содержать все совпадающие дочерние узлы с бесконечной вложенностью.
  4. Добавьте завершенный список узлов в TreeView.

Проблема в вашем сценарии возникает из-за того, что «внешний ключ» относится к столбцу в той же таблице. Это означает, что когда мы перебираем строки, мы должны отслеживать, какие строки уже были проанализированы. Например, в приведенной выше таблице узел, соответствующий второй и третьей строкам, уже добавлен в первой полной итерации. Поэтому мы не должны добавлять их снова. Есть два способа отслеживать это:

  1. Поддерживать список идентификаторов, которые были сделаны ( doneNotes ). Перед добавлением каждого нового узла проверьте, существует ли noteID в этом списке. Это более быстрый метод и обычно должен быть предпочтительным. ( этот метод закомментирован в приведенном ниже коде )
  2. Для каждой итерации используйте универсальный делегат предиката ( FindNode ) для поиска в списке добавленных узлов (с учетом вложенных узлов ), чтобы увидеть, существует ли добавляемый узел в этом списке. Это более медленное решение, но мне нравится сложный код! : P

Хорошо, здесь Испытанный и проверенный код (C # 2.0):


public partial class TreeViewColor : Form
{
  private DataTable dt;
  // Alternate way of maintaining a list of nodes that have already been added.
  //private List<int> doneNotes;
  private static int noteID;

  public TreeViewColor()
  {
    InitializeComponent();
  }

  private void TreeViewColor_Load(object sender, EventArgs e)
  {
    CreateData();
    CreateNodes();

    foreach (TreeNode rootNode in treeView1.Nodes)
    {
      ColorNodes(rootNode, Color.MediumVioletRed, Color.DodgerBlue);
    }
  }

  private void CreateData()
  {
    dt = new DataTable("CaseNotes");
    dt.Columns.Add("NoteID", typeof(string));
    dt.Columns.Add("NoteName", typeof(string));
    DataColumn dc = new DataColumn("ParentNoteID", typeof(string));
    dc.AllowDBNull = true;
    dt.Columns.Add(dc);

    // Add sample data.
    dt.Rows.Add(new string[] { "1", "One", null });
    dt.Rows.Add(new string[] { "2", "Two", "1" });
    dt.Rows.Add(new string[] { "3", "Three", "2" });
    dt.Rows.Add(new string[] { "4", "Four", null });
    dt.Rows.Add(new string[] { "5", "Five", "4" });
    dt.Rows.Add(new string[] { "6", "Six", null });
    dt.Rows.Add(new string[] { "7", "Seven", null });
    dt.Rows.Add(new string[] { "8", "Eight", "7" });
    dt.Rows.Add(new string[] { "9", "Nine", "8" });
  }

  private void CreateNodes()
  {
    DataRow[] rows = new DataRow[dt.Rows.Count];
    dt.Rows.CopyTo(rows, 0);
    //doneNotes = new List<int>(9);

    // Get the TreeView ready for node creation.
    // This isn't really needed since we're using AddRange (but it's good practice).
    treeView1.BeginUpdate();
    treeView1.Nodes.Clear();

    TreeNode[] nodes = RecurseRows(rows);
    treeView1.Nodes.AddRange(nodes);

    // Notify the TreeView to resume painting.
    treeView1.EndUpdate();
  }

  private TreeNode[] RecurseRows(DataRow[] rows)
  {
    List<TreeNode> nodeList = new List<TreeNode>();
    TreeNode node = null;

    foreach (DataRow dr in rows)
    {
      node = new TreeNode(dr["NoteName"].ToString());
      noteID = Convert.ToInt32(dr["NoteID"]);

      node.Name = noteID.ToString();
      node.ToolTipText = noteID.ToString();

      // This method searches the "dirty node list" for already completed nodes.
      //if (!doneNotes.Contains(doneNoteID))

      // This alternate method using the Find method uses a Predicate generic delegate.
      if (nodeList.Find(FindNode) == null)
      {
        DataRow[] childRows = dt.Select("ParentNoteID = " + dr["NoteID"]);
        if (childRows.Length > 0)
        {
          // Recursively call this function for all childRowsl
          TreeNode[] childNodes = RecurseRows(childRows);

          // Add all childnodes to this node.
          node.Nodes.AddRange(childNodes);
        }

        // Mark this noteID as dirty (already added).
        //doneNotes.Add(noteID);
        nodeList.Add(node);
      }
    }

    // Convert this List<TreeNode> to an array so it can be added to the parent node/TreeView.
    TreeNode[] nodeArr = nodeList.ToArray();
    return nodeArr;
  }

  private static bool FindNode(TreeNode n)
  {
    if (n.Nodes.Count == 0)
      return n.Name == noteID.ToString();
    else
    {
      while (n.Nodes.Count > 0)
      {
        foreach (TreeNode tn in n.Nodes)
        {
          if (tn.Name == noteID.ToString())
            return true;
          else
            n = tn;
        }
      }
      return false;
    }
  }

  protected void ColorNodes(TreeNode root, Color firstColor, Color secondColor)
  {
    root.ForeColor = root.Index % 2 == 0 ? firstColor : secondColor;

    foreach (TreeNode childNode in root.Nodes)
    {
      Color nextColor = childNode.ForeColor = childNode.Index % 2 == 0 ? firstColor : secondColor;

      if (childNode.Nodes.Count > 0)
      {
        // alternate colors for the next node
        if (nextColor == firstColor)
          ColorNodes(childNode, secondColor, firstColor);
        else
          ColorNodes(childNode, firstColor, secondColor);
      }
    }
  }
}

12
ответ дан 1 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: