簡體   English   中英

從對象填充TreeView

[英]Populate a TreeView from an object

我的WinForm應用程序中的treeview出現問題。 我創建了一個TreeViewItem類來保存數據。 只有5個字段: CaseNoteID,ContactDate,ParentNoteID,InsertUser,ContactDetails。

public class TreeItem
{
    public Guid CaseNoteID;
    public Guid? ParentNoteID;
    public string ContactDate;
    public string InsertUser;
    public string ContactDetails;

    public TreeItem(Guid caseNoteID, Guid? parentNoteID, string contactDate, string contactDetails, string insertUser)
    {
        CaseNoteID = caseNoteID;
        ParentNoteID = parentNoteID;
        ContactDate = contactDate;
        ContactDetails = contactDetails;
        InsertUser = insertUser;
    }
}

計划是通過顯示由ParentNoteID字段確定的父項下的注釋來顯示注釋的關系。 真的很簡單。 不幸的是,到目前為止,我的所有嘗試都在兩個位置上都放置了一個“子”便箋,其中一個帶有ParentNoteID。 第一級下一級是合適的父母。

當我單步執行代碼時,我的數據會准確返回。

 List<TreeItem> items = BLLMatrix.GetTreeViewData(HUD.PersonId);
        PopulateTree(tvwCaseNotes,items);

我只是不知道該怎么做,並用它准確地填充我的TreeView 這是我開始的事情,但現在我被困住了。

  public static void PopulateTree(TreeView tree, ICollection<TreeItem> items)

我只是似乎無法包扎。 我是否需要拆分數據調用,並首先返回ParentNoteID = null所有ParentNoteID = null ,然后再獲取其余ParentNoteID = null以某種方式將兩者ParentNoteID = null

@霍根:對於這個問題的急劇變化,我深表歉意。 從您的回應中可以明顯看出,我一開始並沒有從一個好的角度來解決這個問題。 其次,原始方法仍然無效。

也許我完全誤解了您,但是您擁有一個扁平的層次結構,其中每個元素都知道其父元素。 現在,您必須創建每個元素,然后建立層次結構。 這是這種實現的第一步(缺少循環檢查,錯誤處理等):

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        PopulateTreeView(treeView, SampleData());
    }

    private IEnumerable<Item> SampleData()
    {
        yield return new Item { CaseID = "1" };
        yield return new Item { CaseID = "2" };
        yield return new Item { CaseID = "3" };
        yield return new Item { CaseID = "4", ParentID = "5" };
        yield return new Item { CaseID = "5", ParentID = "3" };
        yield return new Item { CaseID = "6" };
        yield return new Item { CaseID = "7", ParentID = "1" };
        yield return new Item { CaseID = "8", ParentID = "1" };
    }

    private void PopulateTreeView(TreeView tree, IEnumerable<Item> items)
    {
        Dictionary<string, Tuple<Item, TreeNode>> allNodes = new Dictionary<string, Tuple<Item, TreeNode>>();

        foreach (var item in items)
        {
            var node = CreateTreeNode(item);
            allNodes.Add(item.CaseID, Tuple.New(item, node));
        }

        foreach (var kvp in allNodes)
        {
            if (kvp.Value.First.ParentID != null)
            {
                allNodes[kvp.Value.First.ParentID].Second.Nodes.Add(kvp.Value.Second);
            }
            else
            {
                tree.Nodes.Add(kvp.Value.Second);
            }
        }
    }

    private TreeNode CreateTreeNode(Item item)
    {
        var node = new TreeNode();
        node.Text = item.CaseID;

        return node;
    }
}

public class Item
{
    public string CaseID { get; set; }
    public string ParentID { get; set; }
}

public class Tuple<T>
{
    public Tuple(T first)
    {
        First = first;
    }

    public T First { get; set; }
}

public class Tuple<T, T2> : Tuple<T>
{
    public Tuple(T first, T2 second)
        : base(first)
    {
        Second = second;
    }

    public T2 Second { get; set; }
}

public static class Tuple
{
    //Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2")
    public static Tuple<T1> New<T1>(T1 t1)
    {
        return new Tuple<T1>(t1);
    }

