我正在我的应用程序中使用 TreeView,并且具有以下结构:
-Main
--Test Category A
---A.1
----T1
----T2
--Test Category B
---B.1
----T1
----T2
当从查找窗口中选择一个项目(例如,T.1)时,我希望 TreeView 自动展开并选择相应的节点。
预期行为: 如果选择 T.1,TreeView 应如下展开:
-Main
--Test Category A
---A.1
----T1
并突出显示/选择 T.1。
当前行为: 运行代码时,仅展开父节点(-Main),但(测试类别 A)和(A.1)不展开。
如果我事先手动展开和折叠 TreeView,代码将按预期工作,完全展开并选择正确的节点。
这是我的 MainWindow.xaml.cs 中的代码片段:
public void SelectTreeViewItem(TestCaseNode selectedItem)
{
if (selectedItem == null)
return;
TestCasesTree.UpdateLayout();
var tvi = FindTviFromObjectRecursive(TestCasesTree, selectedItem);
if (tvi != null)
{
tvi.IsSelected = true;
tvi.BringIntoView();
}
}
public static TreeViewItem FindTviFromObjectRecursive(ItemsControl ic, object o)
{
if (ic == null)
return null;
TreeViewItem result = null;
foreach (object item in ic.Items)
{
TreeViewItem tvi = ic.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (tvi != null)
{
tvi.IsExpanded = true;
tvi.UpdateLayout();
if (item.Equals(o))
{
result = tvi;
}
TreeViewItem childResult = FindTviFromObjectRecursive(tvi, o);
if (childResult != null)
{
result = childResult;
}
}
}
return result;
}
为什么 TreeView 第一次尝试无法完全展开并选择节点?如何修改代码以确保 TreeView 的行为符合预期而不需要手动干预?
任何帮助或指示将不胜感激!谢谢你。
编辑(更新):
我相信问题不在于我以前的代码,而在于我如何处理传递测试用例 ID。我有一个主窗口,用户可以在其中打开名为“搜索”的用户控件。当“搜索”窗口打开时,它出现在主窗口的顶部。在此“搜索”窗口中,用户选择一个测试用例 ID 并单击“搜索”。
我怀疑问题出在这里:在 UserControl 完全关闭之前,TestCase ID 被转发到 MainWindow,导致 Treeview UI 在第一个元素之外保持不更新。这似乎会影响 FindTviFromObjectRecursive(TestCasesTree, selectedItem) 函数的执行,该函数在仅扩展第一个元素(打开搜索窗口时存在的元素)后返回 Null。
这是我的 UserControl MainWindowViewModel.cs 的相关部分:
public TestCaseNode SelectedTreeViewItem
{
...
set
{
...
((MainWindow))Application.Current.MainWindow).SelectTreeViewItem(value);
}
}
public void HighlightAndSelectTestCase(TestCaseNode testCase)
{
...
SelectedTreeViewItem = testCase;
}
这是我的 UserControl SearchwindowVM.cs 的相关部分:
public SearchWindowVM(MainWindowViewModel mainWindowViewModel)
{
// Code initialization...
NotifyMainWindow = (testCase) =>
{
_mainWindowViewModel.HighlightAndSelectTestCase(testCase);
};
}
public void CloseClick()
{
if (SelectedTestCase != null)
{
DialogHost.CloseDialogCommand.Execute(null, null);
NotifyMainWindow?.Invoke(SelectedTestCase);
}
}
不幸的是,我对此有点迷失。
您可以考虑的一件事是采用基于路径的方法来定位树节点,例如
Main\Test Category B\B.1\T1
:
private TreeViewItem? FindItemByPath(TreeView treeView, string path)
{
string[] nodes = path.Split(Path.DirectorySeparatorChar);
ItemsControl currentLevel = treeView;
foreach (string header in nodes)
{
bool found = false;
foreach (var item in currentLevel.Items)
{
if (item is TreeViewItem treeViewItem && treeViewItem.Header.ToString() == header)
{
currentLevel = treeViewItem;
found = true;
break;
}
}
if (!found)
{
return null;
}
}
return currentLevel as TreeViewItem;
}
无论您如何找到该项目,接下来您想要的是迭代并扩展其所有父项。
private void SelectItem(TreeViewItem item)
{
var parent = VisualTreeHelper.GetParent(item);
while (parent is TreeViewItem parentItem)
{
parentItem.IsExpanded = true;
parent = VisualTreeHelper.GetParent(parentItem);
}
item.IsSelected = true;
item.BringIntoView();
}