5

Por lo tanto, se ve muy tonto tener una colección sin cromo si los artículos se cortan/recortan al final de la región de desplazamiento.Panel de virtualización que no recorta elementos

Quiero crear un panel de virtualización para colecciones (ItemsControl/ListBox) que solo dibuja elementos completos, nunca piezas de elementos. Por ejemplo:

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

enter image description here

que no quieren el contenedor parcial tercero que se mostrará a menos que haya espacio para el elemento/contenedor TODA a visualizar. En los ejemplos, el tercer elemento se recortó debido a la falta de espacio.

¿Alguna sugerencia? ¿Debería intentar reinventar la rueda (construir mi propio VirtualizingWholeItemPanel)?

EDITAR:

Microsoft aclaró que VirtualizingPanel.ScrollUnit no esté destinado a realizar esta funcionalidad en absoluto. Parece que VirtualizingPanel.ScrollUnit tiene un propósito muy similar al antiguo CanContentScroll en ScrollViewer.

+0

¿Está cambiando lo que ' VirtualizingPanel.ScrollUnit' está configurado en? Porque, de manera predeterminada, está establecido en 'Item', que es lo que estás buscando. Tal vez publiques algunos códigos y capturas de pantalla, y como se trata de una Vista previa del desarrollador, puedes enviar un ticket de problema a Microsoft Connect si es realmente un error. –

+0

Estoy estableciendo explícitamente 'ScrollUnit' en' Item'. Editaré y agregaré mi código de muestra. –

+0

Por lo que sé, es una "característica" de la virtualización. Para la velocidad, no reevalúa el ancho cuando se reutilizan los contenedores de la pantalla. Podría intentar horizontalcontent alignment = stretch.O puede repetir la lista de cadenas y establecer explícitamente el ancho para acomodar el más grande. O bien, puede establecer un ancho fijo que crea que se manejará más y activar el ajuste de texto. – Paparazzi

Respuesta

4

Tengo un método de ayuda que utilizo para determinar si un control es parcial o completamente visible dentro de un contenedor primario. Probablemente pueda usarlo con un Converter para determinar la visibilidad de los elementos.

Su convertidor sería o bien tendrá que calcular el contenedor padre del elemento de interfaz de usuario (Mi blog tiene un conjunto de Visual Tree Helpers que podría ayudar con esto si quiere), o podría ser un MultiConverter que acepta tanto el elemento de interfaz de usuario y la contenedor principal como parámetros.

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

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

El código para determinar la visibilidad de un control dentro de sus padres se ve así:

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

Editar

hizo algunas pruebas y, aparentemente, el convertidor se ejecute antes de que los controles están efectivamente prestados. Como un truco, funcionará si usa un MultiConverter y le pasa el ActualHeight del control, lo que obligará al convertidor a reevaluar cuando se represente el control.

Aquí está el convertidor de que estaba usando:

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

utilicé el XAML informados en su pregunta, y se agregó un estilo implícito para ListBoxItem en el .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> 
+0

ControlVisibility podría convertirse en una enumeración '[Flags]'. Nada de juego que cambie, solo una sugerencia. –

+0

Buena publicación. ¡Gracias! –

+1

@ m-y: no creo que haya ninguna razón para convertirlo en una enumeración de banderas. El valor nunca debe ser igual a más de una de las posibilidades. Desde mi punto de vista las enumeraciones de banderas se usan para concatenar múltiples valores junto con boolean &, |. –

Cuestiones relacionadas