WPF TreeView - 键盘导航性能低下 [英] WPF TreeView - Slow Performance in Keyboard Navigation

查看:160
本文介绍了WPF TreeView - 键盘导航性能低下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个TreeView,它是一个填充的运行时。它定义如下:

 < TreeView ItemsSource ={Binding Path = RootItem.ChildItems}> 

< TreeView.ItemContainerStyle>
< Style TargetType ={x:Type TreeViewItem}>
< Setter Property =IsExpandedValue ={Binding IsExpanded,Mode = TwoWay}/>
< Setter Property =IsSelectedValue ={Binding IsSelected,Mode = TwoWay}/>
< / Style>
< /TreeView.ItemContainerStyle>

< TreeView.ItemTemplate>
...
< /TreeView.ItemTemplate>
< / TreeView>

我正在使用Style / Setter的部分,使我可以绑定两个属性 IsSelected IsExpanded 到相同名称的属性(类型为 bool )的基础项目,因为我正在使用它们来确定何时以及如何异步加载子项。



树视图中显示的项目全部继承自相同的基础类我绑定的属性如下所示:

  public bool IsExpanded 
{
get {return _IsExpanded; }
set
{
if(HasAsynchChildItems)
if(value)
LoadChildItems();
else if(!value)
Collapse();
_IsExpanded = value;
}
}

HasAsynchChildItems 是一个确定是否应该异步加载子项目的属性。 Load code> LoadChildItems()是加载它们的。它是异步的



只要只有几个项目,一切都正常。




在树上某一点,有大约2500多个项目,应用程序开始变得无响应,需要大约20-30秒加载。不仅如此,当它们加载完毕后,当我更改选择时,该应用程序会延迟10秒钟。



所有导致应用程序变慢的项目都有 HasAsycnchChildItems 假的。所以 LoadChildItems()不会启动。



我是通过style setter绑定的问题吗? >

PS:我也用Performance Explorer监控了这个东西,Visual Studio告诉我90%的处理时间在 PresentationFramework.ni.dll



任何想法?



编辑 p>

经过一番调查,我需要更新问题:



  1. 选择和展开也几乎是即时的。


  2. 什么真正的停顿挂起应用程序,是通过键盘导航节点(向上+向下箭头)。大约需要15秒。如果我通过鼠标点击更改选择,那么是立即的。



解决方案

已经找到了一些解决方法。



正如我在上面的评论中所述(因此我再次编辑了我的原始问题),我发现问题不在于DataBinding ,也没有任何其他数据相关的发行。这只是TreeView控件本身的一个问题,以及它如何处理键盘导航。



如果您浏览TreeView,则问题仅出现 向下箭头向下箭头



不会发生 PageDown PageUp 鼠标点击



所以这里是我做的。首先,我在我的TreeView上启用了虚拟化,它单独已经改善了很多,但还不能令人满意:

  ; TreeView ItemsSource ={Binding Path = RootItem.Items}Grid.Row =1
VirtualizingStackPanel.IsVirtualizing =True
VirtualizingStackPanel.VirtualizationMode =Recycling

我做的第二件事是编写自己的自定义事件处理程序,以通过ArrowUp / ArrowDown处理TreeView的导航。我必须补充说,我完全不喜欢写这样的代码(这也只是一个快速测试/实验的结果,所以也许是龙!)。进一步:我的TreeView中的所有项目都继承自基础类 ManagementItem ,它提供 IsSelected IsExpanded 索引(表示项目在父项的子项目中的位置)。

  private void TreeView_PreviewKeyDown(object sender,KeyEventArgs e)
{
var tv = sender as TreeView;
var item = tv.SelectedItem作为ManagementItem;

e.Handled = false;

如果(e.Key == Key.Down)
尝试
{
if(item.IsExpanded)
item.Items.First() .IsSelected = true;
else
if(item.Index == item.Owner.Items.Count - 1)
item.Owner.Owner.Items [item.Owner.Index + 1] .IsSelected = true ;
else
item.Owner.Items [item.Index + 1] .IsSelected = true;
e.Handled = true;
} catch {}

if(e.Key == Key.Up)
try
{
if(item.Index == 0)
item.Owner.IsSelected = true;
else
item.Owner.Items [item.Index - 1] .IsSelected = true;
e.Handled = true;
} catch {}

}

