2

我希望有人能帮忙。很长一段时间的 windows forms/aspx 用户,正在迁移到 WPF。

不期待对此的编码答案,但将不胜感激任何以不同方式接近的指针 - 我可能以非常落后的方式接近这个问题。

所以目标是有一个带有子 ObservableCollection“childen”的 ObservableCollection,然后绑定到我的 WPF 树视图控件。

我可以毫无问题地将我的集合绑定到树视图,并根据需要使用复选框图像对其进行样式设置,令人沮丧的是,它的 ObservableCollection 带有我一开始就无法生成的孩子的孩子。

我在 SQL 中有一个带有 LDAP 路径的表,以及我针对该 LDAP 路径存储的各种其他信息,我将这些信息读入我的 ObservableCollection。

单级,没问题,我正在努力的一点是通过 LDAP 路径对子对象的子对象进行排序,所以当我绑定到树视图时,会呈现为 AD OU 的结构化。

例如:

  • TopOU

    • 用户

      • 前台用户

      • 帮助台用户

我的数据库中的示例 LDAP 路径

LDAP://OU=前台用户,OU=用户,OU=TopOU,DC=dev,DC=local

LDAP://OU=Helpdesk 用户,OU=Users,OU=TopOU,DC=dev,DC=local

LDAP://OU=OU=Users,OU=TopOU,DC=dev,DC=local

LDAP://OU=OU=TopOU,DC=dev,DC=local

private ObservableCollection<AssignmentData> OUTreeAssignmentsCollection = new ObservableCollection<AssignmentData>();

public class AssignmentData : INotifyPropertyChanged
{
        public Int32 AssignmentID { get; set; }
        public String AssignmentName { get; set; }
        public AssignmentTypes AssignmentType { get; set; }
        //other stuff....

        //For TreeView all sub nodes
        public ObservableCollection<AssignmentData> Children { get; set; }
}

然后我开始以一种相当讨厌的方式从我的数据库中读取数据,这就是一切都出错的地方,我可以使用一些指针。

cmd = new SqlCommand("SELECT UserGroups.UserGroupID, UserGroups.Name, UserGroups.LDAPPath FROM UserGroups WHERE UserGroups.TypeID=1", DBCon);
            reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                String strLDAPHierarchical = GetLDAPHierarchical(reader[2].ToString());
                AssignmentData newItem = new AssignmentData()
                        {
                            AssignmentID = Convert.ToInt32(reader[0]),
                            AssignmentName = reader[1].ToString(),
                            AssignmentImage = ouIcon,
                            AssignmentLDAPPath = reader[2].ToString(),
                            AssignmentCNPath = GetCNFromLDAPPath(reader[2].ToString()),
                            AssignmentTooltip = GetADSLocationTooltip(reader[2].ToString()),
                            AssignmentType = AssignmentTypes.UserOU,
                            AssignmentLDAPHierarchical = strLDAPHierarchical
                        };


                if (strLDAPHierarchical.Contains(","))
                {
                    //Now check all the root nodes exist to continue
                    String strLDAPHierarchicalCheckPath = strLDAPHierarchical;
                    String[] SplitLDAPHierarchical = strLDAPHierarchical.Split(new Char[] { ',' });

                    Int32 reverseI = SplitLDAPHierarchical.Length - 1;
                    String prevPath = "";
                    for (int i = 0; i < SplitLDAPHierarchical.Length; i++)
                    {
                        String path = SplitLDAPHierarchical[reverseI];
                        //now check if this node is already there and if not look it up and create it
                        if (path != "")
                        {
                            if (i == 0) { strLDAPHierarchicalCheckPath = path; }
                            else { strLDAPHierarchicalCheckPath = path + "," + prevPath; }
                            WriteLog("CHECK:" + strLDAPHierarchicalCheckPath);
                            LookupItemByLDAPHierarchical(strLDAPHierarchicalCheckPath, newItem);

                            if (i == 0) { prevPath = path; }
                            else { prevPath = path + "," + prevPath; }
                            reverseI = reverseI - 1;
                        }
                    }
                }
                else
                {
                    //is top level object, so create at the root of the collection
                    UserOUCollection.Add(newItem);
                }

添加子项目的功能:-/

internal AssignmentData LookupItemByLDAPHierarchical(String strLDAPHierarchical, AssignmentData fromItem)
    {
        AssignmentData currentItem = null;
        foreach (AssignmentData d in UserOUCollection)
        {

            if (d.AssignmentLDAPHierarchical == strLDAPHierarchical) { currentItem = d; break; }
            if (d.Children != null)
            {
                currentItem = CheckChildNodesByLDAPHierarchical(d, strLDAPHierarchical);
                if (currentItem != null) { break; }
            }
        }

        String strMessage = "null";
        if (currentItem != null) { strMessage = currentItem.AssignmentLDAPPath; }

        if (currentItem == null) 
        {
            String strWhere = "LDAPPath LIKE 'LDAP://" + strLDAPHierarchical + "%'";

            SqlConnection DBCon = new SqlConnection(SQLString);
            DBCon.Open();

            SqlCommand cmd = new SqlCommand("SELECT UserGroupID, Name, LDAPPath FROM UserGroups WHERE " + strWhere + " AND TypeID=1", DBCon);

            SqlDataReader reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                strLDAPHierarchical = GetLDAPHierarchical(reader[2].ToString());
                AssignmentData newItem = new AssignmentData()
                {
                    AssignmentID = Convert.ToInt32(reader[0]),
                    AssignmentName = reader[1].ToString(),
                    AssignmentImage = ouIcon,
                    AssignmentLDAPPath = reader[2].ToString(),
                    AssignmentCNPath = GetCNFromLDAPPath(reader[2].ToString()),
                    AssignmentTooltip = GetADSLocationTooltip(reader[2].ToString()),
                    AssignmentType = AssignmentTypes.UserOU,
                    AssignmentLDAPHierarchical = strLDAPHierarchical
                };

                    String strLDAPHierarchicalCheckPath = strLDAPHierarchical;
                    foreach (String path in strLDAPHierarchical.Split(new Char[] { ',' }))
                    {
                        //now check if this node is already there and if not look it up and create it
                        if (path != "")
                        {
                            strLDAPHierarchicalCheckPath = strLDAPHierarchicalCheckPath.Replace(path + ",", "");
                            currentItem = LookupItemByLDAPHierarchical(strLDAPHierarchicalCheckPath, currentItem);

                            if (null == currentItem)
                            {
                                UserOUCollection.Add(newItem); //new root item
                            }
                            else
                            {
                                if (currentItem.Children == null)
                                {
                                    //add new child
                                    currentItem.Children = new ObservableCollection<AssignmentData> { newItem };
                                }
                                else
                                {
                                    //add more children to exisiting
                                    currentItem.Children.Add(newItem);
                                }
                            }
                            currentItem = null;
                        }
                    }

                //Find a current Item to add the node to
                //currentItem = LookupItemByLDAPHierarchical(strLDAPHierarchical);

            }
            reader.Close();
            reader.Dispose();

            DBCon.Close();
            DBCon.Dispose();


        }

        return currentItem;
    }

