Watki i wydajność z C# wraz z prośbą o poradę.

0

Witajcie.

Jako, że piszę ten swój komunikatorek internetowy w C# WPF natrafiłem ostatnio na pewną kwestię, z którą nie wiem jak sobie poradzić. Program piszę według wzorca MVVM i chcę się dowiedzieć jak aktualizować widok w czasie rzeczywistym za pomocą funkcji, która będzie bez przerwy sprawdzała wejście programu.

Mam np. serwer i dorobione GUI do tego serwera. Odbiór i wysyłkę danych do klientów realizuje mi osobna klasa 'SerwerTCP, którą zrobiłem Singletonem i wstawiłem jako obiekt do mojego ViewModelu. Rzecz w tym, że to właśnie ta klasa zawiera dane przesłane przez klientów, które ViewModel musi odpowiednio zinterpretować żeby na bieżąco aktualizować widok. Tutaj właśnie jest problem jak to zrobić.

Najpierw napisałem funkcję ViewModelu, która za pomocą Timera sprawdzała mi bez przerwy zawartość danych przesłanych przez klientów i na tej podstawie aktualizowała widok. Wyglądało to tak:

private void interpretujDane() {
    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
    timer.Interval = 1;
    timer.Start();
    timer.Tick += (sender, args) => {
        for (int i = 0; i < this.serwer.listaKlientow.Count; i++) {
            if (this.serwer.listaKlientow[i].odebrane != null) {
                if (this.serwer.listaKlientow[i].odebrane.StartsWith("<Connecting/>")) {

                    //  Tutaj aktualizuj widok...

                }
            }
        }
    };
}               

Takie rozwiązanie działa, ale ma pewną wadę. Co jeżeli upłynie 1ms, a funkcja nie zdąży się wykonać w całości? Czy mimo to wykona się kolejny 'tick'?

Drugim rozwiązaniem, które wymyśliłem jest wątek działający w tle, z pętlą 'while(true)' w ciele metody:

//  Konstruktor ViewModelu
public OknoGlowneViewModel(){

    //  Jako, że tworzenie w ten sposób wątków jest niewydajne...
    Thread watekInterpretera = new Thread(this.interpretujDane) { IsBackground = true };
    watekInterpretera.Start();

    //  ... skorzystałem z możliwości uruchomienia wątku za pomocą puli:
    //  Zakomentowałem, bo "albo jedno albo drugie".
    //  ThreadPool.QueueUserWorkItem(interpretujDane);
}

//  object stan - do uruchomienia funkcji przez ThreadPool.
private void interpretujDane(/*object stan */) {
    while(true){
        for (int i = 0; i < this.serwer.listaKlientow.Count; i++) {
            if (this.serwer.listaKlientow[i].odebrane != null) {
                if (this.serwer.listaKlientow[i].odebrane.StartsWith("<Connecting/>")) {

                    //  Tutaj aktualizuj widok np. za pomocą:
                    App.Current.Dispatcher.Invoke((Action)(() => {
                        //  Akcja na elemencie zbindowanym z GUI.
                    }));

                }
            }
        }
    }
}   

To też działa, tylko zżera od razu 25% czasu procesora, w przeciwieństwie do rozwiązania z timerem, które wydaje mi się... nazwijmy to nieładne.
Jak to można inaczej ugryźć? Jak ViewModel może w czasie rzeczywistym na bieżąco aktualizować widok, w zależności od danych, które musi bez przerwy interpretować?
W QT taka akcja jest wykonywana przez pętlę główną programu, a tutaj nie wiem jak mogę to inaczej rozwiązać :-/

Pozdrawiam
Grzesiek

1

Poczytaj o wzorcu obserwator, albo zaznajom z pojęciem bindingu.

0

@dam1am - właśnie poznałem. Nie znałem wcześniej tego wzorca. Właściwie używałem tylko Singleton. Zaimplementowałem interfejsy IObserver i IObservable i świetnie działa. O to mi chodziło ☺ MVVM i wszelakich wzorów dopiero się uczę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0