Podobny problem wystąpił w przypadku jednoczesnego korzystania z wielu produktów WPF DataGrid
. To w końcu sprowadza się do dwóch głównych zagadnień:
- słowniki zasobów
- Wiązania
zasób słowników
Mogą to być poważne zatory jeśli używasz podstawowy WPF dysponuje, nie będąc ostrożnym.
W moim przypadku, dla jednego logicznego przewijania w ItemsControl
który został zawierającego moje DataGrids
, ja dostawałem coś jak 10 milionów zadzwonić do GetValue
i GetValueWithoutLock
na ResourceDictionary. Ponad 1 sekunda do przetworzenia.
Ta wielka liczba ResourceDictionary
dostępów został spowodowany przez różnych źródeł:
- pobieranie zasobów Dynamiczny: Jeśli masz
ControlTemplates
, a bardziej ogólnie zasobów umieszczonych w niektórych słownikach zasobów, a dostęp do nich poprzez {DynamicResource ...}
, należy je usunąć . Mieć gdzieś statyczne miejsce i mieć do nich bezpośredni dostęp.
- Pobieranie stylu: Jeśli nie masz stylu w używanym obrazie lub masz styl, ale nie ustawiono właściwości FrameworkElement.OverridesDefaultStyle, program WPF spróbuje znaleźć styl pasujący do formantu we wszystkich zasobach, co jest wynikiem w wielu dostępach do słowników zasobów. Aby tego uniknąć, należy zastąpić wszystkie szablony kontrolne kontrolek i ustawić
Style={x:Null}
dla każdej kontrolki (jeśli potrzebujesz stylu dla formantu, ustawić go w linii kontrolnej i dodać). DataTemplates: szablon danych niejawnych jest bardzo przydatny, ale daleko im do tego. Szukając aplikacji do zastosowania, WPF ponownie przejrzy twoje słowniki zasobów, aby znaleźć DataTemplate
pasujące do typów ViewModels. Rozwiązaniem jest użycie selektora DataTemplate
dla każdej kontrolki powiązanej z ViewModel i wdrożenie zoptymalizowanego sposobu pobrania poprawnego DataTemplate
. (Osobiście posiadam pola statyczne dla mojej dataTemplate, którą pobieram tylko raz z resourceDictionary i zoptymalizowanego DataTemplateSelector
, który zwraca je w razie potrzeby.)
Wiązania
Wiązania są bardzo przydatne, ale bardzo drogie, pamięć i wydajność mądry mądry. W bardzo rozsądnym środowisku - z punktu widzenia wydajności - nie można po prostu używać ich bez zachowania ostrożności. Na przykład, bindowanie może utworzyć do 3 WeakReferences dla każdego bindowanego obiektu, może używać odbicia, itp. W końcu skończyłem z usunięciem prawie całej mojej funkcji obsługi zdarzeń wiążącej i podłączonej w zdarzeniu PropertyChanged DataContext. Kiedy DataContext
zmienia się w moich kontrolkach (masz zdarzenie DataContextChanged
) testuję, czy mój DataContext
obsługuje INotifyPropertyChanged
, a jeśli tak jest, dołączam procedurę obsługi zdarzeń do zdarzenia PropertyChanged
i aktualizuję właściwości w razie potrzeby. (Miałem tylko jeden sposób wiązania, dlatego wybrałem ten sposób robienia rzeczy, ale są inne rozwiązania).
Może wydawać się frustrujące, nie używając wiązań podczas korzystania z MVVM i WPF, ale w rzeczywistości nie było sposobu, aby zoptymalizować wiązania w moim przypadku.
Ostatnia rzecz: jeśli masz obiekty Freezable
(np. Pędzle), nie wahaj się, jeśli możesz, pod Freeze
.
Oto kilka porad, które mogą pomóc w zoptymalizowaniu kodu. Będziesz potrzebował profilera (zawsze korzystam z porady dotTrace, ponieważ jest to najlepszy profiler, jakiego kiedykolwiek używałem) do monitorowania tego, co się naprawdę dzieje i dostosowywania się do wyników.
Powodzenia!
Dziękujemy za szczegółową odpowiedź. Zawiera już pewne punkty, które mogę poprawić w mojej aplikacji (freezables, domyślne nadpisanie stylu). Sprawdzę to i zgłoś później. –
Jasne, daj mi znać, jak to działa! To było dobre ćwiczenie dla mnie, ponieważ muszę napisać post na moim blogu :) – Sisyphe
Mamy wiele słowników zasobów dla wszystkiego i aplikacja jest nadal bardzo szybka.Sposób, w jaki do tego przystąpiliśmy, polegał na stworzeniu jednego słownika zasobów dla jednego zasobu (takiego jak styl, wektor, pędzel itd.), A następnie z każdego widoku odwołujemy się tylko do tych słowników zasobów, które są potrzebne. Problemem jest sama siatka, ponieważ nie wirtualizuje. – adminSoftDK