문제

가 WinForm 트리 제어 표시하는 부모는 아이의 관계를 CaseNotes(내가 알기에는 아무 의미를 당신의 대부분이지만 그것이 나를 시각화하는 대한 답변).

나의 DataTable CaseNotes 는 내가 필요로 표시됩니다.부모/아동은 다음과 같이 정의됩니다.는 경우 행 ParentNoteID 그것은 childNode 의 참고 그렇지 않으면 그것은 rootNode.그것은 또한 수 부모 note(지 rootNode)는 경우 다른 행는 그것의 ID 로 ParentNoteID.

복잡하게 만(어쩌면 단순화하는)일을 내가 아래 작업(주)코드는 색상 노드를 교대의 명암.나는 수동으로 만들어진 정적 컬렉션 트와 그들 상당히습니다.지금 내가 필요로하는 동적으로 채우 노드에서 내 DataTable.

이후 나는 이미가를 통해 트리 노드 노드별로 말할 수 있을 추가로 데이터를 이 과정을 어떻게 든?어쩌면 내가 필요로를 구축하는 노드를 먼저 색상으로 별도 루틴 그러나 재귀는 방법은 여전히 적용을 정확합니까?

말할 수를 표시하고 싶 CaseNoteID 각 노드입니다.에 반환되는 DataTable 고유입니다.

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

        }
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);
            }
        }
    }

편집

내 생각/시도는 지금까지:

        public void BuildSummaryView()
    {
        tvwCaseNotes.Nodes.Clear();

        DataTable cNotesForTree = CurrentCaseNote.GetAllCNotes(Program._CurrentPerson.PersonID);
        foreach (var cNote in cNotesForTree.Rows)
        {

            tvwCaseNotes.Nodes.Add(new TreeNode("ContactDate"));
        }
        FormPaint();
    }

물론 이것은 결함이 있습니다.하나는 그냥 디스플레이의 ContactDate 습니다.부여된 보다 정확한 숫자의 번지의 값이 ContactDate(는 데이터베이스에서 열 및 반환되지에 DataTable.두 번째 나를 추가해야 ChildNode 논리입니다.A if (node.parentNode = node.CaseNoteID) blah...

편집 2

그래서 나는 이것을 발견 링크 , 며,그것은 것 같아요 내 DataTable 로 ArrayList.는 것입니다.

3 편집

좋아요 감사하 bagle.l 이것은 주로 작동합니다.나는 단지 하나 더 많은 질문입니다.어떻게 이-->

DataTable cNotesForTree = CurrentCaseNote.GetAllCNotes(Program._CurrentPerson.PersonID);

고 돌아 DataTable 는 이유는 무엇입니까?나는 그냥 바꾸기 이-->

    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" });

나의 혼란,내 생각,내가 여전히 필요합니다.를 추가하고 행이 있습니다.추가?또한 어떻게 DataColumn 번역하면 나는 실제 데이터 구조는?죄송하는 아주 무식한 질문에,좋은 소식은 내가 결코 가질을 묻다.

편집 4

다음을 제공하 런타임 오류가 있습니다.

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);
  }

이 오류는 다음과 같이--> 을 찾을 수 없는 열[ea8428e4] 첫 번째 8 자리 숫자의 올바른 NoteID(가 Guid 를 사용하여).해야 하고 열의는 이름??기 때문에 나는 Guid 를 사용하는 다른 뭔가가 있나요?나는 모든 변경 참고의 코드를니다.

도움이 되었습니까?

해결책

을 시도는 이 문제를 해결하기 위해 만들고,샘플 windows 양식을 썼고,다음과 같은 코드입니다.내 계획 datatable 디자인은 다음과 같다:

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

이 만들어 나무로(sorry,나는 아주 좋지 않으로 ASCII art!):

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

의사는 다음과 같이 간다:

  1. 반복을 통해 모든 행 datatable.
  2. 각 행을 만듭 트 설정의 속성입니다.재귀적으로 반복하는 프로세스에 대한 모든 행에 있는 ParentNodeID 일치하는 이 행의 ID 입니다.
  3. 각 완전한 반복을 반환 노드를 포함하는 모든 일치하는 childnodes 으로 무한한 중첩이 있습니다.
  4. 추가 완료된를 트리.

문제에 시나리오에서 발생한 사실"외국의 열쇠"를 의미에서 열일 수 있습니다.즉,이 경우 우리는 반복하는 행을 통해,우리가 트랙을 유지하는 행이 이미 구문 분석됩니다.예를 들어,위의 표에서,노드에 일치하는 두번째와 세번째 행이 이미 추가되 처음에 완료됩니다.따라서,우리가 해야 합니다 추가하지 않습니다.하는 방법은 두 가지가 있을 추적이:

  1. 목록을 유지의 ID 는 완료되었습니다(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);
      }
    }
  }
}

다른 팁

는 훨씬 더 간단 확장을 위한 방법이 트를 포함,사용의 새로운 확장 클래스는 두 가지 유용한 특성을 트.

    internal class IdNode : TreeNode
    {
        public object Id { get; set; }
        public object ParentId { get; set; }
    }

    public static void PopulateNodes(this TreeView treeView1, DataTable dataTable, string name, string id, string parentId)
    {
        treeView1.BeginUpdate();
        foreach (DataRow row in dataTable.Rows)
        {
            treeView1.Nodes.Add(new IdNode() { Name = row[name].ToString(), Text = row[name].ToString(), Id = row[id], ParentId = row[parentId], Tag = row });
        }
        foreach (IdNode idnode in GetAllNodes(treeView1).OfType<IdNode>())
        {
            foreach (IdNode newparent in GetAllNodes(treeView1).OfType<IdNode>())
            {
                if (newparent.Id.Equals(idnode.ParentId))
                {
                    treeView1.Nodes.Remove(idnode);
                    newparent.Nodes.Add(idnode);
                    break;
                }
            }
        }
        treeView1.EndUpdate();
    }

    public static List<TreeNode> GetAllNodes(this TreeView tv)
    {
        List<TreeNode> result = new List<TreeNode>();
        foreach (TreeNode child in tv.Nodes)
        {
            result.AddRange(GetAllNodes(child));
        }
        return result;
    }
    public static List<TreeNode> GetAllNodes(this TreeNode tn)
    {
        List<TreeNode> result = new List<TreeNode>();
        result.Add(tn);
        foreach (TreeNode child in tn.Nodes)
        {
            result.AddRange(GetAllNodes(child));
        }
        return result;
    }

감사 modiX방법 모두 얻을 수(중첩)노드입니다.

이를 확인:

Public Sub BuildTree(ByVal dt As DataTable, ByVal trv As TreeView, ByVal expandAll As [Boolean])
    ' Clear the TreeView if there are another datas in this TreeView
    trv.Nodes.Clear()
    Dim node As TreeNode
    Dim subNode As TreeNode
    For Each row As DataRow In dt.Rows
        'search in the treeview if any country is already present
        node = Searchnode(row.Item(0).ToString(), trv)
        If node IsNot Nothing Then
           'Country is already present
            subNode = New TreeNode(row.Item(1).ToString())
            'Add cities to country
            node.Nodes.Add(subNode)
        Else
            node = New TreeNode(row.Item(0).ToString())
            subNode = New TreeNode(row.Item(1).ToString())
            'Add cities to country
            node.Nodes.Add(subNode)
            trv.Nodes.Add(node)
        End If
    Next
    If expandAll Then
        ' Expand the TreeView
        trv.ExpandAll()
    End If
End Sub

더하고 전체 소스 코드: 는 방법을 채우 트리부터 datatable 에 vb.net

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top