.net 列表框,滚动查看器и;癌症卷轴

.net 列表框,滚动查看器и;癌症卷轴,.net,wpf,.net,Wpf,我有带ScrollViewer的列表框 <ScrollViewer Focusable="False" CanContentScroll="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled"> <ListBox ItemsSource="{Bin

我有带ScrollViewer的列表框

<ScrollViewer Focusable="False" CanContentScroll="True"                     
                  HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled">            
         <ListBox ItemsSource="{Binding Path=MyItems}" VerticalAlignment="Stretch" Focusable="False">
                <ListBox.ItemContainerStyle>                    
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="OverridesDefaultStyle" Value="true"/>
                    <Setter Property="HorizontalContentAlignment"  Value="Stretch"/>                        
                    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                <Border CornerRadius="3,3,3,3">
                                    <Grid>
                                        <myControls:MyControl/>
                                    </Grid>    
                                </Border>     
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.Style>
                <Style TargetType="ListBox">
                    <Setter Property="SnapsToDevicePixels" Value="true"/>
                    <Setter Property="OverridesDefaultStyle" Value="true"/>
                    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
                    <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>        
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="ListBox">                                    
                                <ScrollViewer Focusable="False" CanContentScroll="True">
                                    <Border>                                           
                                        <StackPanel Margin="2"           Orientation="Horizontal" IsItemsHost="True"/>                                                                           
                                    </Border>
                                </ScrollViewer>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.Style>
        </ListBox>           
    </ScrollViewer>

但是CanContentScroll=“True”不起作用。它仍然以物理单位滚动。
我的代码有什么问题?谢谢

问题在于ScrollViewer和StackPanel之间的边界,这会阻止ScrollViewer找到StackPanel。StackPanel实现了IScrollInfo接口来执行逻辑滚动,但是如果ScrollViewer找不到IScrollInfo子级,它会返回到物理滚动

有三种方法可以在ScrollViewer中获得逻辑滚动:

  • 让ScrollViewer的直接子级成为可以进行逻辑滚动的面板(例如StackPanel)
  • 让ScrollViewer的直接子级为ItemsPresenter,它显示这样一个面板
  • 让ScrollViewer的直接子类成为您自己编写的实现IScrollInfo的自定义类
  • 简单的解决方案

    前两种解决方案不言自明,但我想指出,使用ItemsPresenter可能比直接在模板中包含StackPanel更好。这样,解决方案中的其他列表框就可以利用ControlTemplate,而不用被迫使用相同的面板。换句话说,我会这样做,而不是你写的:

    <ListBox>
      <ListBox.ItemContainerStyle>
        ...
      </ListBox.ItemContainerStyle>
    
      <ListBox.ItemsPanel>
        <ItemContainerTemplate>
          <StackPanel Margin="2" Orientation="Horizontal" ... />
        </ItemContainerTemplate>
      </ListBox.ItemsPanel>
    
      <ListBox.Template>
        <ControlTemplate>
          <ScrollViewer Focusable="False" CanContentScroll="True">   
            <ItemsPresenter />
          </ScrollViewer>
        </ControlTemplate>
      </ListBox.Template>
    </ListBox>
    
    
    ...
    
    先进技术

    若确实需要在逻辑滚动的StackPanel周围显示边框,但该边框显示为随数据滚动,则必须执行一些额外的管道操作。当StackPanel执行逻辑滚动时,StackPanel本身在排列期间滚动其内容,ScrollViewer根本不执行任何实际滚动(它只管理滚动条等)。你会发现StackPanel坚决拒绝滚动任何实际上不是它的子项的内容,所以除非你的边框可以是一个实际的ListBox项,否则你需要稍微假装一下

    要使其看起来像是边框与StackPanel内容一起滚动:

  • 创建一个“CompoundScrolling”自定义控件来管理实现IScrollInfo的控件
  • 为“CompoundScrolling”控件提供一个包含网格的模板
  • 在网格中放置边框和StackPanel,边框在后面,StackPanel上有适当的边距
  • 通过调用StackPanel上的等效方法来实现所有IScrollInfo属性和方法(您可以给它一个PART_uu名称并在OnApplyTemplate中找到它)
  • 每当IScrollInfo方法被代理时,以及在OnMeasure、OnArrange等中,检查StackPanel的滚动状态并更新边框的位置以匹配
  • 通过在0和Items.Count-1上调用ItemContainerGenerator.ContainerFromIndex,然后检查这些容器在StackPanel中的位置,查看它们是否可见,可以检测StackPanel的滚动状态。如果是这样,边框的顶部和底部(或方向=水平的左侧和右侧)应可见,否则不应可见。当然,其他方面总是可见的