c# – 带虚拟化的WPF TreeView – 选择项目并将其置于视图中
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c# – 带虚拟化的WPF TreeView – 选择项目并将其置于视图中,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6129字,纯文字阅读大概需要9分钟。
内容图文
![c# – 带虚拟化的WPF TreeView – 选择项目并将其置于视图中](/upload/InfoBanner/zyjiaocheng/822/51cebda42f4b415c82466dd2a2147e19.jpg)
我最近一直在使用WPF树视图,当用户使用在后备对象上设置IsSelected属性的搜索功能时,我正试图让所选项目显示在屏幕上时非常糟糕.
目前我的方法是使用这个答案中的方法:https://stackoverflow.com/a/34620549/800318
private void FocusTreeViewNode(TreeViewEntry node)
{
if (node == null) return;
var nodes = (IEnumerable<TreeViewEntry>)LeftSide_TreeView.ItemsSource;
if (nodes == null) return;
var stack = new Stack<TreeViewEntry>();
stack.Push(node);
var parent = node.Parent;
while (parent != null)
{
stack.Push(parent);
parent = parent.Parent;
}
var generator = LeftSide_TreeView.ItemContainerGenerator;
while (stack.Count > 0)
{
var dequeue = stack.Pop();
LeftSide_TreeView.UpdateLayout();
var treeViewItem = (TreeViewItem)generator.ContainerFromItem(dequeue);
if (stack.Count > 0)
{
treeViewItem.IsExpanded = true;
}
else
{
if (treeViewItem == null)
{
//This is being triggered when it shouldn't be
Debugger.Break();
}
treeViewItem.IsSelected = true;
}
treeViewItem.BringIntoView();
generator = treeViewItem.ItemContainerGenerator;
}
}
TreeViewEntry是我的后备数据类型,它具有对其父节点的引用. Leftside_TreeView是绑定到我的对象列表的虚拟化TreeView.关闭虚拟化不是一种选择,因为性能非常糟糕.
当我搜索一个对象并找到后备数据对象时,我将该对象作为其参数调用此FocusTreeViewNode()方法.它通常在第一次调用时工作,选择对象并将其带入视图.
在第二次执行搜索时,将传入要选择的节点,但是当清空堆栈时,ContainerFromItem()调用(因此它尝试为对象本身生成容器)返回null.当我调试这个时,我可以在ContainerGenerator的项目列表中看到我正在搜索的对象,但由于某种原因它没有被返回.我查看了所有与UpdateLayout()和其他事情有关的事情,但我无法弄清楚这一点.
即使在将父节点带入视图之后,容器中的一些对象也可能在页面外 – 例如,扩展器下面有250个项目,并且每次只渲染60个.这可能是个问题吗?
更新
这是一个示例项目,它使虚拟化树视图显示此问题. https://github.com/Mgamerz/TreeViewVirtualizingErrorDemo
在VS中构建它,然后在搜索框中输入类似于4.按几次搜索,它会抛出一个异常,说容器为空,即使你打开生成器对象,你也可以清楚地看到它在生成器中.
解决方法:
与WPF开发的许多其他方面一样,可以使用MVVM设计模式来处理此操作.
创建一个ViewModel类,包括一个IsSelected属性,该属性保存每个树项的数据.
然后,可以通过附加属性处理将所选项目置于视图中
public static class perTreeViewItemHelper
{
public static bool GetBringSelectedItemIntoView(TreeViewItem treeViewItem)
{
return (bool)treeViewItem.GetValue(BringSelectedItemIntoViewProperty);
}
public static void SetBringSelectedItemIntoView(TreeViewItem treeViewItem, bool value)
{
treeViewItem.SetValue(BringSelectedItemIntoViewProperty, value);
}
public static readonly DependencyProperty BringSelectedItemIntoViewProperty =
DependencyProperty.RegisterAttached(
"BringSelectedItemIntoView",
typeof(bool),
typeof(perTreeViewItemHelper),
new UIPropertyMetadata(false, BringSelectedItemIntoViewChanged));
private static void BringSelectedItemIntoViewChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (!(args.NewValue is bool))
return;
var item = obj as TreeViewItem;
if (item == null)
return;
if ((bool)args.NewValue)
item.Selected += OnTreeViewItemSelected;
else
item.Selected -= OnTreeViewItemSelected;
}
private static void OnTreeViewItemSelected(object sender, RoutedEventArgs e)
{
var item = e.OriginalSource as TreeViewItem;
item?.BringIntoView();
// prevent this event bubbling up to any parent nodes
e.Handled = true;
}
}
然后,这可以用作TreeViewItems样式的一部分
<Style x:Key="perTreeViewItemContainerStyle"
TargetType="{x:Type TreeViewItem}">
<!-- Link the properties of perTreeViewItemViewModelBase to the corresponding ones on the TreeViewItem -->
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="IsEnabled" Value="{Binding IsEnabled}" />
<!-- Include the two "Scroll into View" behaviors -->
<Setter Property="vhelp:perTreeViewItemHelper.BringSelectedItemIntoView" Value="True" />
<Setter Property="vhelp:perTreeViewItemHelper.BringExpandedChildrenIntoView" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"
MinWidth="14" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander"
Grid.Row="0"
Grid.Column="0"
ClickMode="Press"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource perExpandCollapseToggleStyle}" />
<Border x:Name="PART_Border"
Grid.Row="0"
Grid.Column="1"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter x:Name="PART_Header"
Margin="0,2"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
ContentSource="Header" />
</Border>
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="Expander" Property="Visibility" Value="Hidden" />
</Trigger>
<!-- Use the same colors for a selected item, whether the TreeView is focussed or not -->
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="PART_Border" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TreeView}">
<Setter Property="ItemContainerStyle" Value="{StaticResource perTreeViewItemContainerStyle}" />
</Style>
更多详细信息以及我最近blog post的完整使用示例.
10月13日更新
在标准(非延迟加载模式)下运行时,博客文章已经过修改.关联的演示项目显示了在TreeView中显示的超过400,000个元素的嵌套数据结构,但是选择任何随机节点的响应是瞬时的.
内容总结
以上是互联网集市为您收集整理的c# – 带虚拟化的WPF TreeView – 选择项目并将其置于视图中全部内容,希望文章能够帮你解决c# – 带虚拟化的WPF TreeView – 选择项目并将其置于视图中所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。