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)
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)
我遇到了类似的问题.我需要防止水平滚动但保留垂直滚动.我的解决方案是处理OnRequestBringIntoView方法,因为我希望它的行为.我ResourceDictionary为a 创建了一个TreeViewItem并添加了EventSettersfor OnSelected和OnRequestBringIntoView方法.
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)
提供@ 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)