Domanda

Ho una classe chiamata Book;

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

ListBox visualizza un elenco di libri e ItemTemplate è stato modificato in modo da rappresentare visivamente il libro. Il testo mostra il nome, l'autore e il numero di pagine del libro. La categoria, tuttavia, è rappresentata da un certo colore (ad esempio, la storia è blu, il romanticismo è rosso ecc.) Ora, il testo ha un effetto OuterGlowBitmap e un convertitore di valori dalla categoria (int) al colore appropriato. Tutto è associato in DataTemplate per ListBoxItem. Tecnicamente, tutto funziona bene.

Il problema, tuttavia, sono le prestazioni. Sembra che l'effetto bitmap outerGlow sia pesante sul processore, quindi quando ho un elenco di circa 500 libri, ci vogliono circa 500 ms per recuperare i dati dal database ma circa 10 secondi per caricare effettivamente gli elementi in ListBox. E anche quando il caricamento è terminato, lo scorrimento è molto lento. Ho provato a impostare VirtualizingStackPanel.IsVirtualizing su True, ma senza risultati. (Il numero massimo di libri che possono essere presenti nel database in qualsiasi momento è di circa 30000.)

Tuttavia, anche quando ci sono più di 100 voci nella casella di riepilogo, la mente umana non può elaborare molto rapidamente, quindi non ho l'obiettivo di caricare ed elencare all'utente tutti i libri che sono stati cercati. Questo è il motivo per cui ho creato una classe di navigazione wrapper BookNavigator che lega effettivamente la casella di riepilogo al suo oggetto ObservableCollection. Tutti i libri vengono caricati in questo BookNavigator, ma solo X di essi vengono visualizzati nella casella di riepilogo (aggiungendoli a ObservableCollection).

Il problema è che desidero che quel numero di libri visualizzati sia abbastanza piccolo da non visualizzare la barra di scorrimento per la casella di riepilogo, quindi posso implementare i miei metodi di scorrimento (Primo, Precedente, Successivo, Ultimo, o semplicemente il mio barra di scorrimento, non importa).

Come posso calcolare quanti elementi visualizzare in modo che la barra di scorrimento non sia visualizzata?

Vengono visualizzati due problemi: - Il ridimensionamento dell'applicazione può modificare le dimensioni della casella di riepilogo - Non tutti gli elementi della casella di riepilogo hanno la stessa altezza (a seconda del numero di autori).

Esiste un modo per ottenere ciò che sto cercando di fare?


MODIFICA (come risposta a Martin Harris)

Il problema con il codice suggerito da Martin Harris è che il ciclo foreach utilizza FrameworkElement, ma la casella di riepilogo è piena di oggetti di tipo Book che non ereditano da FrameworkElement, né ha altri mezzi per calcolare la sua altezza. L'elemento radice di ListBoxItem è una griglia, quindi forse sarebbe possibile recuperarla, ma non so come farlo?

Esiste un modo per ottenere gli elementi dell'interfaccia utente reali creati per rappresentare l'elemento della lista?


Modifica

Ho trovato questo Q / A che sembra essere quello di cui ho bisogno .. ItemContainerGenerator

È stato utile?

Soluzione 4

La soluzione può essere implicitamente trovata qui: Solution

Altri suggerimenti

Dopo aver provato a capire qualcosa di simile, ho pensato di condividere il mio risultato qui (poiché sembra più facile delle altre risposte):

Test di visibilità semplice che ho ottenuto da qui .

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

Successivamente è possibile scorrere ciclicamente i listboxitems e utilizzare quel test per determinare quali sono visibili. Il conteggio di questo elenco ti darebbe il numero di elementi visibili nella casella di riepilogo.

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

Questo conterrebbe quindi l'elenco degli elementi attualmente visualizzati nella casella di riepilogo (compresi quelli nascosti da scorrimento o qualcosa di simile).

Probabilmente potresti capire le dimensioni di tutti i libri prima di aggiungerli alla casella di riepilogo (possibilmente analizzando e popolando il modello XAML nel codice dietro quindi chiedendo al controllo esterno per le sue dimensioni) questo sarebbe molto lavoro per non molto guadagno. Non puoi semplicemente selezionare un numero di libri che sarà sufficiente per riempire la casella di riepilogo, ma non così tanti per rallentare il rendering e disattivare la barra di scorrimento? Ciò potrebbe essere ancora collegato alla dimensione della casella di riepilogo in modo che man mano che crescevano venivano aggiunti più articoli, ma il costo delle prestazioni per l'aggiunta di alcuni elementi extra dovrebbe essere inferiore al costo di calcolare nuovamente tutte le dimensioni.

Esempio rapido: supponiamo che la dimensione di un libro con un autore sia di 150 pixel. Puoi prendere la dimensione della casella di riepilogo e dividerla per 125 per ottenere una stima approssimativa del numero di elementi che sarebbero nel campo di gioco, ma non costosi da calcolare. Quello che vuoi evitare sono troppi elementi poiché lasceranno spazio vuoto.


Modificato alla luce del tuo commento.

In tal caso, è possibile aggiungere gli elementi alla casella di riepilogo (utilizzando il metodo sopra per fare un'ipotesi ravvicinata), quindi calcolare quale sia l'ultimo elemento completamente visibile e quindi rimuovere gli elementi extra.

Questo metodo di estensione otterrà l'ultimo elemento che è completamente mostrato in una casella di riepilogo o null se non sono visibili elementi:

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

Se l'elenco viene ingrandito, è possibile aggiungere alla raccolta abbastanza elementi da riempire il vuoto ed eseguire nuovamente il processo.

" Come posso calcolare quanti elementi visualizzare in modo che la barra di scorrimento non sia visualizzata? & Quot;

Risposta breve: (listBox1.Height / listBox1.ItemHeight)

Questo ti dà il numero di righe visualizzate / disponibili, quindi puoi leggere solo questo numero di righe e riempire tutta la casella di riepilogo.

Ora, la demo:

        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();

Questo esempio ti consente di scegliere il numero di elementi che saranno visibili, quindi è il numero di righe os che sono effettivamente disponibili per la visualizzazione. Pertanto, aggiungi solo " listbox_total_visible_items " gli elementi e la casella di riepilogo saranno pieni e non mostreranno le barre di scorrimento.

Codice spiegato:

  1. listbox_total_visible_items contiene il numero di righe da mostrare

  2. casella di riepilogo di installazione con le dimensioni appropriate, solo 2 righe

3-7. aggiungi alcune righe

  1. vai all'ultima riga, solo per divertimento

  2. mostra sulla barra di testo del modulo, il numero delle righe della lista, in base all'altezza della lista divisa per la dimensione di ciascun elemento.

Questo è tutto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top