【发布时间】:2008-10-28 21:26:38
【问题描述】:
我正在使用 TreeView 控件,当单击其中一个控件时,它会自动滚动到左对齐 TreeViewItem。我已经查看了我的样式和控件模板,但我没有找到任何东西。是否存在导致此问题的默认 ControlTemplate?我想禁用它。
【问题讨论】:
我正在使用 TreeView 控件,当单击其中一个控件时,它会自动滚动到左对齐 TreeViewItem。我已经查看了我的样式和控件模板,但我没有找到任何东西。是否存在导致此问题的默认 ControlTemplate?我想禁用它。
【问题讨论】:
项目滚动是因为 ScrollViewer 对它们调用了 BringIntoView()。因此,避免滚动的一种方法是抑制对 RequestBringIntoView 事件的处理。您可以通过继承 TreeView 并实例化此控件来快速尝试:
public class NoScrollTreeView : TreeView
{
public class NoScrollTreeViewItem : TreeViewItem
{
public NoScrollTreeViewItem() : base()
{
this.RequestBringIntoView += delegate (object sender, RequestBringIntoViewEventArgs e) {
e.Handled = true;
};
}
protected override DependencyObject GetContainerForItemOverride()
{
return new NoScrollTreeViewItem();
}
}
protected override DependencyObject GetContainerForItemOverride()
{
return new NoScrollTreeViewItem();
}
}
【讨论】:
在这个问题上花了几个小时后,我找到了一个适合我的解决方案。
防止 TreeViewItem 上的 RequestBringIntoView 事件冒泡的解决方案是第一步。不幸的是,如果您以编程方式更改所选项目,这也会停止显示树视图项目
yourtreeview.SelectedItem = yourtreeviewitem
所以,对我来说,解决方案是修改treeview的controltemplate如下:
<Style x:Key="{x:Type TreeView}" TargetType="TreeView">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<Border Name="Border" BorderThickness="0" Padding="0" Margin="1">
<ScrollViewer Focusable="False" CanContentScroll="False" Padding="0">
<Components:AutoScrollPreventer Margin="0">
<ItemsPresenter/>
</Components:AutoScrollPreventer>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
“autoscrollpreventer”是:
using System;
using System.Windows;
using System.Windows.Controls;
namespace LiveContext.Designer.GUI.Components {
public class AutoScrollPreventer : StackPanel
{
public AutoScrollPreventer() {
this.RequestBringIntoView += delegate(object sender, RequestBringIntoViewEventArgs e)
{
// stop this event from bubbling so that a scrollviewer doesn't try to BringIntoView..
e.Handled = true;
};
}
}
}
希望对你有帮助..
【讨论】:
看来我在MSDN找到了一个很好的线索:
听起来这是一种互动 使用滚动查看器和焦点 系统。
当一个元素聚焦在一个 ScrollViewer(它是 TreeView 模板),ScrollViewer 被指示制作元素 可见的。它会自动响应 滚动到请求的元素。
ScrollViewer 内部的方法 处理这些焦点请求的是 所有私人和/或内部所以你 真的无法接近他们。我不 认为你可以做的太多了 这个案例;这就是焦点的工作原理。
那么,是这样吗?当然有一种方法可以修改 TreeView 模板,这样 ScrollViewer 就不会出现这种行为......
【讨论】:
好的,我终于可以得到这样的默认样式了:
using (Stream sw = File.Open(@"C:\TreeViewDefaults.xaml", FileMode.Truncate, FileAccess.Write))
{
Style ts = Application.Current.FindResource(typeof(TreeView)) as Style;
if (ts != null)
XamlWriter.Save(ts, sw);
}
生产者:
<Style TargetType="TreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style.Triggers>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing">
<Setter Property="ItemsControl.ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate><VirtualizingStackPanel IsItemsHost="True" /></ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</Style.Triggers>
<Style.Resources>
<ResourceDictionary />
</Style.Resources>
<Setter Property="Panel.Background">
<Setter.Value><DynamicResource ResourceKey="{x:Static SystemColors.WindowBrushKey}" /></Setter.Value>
</Setter>
<Setter Property="Border.BorderBrush">
<Setter.Value><SolidColorBrush>#FF828790</SolidColorBrush></Setter.Value>
</Setter>
<Setter Property="Border.BorderThickness">
<Setter.Value><Thickness>1,1,1,1</Thickness></Setter.Value>
</Setter>
<Setter Property="Control.Padding">
<Setter.Value><Thickness>1,1,1,1</Thickness></Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value><DynamicResource ResourceKey="{x:Static SystemColors.ControlTextBrushKey}" /></Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility">
<Setter.Value><x:Static Member="ScrollBarVisibility.Auto" /></Setter.Value>
</Setter>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility">
<Setter.Value><x:Static Member="ScrollBarVisibility.Auto" /></Setter.Value>
</Setter>
<Setter Property="Control.VerticalContentAlignment">
<Setter.Value><x:Static Member="VerticalAlignment.Center" /></Setter.Value>
</Setter>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer CanContentScroll="False"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
Background="{TemplateBinding Panel.Background}"
Padding="{TemplateBinding Control.Padding}"
Name="_tv_scrollviewer_"
SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
<Trigger Property="VirtualizingStackPanel.IsVirtualizing">
<Setter Property="ScrollViewer.CanContentScroll" TargetName="_tv_scrollviewer_">
<Setter.Value><s:Boolean>True</s:Boolean></Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>True</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
不幸的是,这看起来没有帮助。我没有看到任何用于停止自动滚动焦点的属性。
还在寻找……
【讨论】:
另一个有趣的花絮:有一个名为 HandlesScrolling 的可覆盖布尔值,它总是返回 true。反编译源代码后,看起来这个属性从未使用过(或者它正在 XAML 中的某个深、暗、秘密的地方使用)。我尝试制作自己的 TreeView 控件来将此值设置为 false,但它不起作用。
【讨论】: