带有列表框的 WPF 滚动查看器 [英] WPF ScrollViewer with ListBox

查看:73
本文介绍了带有列表框的 WPF 滚动查看器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

需要你的帮助.我有一个显示 ScrollViewer 的 ListBox(带有虚拟化).我的 ListBox 项是可展开的,展开时它们的高度可能会超出可见滚动区域.

Need your help. I have a ListBox (with virtualization) which displays a ScrollViewer. My ListBox items are expandable, and while expanded their hight may exceed the visible scrolling area.

我遇到的问题是,当列表框项目超出可见滚动区域时 - 滚动跳转到下一个 ListBox 项目,而不是简单地滚动视图.

The problem i'm expiriencing is that when the list box item is exceeds the visible scrolling area - scrolling jumps to the next ListBox item rather than simply scrolling the view.

检查此代码:

    <ListBox Grid.Row="1" Grid.Column="0" DataContext="{Binding SpecPackageSpecGroupListViewModel}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"
                     ItemContainerStyle="{StaticResource SpecPackageSpecGroupListBoxStyle}" ScrollViewer.IsDeferredScrollingEnabled="True" 
                     ItemsSource="{Binding SortedChildren}" ScrollViewer.CanContentScroll="True"
                     Background="Transparent"
                     BorderThickness="0" SelectionMode="Extended"
                     Margin="5,5,5,5">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Controls:SpecPackageSpecGroupControl/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

当然,我不能用另一个滚动条包装我的 ListBox,因为它会关闭可视化(这对我来说非常无能).

Of-course, i can't wrap my ListBox with another scroller since it will turn off the visualization (which is very impotent to me).

如果我将 CanContentScroll 设置为 False 一切都按预期工作 - 但虚拟化停止工作.

If i set CanContentScroll to False everything works as expected - but the virtualization stops working.

帮助!!!

吉利

推荐答案

好的,就在我准备放弃并以某种方式学习如何处理这个错误之前,我遇到了一个帖子(我似乎无法find now) 这表明 TreeView 确实支持基于像素的滚动(AKA Physical Scrolling)而无需关闭可视化.

Ok, so just before i was about to give up and somehow learn how to live with this bug i bumped into a post (which i can't seem to find now) that suggests that TreeView does support Pixel-Based scrolling (AKA Physical Scrolling) without turning off visualization.

所以我尝试了这个,确实 - 它有效!确保验证虚拟化工作,测试了大约 1000 个项目,还在我的控件构造函数上设置了一个断点,并确保在我的视图滚动时调用它.

So i tried this and indeed - it works! Made sure to verify that virtualization works, tested with ~1000 items and also set a break point on my control constructor and made sure it is called when my view is scrolled.

使用 TreeView 而不是 ListBox 的唯一缺点是 TreeView 似乎不支持多项目选择(我需要) - 但实现这一点比实现 ListBox 的智能滚动要容易得多.

The only disadvantage of using TreeView instead of ListBox is that TreeView doesn't seem to support multiple item selection (which i needed) - but implementing this is way much easier than implementing the smart scrolling for ListBox.

我为 TreeViewItem 创建了一个样式,使 TreeViewItem 的外观和行为与 ListBoxItem 一样,这确实不是强制性的 - 但我更喜欢这样(除了基本样式存在拉伸问题,我必须通过样式修复)).基本上我删除了 ItemsPresenter 并且只使用 ContentPresenter 因为我的数据不是分层的:

I created a style for TreeViewItem that makes the TreeViewItem look and behave just like ListBoxItem, this is really not mandatory - but i preferred it like this (beside the fact that the basic style has stretching issues which i had to fix with styling). Basically i removed the ItemsPresenter and stayed only with the ContentPresenter since my data is not hierarchical:

    <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 方法.

Now - the only thing i've got left to do is implement the multi-selection tree view. There might be different approaches to implement such behavior, i took the ViewModel approach.

从 TreeView 派生,我创建了一个新的 MultiSelectionTreeView:

Derived from TreeView i created a new 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 如下:

Where IMultiSelectionTreeViewItemViewModel is as follows:

public interface IMultiSelectionTreeViewItemViewModel
{
    bool IsSelected { get; set; }
    void ClearSelectedSiblings();
}

当然 - 现在我有责任处理所选项目的呈现方式 - 在我的情况下,这是因为我的树视图项目有自己的 DataTemplate ,它具有选择的指示.如果这不是您的情况并且您需要它,只需扩展您的树视图项数据模板,以根据其视图模型 IsSelected 属性指示其选择状态.

Of course - now it is my responsibility to handle the way selected items are being presented - in my case it was given since my tree view items had their own DataTemplate which had indication for its selection. If this is not your case and you need it, simply extent your tree view item data template to indicate its selection state according to its view model IsSelected property.

希望有一天这会对某人有所帮助:-)玩得开心!

Hope this will help someone someday :-) Have fun!

吉利

这篇关于带有列表框的 WPF 滚动查看器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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