我看过here和here以及其他许多地方,但我似乎无法使用ItemContainerGenerator.ContainerFromItem
方法来处理WPF TreeView!我试图传递我想看的实际项目,但没有得到任何地方,我只是试图获取我的TreeView中的第一项。这是我的示例代码:
private static bool ExpandAndSelectItem(ItemsControl parentContainer, object itemToSelect)
{
// This doesn't work.
parentContainer.BringIntoView();
// May be virtualized, bring into view and try again.
parentContainer.UpdateLayout();
parentContainer.ApplyTemplate();
TreeViewItem topItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(parentContainer.Items[0]);
// Can't find child container unless the parent node is Expanded once
if ((topItem != null) && !topItem.IsExpanded)
{
topItem.IsExpanded = true;
parentContainer.UpdateLayout();
}
}
正如您所看到的,我尝试调用许多“更新”方法来尝试使TreeView“可见”和“可访问”。 Catch-22似乎是你不能使用ContainerFromItem()
,除非第一个TreeViewItem被扩展,但我不能抓住TreeViewItem来扩展它,直到ContainerFromItem()
工作!
另一个有趣的事情是:当我打开这个窗口(它是一个UserControl)时,ContainerFromItem()
返回空值,但是如果我关闭窗口并将其打开,ContainerFromItem()
启动返回非空值。有什么事情我应该寻找或强行解雇?
答案 0 :(得分:4)
原来我正在寻找的事件是“已加载”。我只是在XAML中将一个事件处理程序附加到我的树视图中,并在该事件处理程序中调用了我的逻辑。
<TreeView x:Name="MyTreeView"
Margin="0,5,0,5"
HorizontalAlignment="Left"
BorderThickness="0"
FontSize="18"
FontFamily="Segoe WP"
MaxWidth="900"
Focusable="True"
Loaded="MyTreeView_Load">
...
</TreeView>
事件处理程序:
private void MyTreeView_Load(object sender, RoutedEventArgs e)
{
ShowSelectedThing(MyTreeView, ThingToFind);
}
// Gotta call the TreeView an ItemsControl to cast it between TreeView and TreeViewItem
// as you recurse
private static bool ShowSelectedThing(ItemsControl parentContainer, object ThingToFind)
{
// check current level of tree
foreach (object item in parentContainer.Items)
{
TreeViewItem currentContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if ((currentContainer != null) && (item == ThingToFind)
{
currentContainer.IsSelected = true;
currentContainer.BringIntoView();
return true;
}
}
// item is not found at current level, check the kids
foreach (object item in parentContainer.Items)
{
TreeViewItem currentContainer = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if ((currentContainer != null) && (currentContainer.Items.Count > 0))
{
// Have to expand the currentContainer or you can't look at the children
currentContainer.IsExpanded = true;
currentContainer.UpdateLayout();
if (!ShowSelectedThing(currentContainer, ThingToFind))
{
// Haven't found the thing, so collapse it back
currentContainer.IsExpanded = false;
}
else
{
// We found the thing
return true;
}
}
}
// default
return false;
}
希望这有助于某人。有时在现实世界中,对于要求苛刻的客户,奇怪的要求和短期限,你必须破解!
答案 1 :(得分:0)
当容器生成器的状态为“未启动”时或者&#39; ContainersGenerating&#39;,您无法找到容器。
使用此方法查找数据项的容器。
private static async Task<TreeViewItem> FindItemContainer(ItemsControl itemsControl, object item)
{
var generator = itemsControl.ItemContainerGenerator;
if (generator.Status != GeneratorStatus.ContainersGenerated)
{
var tcs = new TaskCompletionSource<object>();
EventHandler handler = null;
handler = (s, e) =>
{
if (generator.Status == GeneratorStatus.ContainersGenerated)
{
generator.StatusChanged -= handler;
tcs.SetResult(null);
}
else if (generator.Status == GeneratorStatus.Error)
{
generator.StatusChanged -= handler;
tcs.SetException(new InvalidOperationException());
}
};
generator.StatusChanged += handler;
if (itemsControl is TreeViewItem tvi)
tvi.IsExpanded = true;
itemsControl.UpdateLayout();
await tcs.Task;
}
var container = (TreeViewItem)generator.ContainerFromItem(item);
if(container == null)
{
foreach (var parentItem in itemsControl.Items)
{
var parentContainer = (TreeViewItem)generator.ContainerFromItem(parentItem);
container = await FindItemContainer(parentContainer, item);
if (container != null)
return container;
}
}
return container;
}
答案 2 :(得分:0)
private void Lv_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView Lv = (ListView)sender;
Lv.UpdateLayout(); // 1.step
DependencyObject Dep = Lv.ItemContainerGenerator
.ContainerFromItem(Lv.SelectedItem);
((ListViewItem)Dep).Focus(); //2.step
}
我很久以前就遇到过这个问题,现在我又被它困住了很长一段时间。在您的特定控件类型上启动任何 MessageBox 或展开或下拉,其中任何一个都可以完成工作并启动 ItemContainerGenerator。然而,在 .Focus() 之前,.UpdateLayout() 是正确的做法。应该类似于 Treeview 或其项目之一。