Frage

Ich habe eine Klasse namens Buch;

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

Die List-Box zeigt eine Liste der Bücher und die ItemTemplate modifiziert wurde, um visuell das Buch darstellen. Der Text zeigt das Buch Namen, Autor und die Anzahl der Seiten. Die Kategorie, jedoch wird durch eine bestimmte Farbe dargestellt (zum Beispiel Geschichte ist blau, Romantik ist rot etc.) Nun wird der Text einen OuterGlowBitmap Effekt und einen Wertkonverter aus der Kategorie (int) an der entsprechenden Farbe hat. Alles ist in Datatemplate für ListBoxItem gebunden. Technisch funktioniert alles einwandfrei.

Das Problem ist jedoch, ist die Leistung. Es scheint, dass der outerGlow Bitmap-Effekt ist schwer auf dem Prozessor, so dass, wenn ich eine Liste von etwa 500 Büchern habe, dauert es etwa 500 ms, die Daten aus der Datenbank retreive aber etwa 10 Sekunden, um tatsächlich die Elemente in die List-Box zu laden. Und selbst wenn das Laden abgeschlossen ist, ist eine Rolle sehr laggy. Ich habe versucht, die VirtualizingStackPanel.IsVirtualizing auf True gesetzt, aber ohne Erfolg. (Die maximale Anzahl der Bücher, die in der Datenbank zu einem bestimmten Zeitpunkt sein können, beträgt etwa 30000).

Doch selbst wenn es mehr als 100 Elemente in der Listbox ist, kann die menschliche Verstand verarbeitet nicht so viel schneller, so strebe ich nicht alle zu laden und Liste die Bücher für den Benutzer, nach denen gesucht werden. Deshalb habe ich eine Wrapper-Navigations Klasse BookNavigator erstellt haben, die das Listenfeld zu seiner ObservableCollection-Objekt tatsächlich bindet. Alle Bücher sind in diesem BookNavigator geladen, aber nur X von ihnen werden im Listenfeld angezeigt wird (indem man sie auf die ObservableCollection hinzufügen).

Das Problem dabei ist, dass ich die Anzahl der angezeigten Bücher will für listbox klein genug ist, um nicht die Bildlaufleiste angezeigt werden, so kann ich meine eigenen Methoden zum Scrollen (First, Previous, Next, Last oder einfach meine eigenen implementieren Scrollbar, spielt keine Rolle).

Wie kann ich berechnen, wie viele Elemente angezeigt werden, so dass die Bildlaufleiste nicht angezeigt wird?

Zwei Probleme, die auftauchen: - die Listbox der ändern Größe kann die Anwendung Ändern der Größe - Nicht alle listbox Artikel sind von gleicher Höhe (in Abhängigkeit von der Anzahl der Autoren)

.

Gibt es eine Möglichkeit zu erreichen, was ich tun möchte?


EDIT (als Antwort auf Martin Harris)

Das Problem mit dem Code Martin Harris vorgeschlagen, dass die foreach-Schleife Framework verwendet, aber die Listbox mit Objekten des Typs Buch gefüllt ist, das nicht von Framework nicht erben, noch hat sie andere Mittel seine Höhe zu berechnen. Das Wurzelelement des ListBoxItem ist ein Gitter, so wäre es vielleicht möglich sein, dieses Netz zu retreive, aber ich weiß nicht, wie das zu tun?

Gibt es eine Möglichkeit an alle aktuellen UI-Elemente zu erhalten, die erstellt werden Sie den Eintrag vertreten?


Bearbeiten

Ich fand dieses Q / A, das zu sein, was scheint, ich brauche .. ItemContainerGenerator

War es hilfreich?

Lösung 4

Die Lösung kann implizit hier: Lösung

Andere Tipps

Nach dem Versuch, etwas ähnliches, um herauszufinden, dachte ich, ich würde hier mein Ergebnis teilen (wie es scheint einfacher als die anderen Antworten):

Einfacher Sichtbarkeitstest Ich habe von hier .

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

Danach können Sie die ListBoxItems Schleife durch und diesen Test verwenden, um die sichtbar sind, zu bestimmen. Die Zahl dieser Liste würden Sie die Anzahl der sichtbaren Elemente im Listenfeld geben.

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

Dies würde dann die Liste der Elemente enthält zur Zeit im Listenfeld gezeigt (auch versteckt durch Scrollen oder so ähnlich).

Werden Sie wahrscheinlich könnte herauszufinden, die Größen aller Bücher, bevor sie in das Listenfeld hinzugefügt (möglicherweise durch Parsen und die Vorlage XAML in Code bevöl hinter dann die äußere Steuerung für seine Größe zu fragen) dies würde eine Menge Arbeit für nicht viel Gewinn. Können nicht wählen Sie einfach nur eine Reihe von Büchern, die ausreichen werden, um das Listenfeld, aber nicht so viele verlangsamen die Wiedergabe und drehen Sie die Bildlaufleiste aus zu füllen? Dies könnte noch auf die Größe des List-Felds verknüpft werden, so dass es mehr Elemente wuchsen, wurden hinzugefügt, aber die Leistung Kosten ein paar zusätzliche Elemente für das Hinzufügen sollte weniger sein, dass die Kosten für die Berechnung alle Größen wieder.

Schnell Beispiel: Nehmen wir an, dass die Größe eines Buches mit einem Autor 150 Pixel ist. Sie konnten die Größe der List-Box nehmen und teilen sie durch 125 eine grobe Schätzung der Anzahl der Einzelteile zu erhalten, die in-the-Baseballstadion sein würde, aber nicht teuer zu berechnen. Was Sie wollen, ist zu wenig Artikel zu vermeiden, da die leeren Raum verlassen wird.


im Lichte Ihres Kommentars Herausgegeben.

In diesem Fall könnten Sie die Elemente in das Listenfeld hinzufügen (mit der oben beschriebenen Methode eine enge Vermutung zu bekommen), dann berechnen, welche das letzte vollständig sichtbare Element ist und dann die zusätzlichen Elemente entfernen.

Diese Erweiterung Methode wird das letzte Element erhalten, die vollständig in einem Listenfeld oder null angezeigt, wenn keine Elemente sind sichtbar:

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

Wenn die Liste größer gemacht wird dann genügend Elemente in die Sammlung, die Sie in der Lücke füllen und den Prozess erneut aus.

„Wie kann ich berechnen, wie viele Elemente angezeigt werden, so dass die Bildlaufleiste nicht angezeigt wird?“

Kurze Antwort: (ListBox1.Height / listBox1.ItemHeight)

Das gibt Ihnen die Anzahl der angezeigten / verfügbarer Leitungen, so dass Sie nur diese Anzahl von Zeilen lesen können und werden die ganze Listbox füllen.

Nun wird die 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();

In diesem Beispiel ist können Sie die Anzahl der Elemente auswählen, die sichtbar sein werden, so ist es die Anzahl os Linien, die actualy zur Verfügung zu zeigen sind. Daher fügen Sie nur die „listbox_total_visible_items“ Elemente und die Listbox wird voll sein und nicht die Bildlaufleisten zeigen.

-Code erklären:

  1. listbox_total_visible_items enthält die Anzahl der Zeilen angezeigt

  2. werden
  3. Setup listbox mit der richtigen Größe, 2 Zeilen nur

3-7. fügen Sie einige Zeilen

  1. gehen in die letzte Zeile, nur so zum Spaß

  2. auf dem Formular Textleiste zeigen, die Anzahl der listbox Linien, bezogen auf die Listbox Höhe durch die Größe der einzelnen Elemente aufgeteilt.

Das ist es.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top