Pregunta

Tengo una clase llamada Libro;

class Book
{
    public string Name { get; set; }
    public string Author { get; set; }
    public int PagesCount { get; set; }
    public int Category { get; set; }
}

ListBox muestra una lista de libros y ItemTemplate ha sido modificado para representar visualmente el libro. El texto muestra el nombre del libro, el autor y el número de páginas. Sin embargo, la categoría está representada por un determinado color (por ejemplo, el historial es azul, el romance es rojo, etc.) Ahora, el texto tiene un efecto OuterGlowBitmap y un convertidor de valores de la categoría (int) al color apropiado. Todo está vinculado en DataTemplate para ListBoxItem. Técnicamente, todo funciona bien.

El problema, sin embargo, es el rendimiento. Parece que el efecto de mapa de bits de Glow externo es pesado en el procesador, por lo que cuando tengo una lista de aproximadamente 500 libros, se necesitan unos 500 ms para recuperar los datos de la base de datos, pero alrededor de 10 segundos para cargar los elementos en el ListBox. E incluso cuando se realiza la carga, el desplazamiento es muy lento. Intenté establecer VirtualizingStackPanel.IsVirtualizing en True, pero fue en vano. (El número máximo de libros que pueden estar en la base de datos en un momento dado es de aproximadamente 30000).

Sin embargo, incluso cuando hay más de 100 elementos en el cuadro de lista, la mente humana no puede procesar tan rápido, por lo que no pretendo cargar y enumerar al usuario todos los libros que se buscan. Es por eso que he creado una clase de navegación de contenedor BookNavigator que realmente vincula el cuadro de lista a su objeto ObservableCollection. Todos los libros se cargan en este BookNavigator, pero solo X de ellos se muestran en el cuadro de lista (agregándolos a la colección observable).

El problema con esto es que quiero que esa cantidad de libros mostrados sea lo suficientemente pequeña para que listbox no muestre la barra de desplazamiento, de modo que pueda implementar mis propios métodos de desplazamiento (Primero, Anterior, Siguiente, Último, o simplemente el mío barra de desplazamiento, no importa).

¿Cómo puedo calcular cuántos elementos mostrar para que no se muestre la barra de desplazamiento?

Dos problemas emergentes: - Cambiar el tamaño de la aplicación puede cambiar el tamaño del cuadro de lista - No todos los elementos del cuadro de lista tienen la misma altura (según el número de autores).

¿Hay alguna forma de lograr lo que estoy tratando de hacer?


EDITAR (como respuesta a Martin Harris)

El problema con el código que sugirió Martin Harris es que el bucle foreach usa FrameworkElement, pero el cuadro de lista está lleno de objetos de tipo Libro que no hereda de FrameworkElement, ni tiene ningún otro medio para calcular su altura. El elemento raíz del ListBoxItem es una cuadrícula, por lo que tal vez sería posible recuperar esta cuadrícula, pero no sé cómo hacerlo.

¿Hay alguna forma de obtener los elementos de la interfaz de usuario reales que se crean para representar el elemento del cuadro de lista?


EDIT

Encontré este Q / A que parece ser lo que necesito ... ItemContainerGenerator

¿Fue útil?

Solución 4

La solución se puede encontrar implícitamente aquí: Solución

Otros consejos

Después de tratar de descubrir algo similar, pensé en compartir mi resultado aquí (ya que parece más fácil que las otras respuestas):

Prueba de visibilidad simple que obtuve de aquí .

private static bool IsUserVisible(FrameworkElement element, FrameworkElement container)
{
    if (!element.IsVisible)
        return false;

    Rect bounds =
        element.TransformToAncestor(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight));
    var rect = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight);
    return rect.Contains(bounds.TopLeft) || rect.Contains(bounds.BottomRight);
}

Luego puede recorrer los elementos de listbox y usar esa prueba para determinar cuáles son visibles. El recuento de esta lista le daría la cantidad de elementos visibles en el cuadro de lista.

