好吧,就在我准备放弃并以某种方式学习如何忍受这个错误之前,我偶然发现了一篇文章(我现在似乎找不到),该文章表明 TreeView 确实支持基于像素的滚动(又名物理滚动) )而不关闭可视化。
所以我尝试了这个,确实 - 它有效!确保验证虚拟化是否有效,使用约 1000 个项目进行测试,还在我的控件构造函数上设置断点,并确保在滚动视图时调用它。
使用 TreeView 而不是 ListBox 的唯一缺点是 TreeView 似乎不支持多项选择(我需要) - 但实现它比实现 ListBox 的智能滚动要容易得多。
我为 TreeViewItem 创建了一个样式,使 TreeViewItem 的外观和行为就像 ListBoxItem 一样,这实际上不是强制性的 - 但我更喜欢这样(除了基本样式存在拉伸问题,我必须通过样式来修复)。基本上我删除了 ItemsPresenter 并只保留 ContentPresenter,因为我的数据不是分层的:
<Style x:Key="MyTreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Border Name="myBorder"
SnapsToDevicePixels="true"
CornerRadius="0,0,0,0"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
BorderThickness="0"
BorderBrush="Transparent"
Height="Auto"
Margin="1,1,1,3"
Background="Transparent">
<ContentPresenter Grid.Column="1" x:Name="PART_Header" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
现在 - 我唯一要做的就是实现多选树视图。
可能有不同的方法来实现这种行为,我采用了 ViewModel 方法。
从 TreeView 派生,我创建了一个新的 MultiSelectionTreeView:
public class MultiSelectionTreeView : TreeView
{
private static bool CtrlPressed
{
get
{
return Keyboard.IsKeyDown(Key.LeftCtrl);
}
}
protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
{
base.OnSelectedItemChanged(e);
var previouseItemViewModel = e.OldValue as IMultiSelectionTreeViewItemViewModel;
if (previouseItemViewModel != null)
{
if (!CtrlPressed)
previouseItemViewModel.IsSelected = false;
}
var newItemViewModel = e.NewValue as IMultiSelectionTreeViewItemViewModel;
if (newItemViewModel != null)
{
if (!CtrlPressed)
newItemViewModel.ClearSelectedSiblings();
newItemViewModel.IsSelected = true;
}
}
}
其中IMultiSelectionTreeViewItemViewModel如下:
public interface IMultiSelectionTreeViewItemViewModel
{
bool IsSelected { get; set; }
void ClearSelectedSiblings();
}
当然 - 现在我有责任处理所选项目的呈现方式 - 在我的例子中,这是因为我的树视图项目有自己的 DataTemplate ,其中有其选择的指示。
如果这不是您的情况并且您需要它,只需扩展树视图项数据模板以根据其视图模型 IsSelected 属性指示其选择状态。
希望有一天这会对某人有所帮助:-)
玩得开心!
Gili