5

したがって、アイテムがスクロール領域の最後でカット/クロップされている場合、クロムのないコレクションを持つのは本当にばかげているように見えます。

コレクション (ItemsControl/ListBox) の仮想化パネルを作成して、アイテムの一部ではなく、アイテム全体のみを描画したいと考えています。例えば:

 ______________
|              |
|______________|
 ______________
|              |
|______________|
 ______________
|              |

ここに画像の説明を入力

アイテム/コンテナ全体を表示する余地がない限り、3 番目の部分コンテナを表示したくありません。例では、スペースが不足しているため、3 番目の項目がトリミングされています。

助言がありますか?車輪の再発明を試みる必要がありますか (独自のものを構築しますVirtualizingWholeItemPanel)?

編集

VirtualizingPanel.ScrollUnitMicrosoftは、この機能を実行することをまったく意図していないことを明らかにしました。古いonVirtualizingPanel.ScrollUnitと非常によく似た目的を果たしているようです。CanContentScrollScrollViewer

4

1 に答える 1

4

コントロールが親コンテナー内で部分的にまたは完全に表示されているかどうかを判断するために使用するヘルパー メソッドがあります。おそらくConverter、アイテムの可視性を判断するために と一緒に使用できます。

コンバーターは、UI アイテムから親コンテナーを計算する必要があります (私のブログには、必要に応じてこれを支援できるビジュアル ツリー ヘルパーMultiConverterのセットがあります)。または、UI アイテムと親コンテナーの両方を受け入れる .パラメーター。

ControlVisibility ctrlVisibility= 
    WPFHelpers.IsObjectVisibleInContainer(childControl, parentContainer);

if (ctrlVisibility == ControlVisibility.Full 
    || isVisible == ControlVisibility.FullHeightPartialWidth)
{
    return Visibility.Visible;
}
else
{
    return = Visibility.Hidden;
}

親内でのコントロールの可視性を決定するコードは次のようになります。

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;
}

編集

いくつかのテストを行ったところ、コントロールが実際にレンダリングされる前にコンバーターが実行されるようです。ハックとして、 a を使用してコントロールMultiConverterの を渡すとActualHeight機能します。これにより、コントロールがレンダリングされるときにコンバーターが強制的に再評価されます。

私が使用していたコンバーターは次のとおりです。

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.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>
于 2012-02-23T16:10:53.950 に答える