2013-03-27 11 views
7

Wir erstellen eine WPF-Anwendung, die stark verzierte Eingabeelemente verwendet. Ein einfaches Beispiel für ein dekoriertes Element ist eine TextBox, die wie ein schreibgeschützter TextBlock aussieht, wenn sie keinen Fokus hat, und nach dem Empfangen des Fokus zu einer TextBox wird. Außerdem wird zusätzliches visuelles Feedback bereitgestellt, wenn der geänderte Wert in der Datenbank gespeichert wird. Das Problem besteht darin, dass das Anzeigen einer Ansicht, die viele dieser Elemente enthält (z. B. 100), sehr langsam ist und die Anwendung sehr unempfindlich macht.Wie UI-Elemente in WPF träge erstellen?

Wir haben diesen Decorator als UserControl implementiert, das alle erforderlichen Elemente enthält (z. B. den TextBlock zum Anzeigen von unfokussiertem Text und rotierendes Bild für den Busy-Indikator). Dann fügen wir das Eingabeelement als Kind dieses Decorator-Steuerelements hinzu, was bedeutet, dass der Decorator zusätzlich zu allen zusätzlichen Elementen auch das Eingabeelement in seinem visuellen Baum enthält. In XAML würde dies wie folgt aussehen:

<custom:Decorator Context="{Binding ValueHelper}" > 
    <TextBox Text="{Binding ValueHelper.Text}"/> 
</custom:Decorator> 

Das macht es einfach für uns jedes Eingabeelement wir wollen dekorieren, sei es entweder Textfeld, Datumsauswahl, Combobox oder jedes individuelle Element.

Nun zurück zum Problem: Sagen wir, wir haben eine Ansicht, die 100 dekorierte Textfelder enthält, und wir navigieren zu dieser Ansicht. Was geschieht? Zumindest mein Quad-Core-Laptop friert für eine lange Zeit, weil es viele hundert Textblöcke, Rechtecke, Bilder usw. erstellen muss, um das visuelle Feedback für jedes dekorierte Element zu liefern, obwohl keine Dekorationen noch sichtbar sind. Was wirklich benötigt wird, sind nur 100 TextBlocks, weil das auf dem Bildschirm sichtbar ist. Es ist nur, nachdem das Element Maus über Ereignis oder Fokus empfängt, wenn andere Elemente benötigt werden. Außerdem wird immer nur ein Element bearbeitet, sodass nur ein Eingabeelement (in diesem Fall ein Textfeld) für die gesamte Anwendung ausreicht.

Also, was wäre der beste Weg, um die gleichen Dekorationen zu erreichen, ohne alle Dekorationselemente (oder das eigentliche Eingabeelement) für jedes Element in der Ansicht zu erstellen?


Ein Beispiel dekoriert TextBox Anwendungsfall zu klären:

Das Textfeld sieht aus wie ein Nur-Lese-Textblock, wenn es nicht den Fokus oder Mauszeiger hat, ist derzeit nicht oben drauf (Zustand 1). Außerdem werden drei Punkte ("...") angezeigt, da das Element momentan keinen Wert hat.

Wenn der Mauszeiger über das Element bewegt wird, wird um TextBlock herum ein gepunktetes grünes Rechteck angezeigt, um anzuzeigen, dass das Element geändert werden kann (Status 2). Die Farbe wäre rot, wenn TextBox schreibgeschützt wäre.

Nach dem Empfang wird das Fokuselement zu einer tatsächlichen TextBox, mit der der tatsächliche Wert geändert werden kann (Status 3).

Der Wert wird in der Datenbank gespeichert, nachdem das Textfeld seinen Fokus verliert, und um anzuzeigen, dass der Wert gerade gespeichert wird, erscheint ein Besetztzeichen auf der linken Seite des Elements (Status 4).