    public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2)
    {
        return new Tuple<T1, T2>(t1, t2);
    }
}

什么是元組?

只是為了回答評論中的問題:

它是一個包含其他兩個對象的簡單容器對象。 而已。

我用了它,因為在我的Dictionary中是一個引用在兩個對象( TreeNodeItem )上的不確定標識符( string CaseID )。 另一種方法是制作兩個Dictionary為Dictionary<string, TreeNode>Dictionary<string, Item> ,但是由於存在1:1關系,因此我采用了元組方法。

也許將其重命名為ItemTreeNodeContainer ,對於您在具體情況下意味着什么,它會變得更加清晰。

使用Oliver的解決方案解決了我的問題。 只是使用Tuple將其重構為.Net 4.0的一部分

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        PopulateTreeView(treeView1, SampleData());
    }

    private IEnumerable<Item> SampleData()
    {
        yield return new Item { CaseID = "1" };
        yield return new Item { CaseID = "2" };
        yield return new Item { CaseID = "3" };
        yield return new Item { CaseID = "4", ParentID = "5" };
        yield return new Item { CaseID = "5", ParentID = "3" };
        yield return new Item { CaseID = "6" };
        yield return new Item { CaseID = "7", ParentID = "1" };
        yield return new Item { CaseID = "8", ParentID = "1" };
    }

    private void PopulateTreeView(TreeView tree, IEnumerable<Item> items)
    {
        Dictionary<string, Tuple<Item, TreeNode>> allNodes = new Dictionary<string, Tuple<Item, TreeNode>>();

        foreach (var item in items)
        {
            var node = CreateTreeNode(item);
            allNodes.Add(item.CaseID, Tuple.Create(item, node));
        }

        foreach (var kvp in allNodes)
        {
            if (kvp.Value.Item1.ParentID != null)
            {
                allNodes[kvp.Value.Item1.ParentID].Item2.Nodes.Add(kvp.Value.Item2);
            }
            else
            {
                tree.Nodes.Add(kvp.Value.Item2);
            }
        }
    }

    private TreeNode CreateTreeNode(Item item)
    {
        var node = new TreeNode();
        node.Text = item.CaseID;

        return node;
    }

}

public class Item
{
    public string CaseID { get; set; }
    public string ParentID { get; set; }
}

MSDN上的元組幫助:

元組類

在我的情況下,我從實體框架傳遞數據源:Entities.Categories,並將Item類替換為由實體框架生成的Category類。

遞歸的基本思想是將堆棧用作每次調用中變量的臨時存儲。 但是,您在遞歸調用中引用了全局變量。 當您更改它(通過過濾器功能)時,它將使遞歸中的所有先前調用無效。 您需要刪除遞歸或在堆棧上推送控制變量(行)的新副本(而不是像您所做的那樣引用)。

根據評論進行編輯

我討厭把代碼在那里,而不能對其進行測試,但我相信這樣的事情應該工作,以解決我所描述的問題。

這是問題區域:

// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
  var tmpCNoteID = dr["CaseNoteID"].ToString();
  var filter = "ParentNote='" + tmpCNoteID + "'";

  DataRow[] childRows = cNoteDT.Select(filter);

  if (childRows.Length > 0)
  {
    // Recursively call this function for all childRows
    TreeNode[] childNodes = RecurseRows(childRows);

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

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

這樣的事情應該可以解決我看到的問題(請注意:這不是優雅的代碼,也不是好的代碼,它只是針對我上面描述的問題的解決方法,我永遠不會在此代碼中使用我的名字)。 另外,在無法測試代碼的情況下,我什至無法確定這是問題所在。

// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
  var tmpCNoteID = dr["CaseNoteID"].ToString();
  var filter = "ParentNote='" + tmpCNoteID + "'";

  DataTable DTCopy = cNoteDT.Copy()

  DataRow[] childRows = DTCopy.Select(filter);

  if (childRows.Length > 0)
  {
    // Recursively call this function for all childRows
    TreeNode[] childNodes = RecurseRows(childRows);

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM