2013-03-27 8 views
7

Jesteśmy tworzenia aplikacji WPF, który sprawia, że ​​ciężkie użycia wysoce zdobionych elementów wejściowych. Prostym przykładem dekorowanego elementu jest TextBox, który wygląda jak TextBlock tylko do odczytu, gdy nie ma fokusu, i zmienia się w TextBox po otrzymaniu fokusa. Ponadto dodatkowa wizualna informacja zwrotna jest dostarczana, gdy zmieniona wartość jest zapisywana w bazie danych. Problem polega na tym, że wyświetlanie widoku zawierającego wiele z tych elementów (powiedzmy 100) jest bardzo powolne i powoduje, że aplikacja bardzo nie odpowiada.Jak tworzyć elementy interfejsu użytkownika leniwie w WPF?

Wdrożyliśmy ten dekorator jako UserControl, który zawiera wszystkie wymagane elementy (na przykład TextBlock pokazać niezogniskowany tekst i obracanie obrazu dla wskaźnika zajęty). Następnie dodajemy element wejściowy jako element podrzędny tego sterowania dekoratorem, co oznacza, że ​​oprócz wszystkich dodatkowych elementów, dekorator zawiera również element wejściowy w jego drzewie graficznym. W XAML będzie to wyglądać tak:

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

To ułatwia nam ozdobić każdy element wejściowy chcemy być to albo pole tekstowe, data kompletacji, combobox lub każdy element niestandardowy.

Teraz wracamy do problemu: załóżmy, że mamy widok, który zawiera 100 ozdobionych pól tekstowych i przechodzimy do tego widoku. Co się dzieje? Przynajmniej mój quad-core laptop zawiesza się przez długi czas, ponieważ ma stworzyć wiele sto bloki tekstu, prostokątów, obrazy itd., Aby zapewnić wizualnie dla każdego elementu zdobione, choć żadne dekoracje są jeszcze widoczne. To, czego naprawdę potrzebowałoby, to tylko 100 TextBlocks, ponieważ jest to widoczne na ekranie. Dopiero po tym, jak element otrzyma wskaźnik myszy nad zdarzeniem lub fokus, gdy potrzebne są inne elementy. Równocześnie edytowany jest tylko jeden element, więc tylko jeden element wejściowy (w tym przypadku textbox) wystarczyłby dla całej aplikacji.

Jaki byłby najlepszy sposób uzyskania tych samych dekoracji bez tworzenia wszystkich elementów dekoracyjnych (lub rzeczywistego elementu wejściowego) dla każdego elementu w widoku?


Przykładem zdobione TextBox wyjaśnienia use-case:

Pole tekstowe wygląda tylko do odczytu TextBlock gdy nie ma ostrości lub kursor nie znajduje się obecnie na wierzchu (stan 1). Również trzy kropki ("...") są wyświetlane, ponieważ element nie ma żadnej aktualnej wartości.

Gdy kursor jest przesuwany w górę elementu, pojawia się linia przerywana zielony prostokąt TextBlock co oznacza, że ​​element może być zmodyfikowany (stan 2). Kolor będzie czerwony, jeśli TextBox stanie się tylko do odczytu.

Po otrzymaniu elementu ostrości zmienia się rzeczywistą pole tekstowe, które mogą być używane, aby zmodyfikować wartość rzeczywistą (stan 3).

Wartość ta jest przechowywana w bazie danych po tekstowe traci skupienie się i pokazać, że wartość jest obecnie zapisany wskaźnik zajętości pojawia się po lewej stronie elementu (stan 4).

Wreszcie, wartość została zapisana i element powraca do stanu bezczynności, pokazując nową wartość (stan 5). (W rzeczywistości elementy mają jeszcze więcej stanów związanych z walidacją i innymi specyficznymi wymaganiami, ale na pewno masz rację, że elementy są bardzo udekorowane.)

enter image description here

Odpowiedz

4

Zamiast rysunek wszystkie elementy interfejsu z góry, rysować te potrzebne tylko

WPF pozwala modyfikować Template obiektu przy użyciu DataTrigger, dzięki czemu można dostosować szablon dla dekorator oparciu o wyzwalacze

przykładem styl dla dekorator może wyglądać tak:

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

Ponadto WPF nie powinien ładować niewidocznych elementów. Możesz spróbować ustawić swoje dekoratory Visibility="Collapsed" jako test, aby sprawdzić, czy to naprawi czas wczytywania.

Jeśli tak i nie chcesz, aby przejść trasę Template, można zapewnić, że Visibility wszystkich swoich obiektów jest ustawiony na Collapsed na początek, a oni tylko gotowi do Visible kiedy powinny być wyświetlane.

Jeśli to nie naprawi twojego czasu ładowania, twój problem prawdopodobnie jest gdzieś indziej. Na przykład wygląda na to, że niektóre elementy Twojego dekoratora mają rozmiar zgodny z zawartą w nim kontrolą treści, więc możliwe jest, że to, co faktycznie spowalnia, nie wyświetla obiektów, ale określa rozmiar obiektów.

+0

Dziękujemy! Szablony kontroli to zdecydowanie najlepszy sposób na dekorowanie elementów. Jednak nie rozwiązuje to problemu z faktycznym elementem wejściowym. TextBox jest naszym najlżejszym elementem i mamy dużo cięższe niestandardowe elementy wejściowe (np. Selektor dat), na które nie możemy sobie pozwolić. Ustawiliśmy widoczność na zwiniętą, ale nadal tworzone jest drzewo wizualne i wszystkie powiązane zasoby są obciążone, co powoduje poważne problemy z wydajnością. – user544511

+0

@ user544511 Kiedy mówisz "wszystkie powiązane zasoby są załadowane", masz na myśli, że każdy dekorator jest załadowany? Ponieważ jeśli używasz pojedynczego formantu interfejsu użytkownika do dekoratora i zamieniasz szablon, nie powinieneś tego robić, ponieważ w drzewie wizualnym istnieje tylko jeden element na raz. – Rachel

+0

Przepraszam, że byłem na wakacjach i nie mogłem odpowiedzieć wcześniej. Miałem na myśli, że faktyczny element wejściowy (który jest dzieckiem dekoratora, np. Selektor dat lub TextBox) jest tworzony, wszystkie jego zasoby (w tym elementy potomne) są ładowane i dodawane do drzewa wizualnego (nawet jeśli jest zwinięte). Powoduje to ogromną skuteczność, ponieważ selektor dat jest elementem o wiele cięższym niż np. a TextBox. – user544511

Powiązane problemy