C# problem z wątkami


(Trance) #1

W aplikacji nad którą pracuję napotkałem mały problem mianowicie pobieram z bazy danych informacje na podstawie których generuję wykres

Niestety aplikacja rzuca wyjątek:

"Ten typ CollectionView nie obsługuje zmian własnej kolekcji SourceCollection z wątku innego niż Dispatcher.

co prawda potrafię zrobić to ze wspomnianego Dispatcher'a

Dispatcher.Invoke(

System.Windows.Threading.DispatcherPriority.Normal,

new Action(

delegate()

{

//funkcja

}

)

);

-powoduje on niestety jednak problem "zamrożenie działania okna głównego aplikacji do czasu wykonania całej funkcji (zakończenie wątku)" jak sprawić żeby okno aplikacji podczas pracy nad funkcją nie "zawieszało się" - chciałbym uaktualniać pasek postępu wykonania funkcji podczas jej działania bezpośrednio z wywoływanej funkcji, uzywam WPF


(Fiołek) #2

Ogranicz odwoływanie się do Dispatchera do minimum - pobierz za jego pomocą to co musisz pobrać, zrób co musisz zrobić i dopiero sam wynik przekaż dalej, bo z tego co zrozumiałem ty robisz wszystko za pomocą Dispatchera(czyli tak jak byś nie miał nowego wątku).


(Trance) #3

dobrze zrozumiałeś, problem jednak w tym że (wydaje mi się) nie da się tego zrobić poprzez inne watki ze względu na to , że chciałbym w Dispatch'erze uaktualniać wykres.. no i tutaj pojawia się wspomniany wyjątek: "Ten typ CollectionView nie obsługuje zmian własnej kolekcji SourceCollection z wątku innego niż Dispatcher.


(Fiołek) #4

Jeśli cały czas operujesz na obiekcie/kontrolce wykresu to nie bardzo wiem jak i czy w ogóle da się to przyspieszyć. Jeśli tylko masz możliwość zminimalizowania odwołań do CollectionView(np. przez uprzednie przygotowanie sobie kolekcji danych i zmianę tylko jednym przypisaniem) - zrób to.


(Trance) #5

problem nie polega na długim wykonywaniu a "zamrożeniu okna w czasie wykonywania"


([alex]) #6

Problem polega na tym że masz kilka wątków które skądś szybko pobierają dane i każą głównemu wątkowi uaktualnić dane. Ponieważ tych wątków jest kilka to główny wątek zajmuje się prawie wyłącznie uaktualnieniem danych. W związku z tym że przerysowywanie ekranu ma niski priorytet to okienko właściwie tego nie robi ponieważ zawsze jakiś wątek "chcę" uaktualnienia.

Zrób klasę pośrednią która przyjmuje dane od wątków, właściwie klasę buforową, jest dwie typowe strategie działania:

  1. po przyjęciu danych odczeka pół sekundy i dopiero wtedy wymusi aktualizacje w głównym wątku. Jeżeli w trakcie tych pół sekundy przyjdzie kolejna aktualizacja to resetujesz timera.

  2. co jakiś czas np co 5 sek wymusza uaktualnienie jeżeli w trakcie tych 5 sek była jakaś zmiana z wątku.

Właściwie można połączyć te dwie strategii, wtedy przy dużym napływie danych będzie odświeżać się co najmniej każde 5 sek, przy danych napływających rzadziej będzie odświeżać się online.