防止TreeView中的自动水平滚动

Rob*_*ert 25 wpf

每当在我的树视图中选择一个节点时,它会自动对该项目进行水平滚动.有没有办法禁用它?

Qua*_*ter 30

处理RequestBringIntoView事件并将Handled设置为true,框架将不会尝试将项目置于视图中.例如,在XAML中执行以下操作:

<TreeView>
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <EventSetter Event="RequestBringIntoView" Handler="TreeViewItem_RequestBringIntoView"/>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>
Run Code Online (Sandbox Code Playgroud)

然后在您的代码隐藏中:

private void TreeViewItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
    e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法保留垂直滚动,只能防止水平滚动? (8认同)
  • 对于@MatthewPirocchi和其他具有相同问题的人:好像我找到了解决方案http://stackoverflow.com/a/34269542/692829 (2认同)

Dar*_*acz 14

我设法使用以下方法解决问题:

<TreeView ScrollViewer.HorizontalScrollBarVisibility="Hidden">
   <TreeView.ItemsPanel>
      <ItemsPanelTemplate>
         <StackPanel MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=1}}" />
      </ItemsPanelTemplate>
   </TreeView.ItemsPanel>
</TreeView>
Run Code Online (Sandbox Code Playgroud)

我将这里呈现ItemsPanel的StackPanel的宽度绑定到TreeView中的ContentPresenter的ActualWidth.

它也适用于"hacked"Stretching TreeView:http://blogs.msdn.com/b/jpricket/archive/2008/08/05/wpf-a-stretching-treeview.aspx(我修改了解决方案不是删除网格列,但将第一个Decorator元素的Grid.Column属性从1更改为2).


小智 6

Matthew,我管理以保留垂直滚动,并且仅在RequestBringIntoView事件引起的滚动之后通过恢复水平位置来阻止水平滚动.

private double treeViewHorizScrollPos = 0.0;
private bool treeViewResetHorizScroll = false;
private ScrollViewer treeViewScrollViewer = null;

private void TreeViewItemRequestBringIntoView( object sender, RequestBringIntoViewEventArgs e )
{
    if ( this.treeViewScrollViewer == null )
    {
        this.treeViewScrollViewer = this.DetailsTree.Template.FindName( "_tv_scrollviewer_", this.DetailsTree ) as ScrollViewer;
        if( this.treeViewScrollViewer != null )
            this.treeViewScrollViewer.ScrollChanged += new ScrollChangedEventHandler( this.TreeViewScrollViewerScrollChanged );
    }
    this.treeViewResetHorizScroll = true;
    this.treeViewHorizScrollPos = this.treeViewScrollViewer.HorizontalOffset;
}

private void TreeViewScrollViewerScrollChanged( object sender, ScrollChangedEventArgs e )
{
    if ( this.treeViewResetHorizScroll )
        this.treeViewScrollViewer.ScrollToHorizontalOffset( this.treeViewHorizScrollPos );

    this.treeViewResetHorizScroll = false;
}
Run Code Online (Sandbox Code Playgroud)


len*_*ena 6

我遇到了类似的问题.我需要防止水平滚动但保留垂直滚动.我的解决方案是处理OnRequestBringIntoView方法,因为我希望它的行为.我ResourceDictionary为a 创建了一个TreeViewItem并添加了EventSettersfor OnSelectedOnRequestBringIntoView方法.

MyResourceDictionary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  x:Class="Resources.MyResourceDictionary" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style TargetType="TreeViewItem" x:Key="treeitem" >
        <EventSetter Event="RequestBringIntoView"  Handler="OnRequestBringIntoView"/>
        <EventSetter Event="Selected" Handler="OnSelected"/>
    </Style>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)

MyResourceDictionary.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace Resources
{
    partial class MyResourceDictionary:ResourceDictionary
    {
        public MyResourceDictionary()
        {
            InitializeComponent();
        }

        private void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
        {
            e.Handled = true; //prevent event bubbling
            var item = (TreeViewItem)sender;
            TreeView tree = GetParentTree(item) as TreeView;
            if(tree!=null)
            {
                var scrollViewer = tree.Template.FindName("_tv_scrollviewer_", tree) as ScrollViewer;
                if (scrollViewer != null)
                {
                    scrollViewer.ScrollToLeftEnd();//prevent horizontal scroll
                    Point relativePoint = item.TransformToAncestor(tree).Transform(new Point(0, 0));//get position of a selected item 
                    if (relativePoint.Y <= scrollViewer.ContentVerticalOffset) return;//do no scroll if we select inside one 'scroll screen'
                    scrollViewer.ScrollToVerticalOffset(relativePoint.Y);//scroll to Y of a selected item
                }
            }
        }

        private DependencyObject GetParentTree(DependencyObject item)
        {
            var target = VisualTreeHelper.GetParent(item);
            return target as TreeView != null ? target : GetParentTree(target);
        }

        private void OnSelected(object sender, RoutedEventArgs e) //handle programmatically selected items
        {
            var item = (TreeViewItem)sender;
            item.BringIntoView();
            e.Handled = true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*ams 6

提供@ lena答案的略微简化版本:

要在保留水平滚动位置的同时垂直滚动,并且没有不必要的副作用,请在XAML中为RequestBringIntoView和Selected添加事件处理程序:

<TreeView>
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <EventSetter Event="RequestBringIntoView" Handler="TreeViewItem_RequestBringIntoView"/>
            <EventSetter Event="Selected" Handler="OnSelected"/>
            ...
Run Code Online (Sandbox Code Playgroud)

在后面的代码中,添加两个事件处理程序:

private void TreeViewItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
    // Ignore re-entrant calls
    if (mSuppressRequestBringIntoView)
        return;

    // Cancel the current scroll attempt
    e.Handled = true;

    // Call BringIntoView using a rectangle that extends into "negative space" to the left of our
    // actual control. This allows the vertical scrolling behaviour to operate without adversely
    // affecting the current horizontal scroll position.
    mSuppressRequestBringIntoView = true;

    TreeViewItem tvi = sender as TreeViewItem;
    if (tvi != null)
    {
        Rect newTargetRect = new Rect(-1000, 0, tvi.ActualWidth + 1000, tvi.ActualHeight);
        tvi.BringIntoView(newTargetRect);
    }

    mSuppressRequestBringIntoView = false;
}
private bool mSuppressRequestBringIntoView;

// Correctly handle programmatically selected items
private void OnSelected(object sender, RoutedEventArgs e)
{
    ((TreeViewItem)sender).BringIntoView();
    e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

  • 很棒的方法。您可以改进两件事: 1. 为了避免幻数,我建议使用“double.NegativeInfinity”和“double.PositiveInfinity”作为“newTargetRect”中的水平边界 2. 由于“TreeViewItem”包含其所有子“TreeViewItems” ` 在其范围内,此实现可能会导致不必要的垂直滚动。我建议使用 ((FrameworkElement)e.OriginalSource).ActualHeight 而不是 `tvi.ActualHeight` (2认同)