这增加了导航性能大幅度地。


I have a TreeView which is populated runtime. It is defined like this:

<TreeView ItemsSource="{Binding Path=RootItem.ChildItems}">

  <TreeView.ItemContainerStyle>
    <Style TargetType="{x:Type TreeViewItem}">
      <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    </Style>
  </TreeView.ItemContainerStyle>

  <TreeView.ItemTemplate>
  ...    
  </TreeView.ItemTemplate>
</TreeView>

I am using the part with the Style / Setter to making it possible for me to bind the two properties IsSelected and IsExpanded to properties of the same name (of type bool) of the base items as I am using them to determine when and how to asynchronously load in the child items.

The items displayed on the treeview all inherit from the same base class. The property I bind to looks like this:

public bool IsExpanded
{
  get { return _IsExpanded; }
  set
  {
    if (HasAsynchChildItems)
      if (value)
        LoadChildItems();
      else if (!value)
        Collapse();
    _IsExpanded = value;
  }
}

HasAsynchChildItems is a propertay that determines if child items should be loaded in asynchronously or not. LoadChildItems() is the one loading them. It's async.

As long as there are only a few items, everything works fine.

At a certain point down the tree there are about 2500+ items and the app begins to become unresponsive and take about 20-30 sec to load. Not only that, but after they are loaded, the app hangs againg for 10+ seconds when I change selection.

All of those items that cause the app to become slow have HasAsycnchChildItems set to false. So LoadChildItems() does not start.

Is the problem that I am binding via style setter?

PS: I have also monitored the thing with Performance Explorer, and Visual Studio tells me that 90% of processing time goes down in PresentationFramework.ni.dll.

Any ideas?

EDIT

After a bit more investigation, I need to update the question:

  1. I found that loading really is fast. The items almost instantly display after they're retrieved from the DB.

  2. Selecting and expanding is also almost instant.

  3. What really stalls hangs the application, is navigating through the nodes via keyboard (up + down arrow). It takes about 15sec each. If I change selection via mouse click, it is immediate.

解决方案

I have found some kind of workaround.

As I stated above in my comment (and therefore I edited my original question again) I have found out that the problem lies neither in DataBinding, nor is it any other data-related issued. It is just an issue with the TreeView control itself, and how it handles keyboard navigation.

The issue appears only if you navigate through the TreeView by UpArrow or DownArrow.

It does not happen with PageDown, PageUp or Mouse-Click.

So here is what I did. First of all, I enabled virtualization on my TreeView, which alone already improved things a lot, but was not yet satisfying:

<TreeView ItemsSource="{Binding Path=RootItem.Items}" Grid.Row="1"
          VirtualizingStackPanel.IsVirtualizing="True"
          VirtualizingStackPanel.VirtualizationMode="Recycling"

The second thing I did was writing my own custom event handler to handle navigation through the TreeView by ArrowUp / ArrowDown. I must add that I totally dislike writing code like that (and it is also just a result of a quick test / experiment, so maybe dere be dragons!). Further: all items in my TreeView inherit from the base class ManagementItem that provides IsSelected, IsExpanded, Index (which indicates the position of the item inside the parent's child items).

private void TreeView_PreviewKeyDown(object sender, KeyEventArgs e)
{
  var tv = sender as TreeView;
  var item = tv.SelectedItem as ManagementItem;

  e.Handled = false;

  if (e.Key == Key.Down)
    try
    {
      if (item.IsExpanded)
        item.Items.First().IsSelected = true;
      else
        if (item.Index == item.Owner.Items.Count - 1)
          item.Owner.Owner.Items[item.Owner.Index + 1].IsSelected = true;
        else
          item.Owner.Items[item.Index + 1].IsSelected = true;
      e.Handled = true;
    } catch {}

  if (e.Key == Key.Up)
    try
    {
      if (item.Index == 0)
        item.Owner.IsSelected = true;
      else
        item.Owner.Items[item.Index - 1].IsSelected = true;
      e.Handled = true;
    } catch {}

 }

This increased navigation performance drastically.

这篇关于WPF TreeView - 键盘导航性能低下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