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;
}
使用我当前的解决方案,我得到了一个树视图,其中包含子节点的子节点,但它们是错误的/大量重复等。我花了几天时间试图修复我上面可能过于复杂的尝试 - 但得出的结论是,我可能以错误的方式去做。
任何帮助非常感谢!
只是细读;)通过您的代码。想我能明白为什么你有很多重复。看起来您的第一个 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;
}