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.
I want to create a virtualizing pan
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.
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
}
///
/// Checks to see if an object is rendered visible within a parent container
///
/// UI element of child object
/// UI Element of parent object
/// ControlVisibility Enum
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;
}
Edit
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(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;
}
}
I used the XAML you posted in your question, and just added an implicit style for ListBoxItem in the .Resources