虚拟化不裁剪项目的面板 [英] Virtualizing Panel that doesn't crop items
问题描述
因此,如果要在滚动区域的末尾剪切/裁剪项目,则拥有无铬的收藏集看起来真的很愚蠢。
So, it looks really silly to have a chrome-less collection if the items are getting cut/cropped at the end of the scroll region.
我想为集合(ItemsControl / ListBox)创建一个虚拟化面板,该面板仅绘制整个项目,而不绘制项目。例如:
I want to create a virtualizing panel for collections (ItemsControl/ListBox) that only draws whole items, never pieces of items. For example:
______________
| |
|______________|
______________
| |
|______________|
______________
| |
我不希望显示第三个部分容器,除非有空间显示整个项目/容器。在示例中,由于缺少空间而裁剪了第三项。
I don't want the 3rd partial container to be displayed unless there is room for the WHOLE item/container to be displayed. In the examples, the third item was cropped because of a lack of space.
有什么建议吗?我是否应该尝试重新发明轮子(构建自己的 VirtualizingWholeItemPanel
)?
Any suggestions? Should I try to reinvent the wheel (build my own VirtualizingWholeItemPanel
)?
编辑:
Microsoft澄清了 VirtualizingPanel。 ScrollUnit
根本不打算执行此功能。看来 VirtualizingPanel.ScrollUnit
的作用与 ScrollViewer <上的旧
CanContentScroll
的目的非常相似。 / code>。
Microsoft clarified that VirtualizingPanel.ScrollUnit
is not intended to perform this functionality at all. It appears that VirtualizingPanel.ScrollUnit
serves a very similar purpose to the old CanContentScroll
on ScrollViewer
.
推荐答案
我有一个辅助方法,用于确定控件是部分可见还是完全可见在父容器中。您可能可以将其与转换器
一起使用以确定项目的可见性。
I have a helper method which I use to determine if a control is partially or completly visible within a parent container. You can probably use it with a Converter
to determine the items' visibility.
您的转换器要么需要计算UI项目中的父容器(我的博客有一组可视树帮助器(如果需要,可以提供帮助),也可以是 MultiConverter
,它同时接受UI项和父容器作为参数。
Your converter would either need to calculate the parent container from the UI item (My blog has a set of Visual Tree Helpers that could assist with this if you want), or it could be a MultiConverter
that accepts both the UI item and the parent container as parameters.
ControlVisibility ctrlVisibility=
WPFHelpers.IsObjectVisibleInContainer(childControl, parentContainer);
if (ctrlVisibility == ControlVisibility.Full
|| isVisible == ControlVisibility.FullHeightPartialWidth)
{
return Visibility.Visible;
}
else
{
return = Visibility.Hidden;
}
确定控件在其父级中的可见性的代码如下:
The code to determine a control's visibility within it's parent looks like this:
public enum ControlVisibility
{
Hidden,
Partial,
Full,
FullHeightPartialWidth,
FullWidthPartialHeight
}
/// <summary>
/// Checks to see if an object is rendered visible within a parent container
/// </summary>
/// <param name="child">UI element of child object</param>
/// <param name="parent">UI Element of parent object</param>
/// <returns>ControlVisibility Enum</returns>
public static ControlVisibility IsObjectVisibleInContainer(
FrameworkElement child, UIElement parent)
{
GeneralTransform childTransform = child.TransformToAncestor(parent);
Rect childSize = childTransform.TransformBounds(
new Rect(new Point(0, 0), new Point(child.ActualWidth, child.ActualHeight)));
Rect result = Rect.Intersect(
new Rect(new Point(0, 0), parent.RenderSize), childSize);
if (result == Rect.Empty)
{
return ControlVisibility.Hidden;
}
if (Math.Round(result.Height, 2) == childSize.Height
&& Math.Round(result.Width, 2) == childSize.Width)
{
return ControlVisibility.Full;
}
if (result.Height == childSize.Height)
{
return ControlVisibility.FullHeightPartialWidth;
}
if (result.Width == childSize.Width)
{
return ControlVisibility.FullWidthPartialHeight;
}
return ControlVisibility.Partial;
}
编辑
进行了一些测试,显然转换器在实际呈现控件之前就开始运行了。作为一种hack,如果您使用 MultiConverter
并将其传递给控件的 ActualHeight
,它将起作用。
Did some tests and apparently the converter gets run before controls are actually rendered. As a hack, it will work if you use a MultiConverter
and pass it the ActualHeight
of the control, which will force the converter to re-evaluate when the control gets rendered.
这里是我使用的转换器:
Here's the converter I was using:
public class TestConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
FrameworkElement child = values[0] as FrameworkElement;
var parent = VisualTreeHelpers.FindAncestor<ListBox>(child);
ControlVisibility ctrlVisibility =
VisualTreeHelpers.IsObjectVisibleInContainer(child, parent);
if (ctrlVisibility == ControlVisibility.Full
|| ctrlVisibility == ControlVisibility.FullHeightPartialWidth)
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
{
return null;
}
}
我使用了您在问题中发布的XAML,并且只是在中为
ListBoxItem
添加了隐式样式。资源
I used the XAML you posted in your question, and just added an implicit style for ListBoxItem
in the .Resources
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Visibility">
<Setter.Value>
<MultiBinding Converter="{StaticResource Converter}">
<Binding RelativeSource="{RelativeSource Self}" />
<Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
这篇关于虚拟化不裁剪项目的面板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!