private List<object> GetVisibleItemsFromListbox(ListBox listBox, FrameworkElement parentToTestVisibility)
{
    var items = new List<object>();

    foreach (var item in PhotosListBox.Items)
    {
        if (IsUserVisible((ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(item), parentToTestVisibility))
        {
            items.Add(item);
        }
        else if (items.Any())
        {
            break;
        }
    }

    return items;
}

Esto contendría la lista de elementos que se muestran actualmente en el cuadro de lista (incluidos los ocultos por desplazamiento o algo similar).

¿Probablemente podría calcular los tamaños de todos los libros antes de agregarlos al cuadro de lista (posiblemente analizando y rellenando la plantilla XAML en el código que está detrás y luego preguntando al control externo por su tamaño) Esto sería mucho trabajo para poco beneficio. ¿No puede simplemente seleccionar una cantidad de libros que serán suficientes para llenar el cuadro de lista, pero no tantos para ralentizar el renderizado y desactivar la barra de desplazamiento? Esto aún podría estar vinculado al tamaño del cuadro de lista para que a medida que creciera se agregaran más elementos, pero el costo de rendimiento para agregar algunos elementos adicionales debería ser menor que el costo de calcular todos los tamaños nuevamente.

Ejemplo rápido: supongamos que el tamaño de un libro con un autor es de 150 píxeles. Puede tomar el tamaño del cuadro de lista y dividirlo por 125 para obtener una estimación aproximada del número de elementos que estarían en el estadio, pero no es costoso de calcular. Lo que desea evitar son muy pocos elementos, ya que eso dejará un espacio vacío.


Editado a la luz de tu comentario.

En ese caso, podría agregar los elementos al cuadro de lista (utilizando el método anterior para obtener una aproximación aproximada), luego calcular cuál es el último elemento completamente visible y luego eliminar los elementos adicionales.

Este método de extensión obtendrá el último elemento que se muestra completamente en un cuadro de lista o nulo si no hay elementos visibles:

public static class ListBoxExtensions
{
    public static FrameworkElement GetLastItem(this ListBox listBox)
    {
        double height = listBox.ActualHeight;

        double currentHeight = 0;
        FrameworkElement previous = null;

        foreach (FrameworkElement item in listBox.Items)
        {
            currentHeight += item.ActualHeight;
            if (currentHeight > height)
            {
                return previous;
            }

            previous = item;
        }

        return previous;
    }
}

Si la lista se hace más grande, puede agregar suficientes elementos a la colección para llenar el vacío y volver a ejecutar el proceso.

" ¿Cómo puedo calcular cuántos elementos mostrar para que no se muestre la barra de desplazamiento? "

Respuesta corta: (listBox1.Height / listBox1.ItemHeight)

Esto le da el número de líneas mostradas / disponibles, por lo que puede leer solo este número de líneas y completará todo el cuadro de lista.

Ahora, la demostración:

        int listbox_total_visible_lines = 2;
        listBox1.Height = (listbox_total_visible_lines + 1) * listBox1.ItemHeight;
        listBox1.Items.Add("um");
        listBox1.Items.Add("dois");
        listBox1.Items.Add("tres");
        listBox1.Items.Add("quatro");
        listBox1.Items.Add("cinco");
        listBox1.SelectedIndex = listBox1.Items.Count - 1;
        this.Text = (listBox1.Height/ listBox1.ItemHeight).ToString();

Este ejemplo le permite elegir la cantidad de elementos que van a estar visibles, por lo que es la cantidad de líneas del sistema operativo las que están realmente disponibles para mostrar. Por lo tanto, agrega solo los " listbox_total_visible_items " elementos y el cuadro de lista estarán llenos y no mostrarán las barras de desplazamiento.

Explicación del código:

  1. listbox_total_visible_items contiene el número de líneas que se mostrarán

  2. cuadro de lista de configuración con el tamaño adecuado, solo 2 líneas

3-7. agregar algunas líneas

  1. ir a la última línea, solo por diversión

  2. muestra en la barra de texto del formulario, el número de líneas del cuadro de lista, en función de la altura del cuadro de lista dividido por el tamaño de cada elemento.

Eso es todo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top