C# 可观察集合 WPF 树视图的 LDAP 路径子项

本文关键字:LDAP 路径 视图 观察 集合 WPF | 更新日期: 2023-09-27 18:34:33

我希望有人能帮忙。长时间的窗口窗体/aspx 用户,移动到 WPF。

不期望对此有一个编码答案,但任何关于不同方法的指针将不胜感激 - 我可能以一种非常落后的方式接近这一点。

因此,目标是拥有一个包含子 ObservableCollection "childen"的 ObservableCollection,然后绑定到我的 WPF 树视图控件。

我可以毫无问题地将我的集合绑定到树视图,并根据需要使用复选框图像设置其样式,令人沮丧的是,它是 ObservableCollection,其中包含我首先无法生成的孩子的孩子的孩子。

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

单级,没问题,我正在努力解决的位是按LDAP路径对子对象的子对象进行排序,因此当我绑定到树视图时,显示为AD OU的结构。

例如:

  • 拓跋涉

    • 用户

      • 前台用户

      • 支持人员用户

数据库中的 LDAP 路径示例

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

LDAP://OU=Helpdesk Users,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;
    }

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

任何帮助非常感谢!

C# 可观察集合 WPF 树视图的 LDAP 路径子项

只是细读;)通过您的代码。想我能明白为什么你有很多重复。看起来您的第一个 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,因此在循环中重复查询数据库不是很有效。当我构建父子对象的树时,我通常会在一个查询中获取所有父/子记录。构建所有对象的平面字典。然后循环遍历它并建立父/子关联。

字典也可用于稍后直接通过键查找对象或循环访问,而无需创建对树进行爬网的递归函数。

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

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

每个项目的键可能应该是来自GetLDAPHierarchical((的结果。

第二个块:接下来遍历字典并创建层次结构。将没有父级的任何内容直接添加到用户操作系统中

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

(粉碎(

非常感谢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;
    }