问题描述
我有列表框用的ScrollViewer
I have ListBox with 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 =真开不工作。它仍然滚动的物理单位。请告诉我错在我的code?谢谢!
But CanContentScroll="True" does't work. It's still scrolling in physical units. Whats wrong in my code? Thanks!
推荐答案
现在的问题是你的ScrollViewer和你StackPanel中,这是$ P $从找到的StackPanel pventing的ScrollViewer中之间的边界。 StackPanel中实现了IScrollInfo接口做逻辑滚动,但如果ScrollViewer中无法找到IScrollInfo孩子就后退做物理滚动。
The problem is the Border between your ScrollViewer and your StackPanel, which is preventing the ScrollViewer from finding the StackPanel. StackPanel implements the IScrollInfo interface to do logical scrolling, but if ScrollViewer can't find an IScrollInfo child it falls back to doing physical scrolling.
有三种方法来获得合理的滚动内的ScrollViewer:
There are three ways to obtain logical scrolling inside a ScrollViewer:
- 让ScrollViewer中的直接子的是一个面板,可以做逻辑滚动(如StackPanel中)
- 让ScrollViewer中的直接子的是一个项目presenter其中presents这样一个小组
- 让ScrollViewer中的直接子的是你自己写的一个实现IScrollInfo的自定义类
- Let the ScrollViewer's direct child be a panel that can do logical scrolling (such as a StackPanel)
- Let the ScrollViewer's direct child be an ItemsPresenter which presents such a panel
- Let the ScrollViewer's direct child be a custom class you write yourself that implements IScrollInfo
简单的解决方案
前两种解决方案是不言自明的,但我要指出的是,使用项目presenter可能比直接包括你的StackPanel在模板一个更好的主意。这样,在解决方案中的其他列表框可以利用你的ControlTemplate而不被强迫使用相同的面板。换句话说,我会做这样的事情,而不是你写的:
The first two solutions are self-explanatory, but I want to point out that using an ItemsPresenter is probably a better idea than directly including your StackPanel in your template. That way other ListBoxes in your solution can take advantage of your ControlTemplate without being forced into using an identical panel. In other words, I would do something like this instead of what you wrote:
<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的项目,你需要假东西敲了一下。
If really need to display a border around a logically-scrolling StackPanel but have that border appear to scroll with the data, you'll have to do some additional plumbing. When a StackPanel is doing logical scrolling, the StackPanel itself scrolls its contents during arrange and the ScrollViewer doesn't do any actual scrolling at all (it just manages scrollbars, etc). You'll find that StackPanel adamantly refuses to scroll anything that isn't actually one of its Children, so unless your border can be an actual ListBox item, you need to fake things out a bit.
要使它看起来像一个边界正在随着StackPanel的内容滚动:
To make it look like a Border is being scrolled along with the StackPanel contents:
- 创建一个CompoundScrolling自定义控件实现IScrollInfo来管理它。
- 给你的CompoundScrolling控制,其中包括一个网格的模板。
- 在网格把边框和StackPanel中,与上StackPanel中背部和适当的利润边界。
- 实施所有IScrollInfo属性和方法调用上的StackPanel等效方法(你可以给它一个PART_名称,发现它在OnApplyTemplate)
- 当IScrollInfo方法代理,并在OnMeasure,OnArrange等,检查的StackPanel的滚动状态和更新边框的位置相匹配。
在检测StackPanel中的滚动状态,可以通过调用ItemContainerGenerator.ContainerFromIndex 0和Items.Count-1,那么检查的StackPanel内的那些容器的定位,看看它们是否可见来完成。如果是这样,顶部和底部(或左和右的方向=水平)的边界的两侧应该是可见的,否则他们不应该。另一侧将当然,始终可见。
Detecting the StackPanel's scrolling state can be done by calling ItemContainerGenerator.ContainerFromIndex on 0 and Items.Count-1, then checking the positioning of those containers within the StackPanel to see if they are visible. If so, the top and bottom (or left and right for Orientation=Horizontal) sides of your Border should be visible, otherwise they should not be. The other sides will, of course, always be visible.
这篇关于列表框,的ScrollViewerиCanContentScroll的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!