使用我当前的解决方案,我得到了一个树视图,其中包含子节点的子节点,但它们是错误的/有很多重复等。我花了几天时间试图解决我上面可能过于复杂的尝试 - 但得出的结论是可能以错误的方式进行。

非常感谢任何帮助!

4

2 回答 2

1

只需仔细阅读;) 通过您的代码。想我可以明白为什么你有很多重复。看起来您的第一个 SQL 查询获取了所有父/子记录。然后,如果有意义的话,第二个查询将再次获取其中一些记录。

一种方法是仅在您的第一个查询中获取顶级项目。可能通过让 SQL 计算逗号的数量。

SELECT UserGroups.UserGroupID, UserGroups.Name, UserGroups.LDAPPath, 
       LENGTH(LDAPPath) - LENGTH(REPLACE(LDAPPath, ',', '')) as CommaCount 
FROM UserGroups 
WHERE UserGroups.TypeID=1 
  AND CommaCount = 2

由于您要求使用不同的方法 ID,因此循环重复查询数据库效率不高。当我构建父子对象树时,我通常会在一个查询中获取所有父/子记录。构建所有对象的平面字典。然后遍历它并建立父/子关联。

字典也可以用于稍后直接通过键或循环查找对象,而不必创建一个爬取树的递归函数。

所以我建议你把它分解成两个代码块。

第一个块:使用获取所有项目的现有查询,创建一个包含所有内容的平面字典。

它们每个项目的键可能应该是 GetLDAPHierarchical() 的结果。

第二块:下一个循环遍历字典并创建层次结构。将没有父级的任何内容直接添加到 UserOUCollection

foreach(AssignmentData d in myDictionary.Values)
{
    String parentKey = GetParentLDAPKey(d.AssignmentLDAPHierarchical);

    if (myDictionary.ContainsKey(parentKey))
    {
        myDictionary(parentKey).children.Add(d);
    }
    else
    {
        UserOUCollection.Add(d);
    }
}

GetParentLDAPKey()将需要通过删除 LDAP 路径的第一部分来生成与其父级相同的密钥。

希望这会为您指明正确的方向。

H

(粉碎)

于 2013-10-28T11:00:41.547 回答
0

非常感谢 hman,他为我指明了一个更合乎逻辑的方向。我使用 LDAPPath 作为我的字典键。

Dictionary<String, AssignmentData> OUDictionary = new Dictionary<String, AssignmentData>();

//Read from DB
cmd = new SqlCommand("SELECT UserGroups.UserGroupID, UserGroups.Name, UserGroups.LDAPPath FROM UserGroups WHERE UserGroups.TypeID=1", DBCon);
            reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                AssignmentData newItem = new AssignmentData()
                        {
                            AssignmentID = Convert.ToInt32(reader[0]),
                            AssignmentName = reader[1].ToString(),
                            AssignmentImage = ouIcon,
                            AssignmentLDAPPath = reader[2].ToString(),
                            AssignmentCNPath = GetCNFromLDAPPath(reader[2].ToString()),
                            AssignmentTooltip = GetADSLocationTooltip(reader[2].ToString()),
                            AssignmentType = AssignmentTypes.UserOU,
                        };
                UserOUDictionary.Add(reader[2].ToString(), newItem);

            }
            reader.Close();
            reader.Dispose();


            //Now Read OU List into TreeView Collection
            foreach (AssignmentData d in UserOUDictionary.Values)
            {
                String parentKey = GetParentLDAPPath(d.AssignmentLDAPPath);
                if (UserOUDictionary.ContainsKey(parentKey))
                {
                    AssignmentData parentItem = UserOUDictionary[parentKey];
                    if (parentItem.Children == null) { parentItem.Children = new ObservableCollection<AssignmentData> { d }; } //add first child
                    else { parentItem.Children.Add(d); } //add more children to exisiting
                }
                else
                {
                    UserOUCollection.Add(d); //add to root of control
                }
            }


private String GetParentLDAPKey(String strLDAPPath)
    {
        String retParentKey = strLDAPPath;
        if (strLDAPPath.Contains(","))
        {
            retParentKey = retParentKey.Replace("LDAP://", "");
            retParentKey = retParentKey.Remove(0, retParentKey.IndexOf(",") + 1);
            retParentKey = "LDAP://" + retParentKey;
        }

        return retParentKey;
    }
于 2013-11-04T17:25:37.870 回答