Schließlich wurde der Wert gespeichert und das Element kehrt in seinen Leerlaufzustand zurück und zeigt den neuen Wert an (Status 5). (Tatsächlich haben die Elemente noch mehr Zustände, die mit der Validierung und anderen spezifischen Anforderungen zusammenhängen, aber Sie haben sicherlich den Punkt erreicht, dass Elemente wirklich hoch dekoriert sind.

)

enter image description here

Antwort

4

Statt alle UI-Elemente im Voraus von zeichnen, zeichnen sie nur die, die benötigt

WPF ermöglicht es Ihnen, die Template eines Objekts zu ändern, um eine DataTrigger verwenden, so dass Sie die Vorlage anpassen können für Ihre Decorator basierend auf Ihren Trigger

Ein Beispiel Stil für Ihren Decorator könnte wie folgt aussehen:

<Style TargetType="{x:Type ContentControl}"> 
    <!-- Default Template --> 
    <Setter Property="ContentTemplate" 
      Value="{StaticResource NoDecoratorTemplate}" /> 

    <Style.Triggers> 
     <DataTrigger Property="Text" Value=""> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource BlankTemplate}" /> 
     </DataTrigger> 
     <Trigger Property="IsMouseOver" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource MouseOverTemplate}" /> 
     </Trigger> 
     <Trigger Property="IsFocused" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource FocusedTemplate}" /> 
     </Trigger> 
     <DataTrigger Property="{Binding IsLoading}" Value="True"> 
      <Setter Property="ContentTemplate" 
        Value="{StaticResource LoadingTemplate}" /> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 

Außerdem sollte WPF nicht sichtbare Elemente nicht laden. Sie können versuchen, Ihre Dekoratoren Visibility="Collapsed" als Test zu setzen, um zu sehen, ob das die Ladezeit behebt.

Wenn es funktioniert und Sie nicht die Template Weg gehen möchten, können Sie sicherstellen, dass die Visibility aller Ihrer Objekte zu Collapsed gesetzt zu beginnen, und sie nur zu Visible gesetzt werden, wenn sie angezeigt werden sollen.

Wenn es Ihre Ladezeit nicht repariert, dann ist Ihr Problem wahrscheinlich woanders. Zum Beispiel sieht es so aus, als ob einige Ihrer Decorator-Elemente entsprechend der darin enthaltenen Inhaltskontrolle dimensioniert sind. Es ist also möglich, dass Sie die Objekte nicht verlangsamen, sondern die Größe der Objekte bestimmen.

+0

Vielen Dank! Kontrollschablonen sind definitiv der richtige Weg, um Elemente zu dekorieren. Dies behebt jedoch nicht das Problem mit dem tatsächlichen Eingabeelement. TextBox ist unser leichtestes Element und wir haben viel schwerere benutzerdefinierte Eingabeelemente (z. B. Datumsauswahl), die wir uns nicht leisten können. Wir haben die Sichtbarkeit bereits reduziert, aber dennoch wird der visuelle Baum erstellt und alle zugehörigen Ressourcen werden geladen, was schwerwiegende Leistungsprobleme verursacht. – user544511

+0

@ user544511 Wenn Sie sagen, dass alle zugehörigen Ressourcen geladen sind, meinen Sie, dass jeder Decorator geladen ist? Wenn Sie ein einzelnes UI-Steuerelement für den Decorator verwenden und die Vorlage austauschen, sollten Sie dieses Verhalten nicht erhalten, da nur ein Element in der visuellen Struktur zu einer Zeit existiert – Rachel

+0

Sorry, ich war im Urlaub und konnte nicht früher antworten. Ich meinte, dass das tatsächliche Eingabeelement (das ein Kind von Decorator ist, z. B. Datumsauswahl oder TextBox) erstellt wird, alle seine Ressourcen (einschließlich untergeordnete Elemente) geladen und der visuellen Struktur hinzugefügt werden (auch wenn es minimiert ist). Dies verursacht einen enormen Leistungseinbruch, da der Datumsaufnehmer ein viel schwereres Element als z.B. eine TextBox. – user544511

Verwandte Themen