LiveChart i wiele wątków w aplikacji.

0

Cześć wszystkim, chciałem zrobić program, który odbiera dane o temperaturze (np. z arduino) i rysuje z nich na bieżąco wykres. Program robi wykres, ale zawiesza się przy tym i nie można nic więcej robić. Chciałem wrzucić to rysowanie wykresu do osobnego wątku ale niestety mam z tym problem :( Jestem początkujący jeśli chodzi o programowanie, dlatego jeśli ktoś ma pomysł dlaczego to nie działa to będę wdzięczny za pomoc :) Błąd jest w linii Thread watek = new Thread(wykres_LadowanieDanych); - dlaczego nie można dodać tej metody do Thread ?

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Thread watek = new Thread(wykres_LadowanieDanych);
            watek.Start();
        }

        public void wykres_LadowanieDanych(object sender, RoutedEventArgs e)
        {
            LineSeries temperatura = new LineSeries() { DataLabels = false, Values = new ChartValues<int>() };
            Random r = new Random();
            Axis x = new Axis();
            Axis y = new Axis();
            temperatura.Stroke = Brushes.Red;
            temperatura.Fill = Brushes.Transparent;
            x.Title = "Czas pomiaru";
            y.Title = "Temperatura powietrza";
            y.MaxValue = 50;
            y.MinValue = -10;
            x.MaxValue = 50;
            wykres_temperatura.AxisX.Add(x);
            wykres_temperatura.AxisY.Add(y);
            wykres_temperatura.Series.Add(temperatura);

            List<string> etykiety = new List<string>();
            x.Labels = etykiety;

            while (IsVisible)
            {
                if (temperatura.Values.Count >= 50)
                {
                    temperatura.Values.Remove(temperatura.Values[0]);
                    etykiety.Remove(etykiety[0]);
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
                }
                if (temperatura.Values.Count < 50)
                {
                    temperatura.Values.Add(r.Next(1, 30));
                    etykiety.Add(DateTime.UtcNow.ToString("HH:mm:ss"));
                    Thread.Sleep(6000);
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
                }
            }
        }

0

Kontrolki interfejsu WPF nie mogą (prawie zawsze, acz są drobne wyjątki) być modyfikowane bezpośrednio z innych wątków niż wątek UI, aby to obejść możesz użyć Dispatcher.Invoke() lub od wersji wpf 4..5 BindingOperations.EnableCollectionSynchronization które umożliwia manipulowanie kolekcją zbindowaną do kontrolki z innych wątków.

0

Bo do konstruktora Thread musisz przekazać delegatę o określonej sygnaturze:

  1. Nie ma żadnych parametrów
public delegate void ThreadStart()
  1. Ma parametr typu object, i potem w metodzie Start go przekazujsz
public delegate void ParameterizedThreadStart(object obj)

A Ty w swoim kodzie używasz delegaty z dwoma parametrami stąd błąd, czyli zamiast tego:

public void wykres_LadowanieDanych(object sender, RoutedEventArgs e){...}

Robisz tak

public void wykres_LadowanieDanych(){...}

I błąd znika, ale znając życie pewnie pojawi się kolejny

0

Dzięki, po usunięciu zawartości nawiasu w metodzie jest rzeczywiście inny błąd :( Spróbuję przez Dispatcher :)

0

Nie wiem czy to dobrze rozumiesz. Jak masz zwykła apke to ona działa na jednym wątku, który można nazwać głównym. No i teraz jak masz jakas wymagająca operacje do wykonania to musisz utworzyć dodatkowy wątek zwany roboczym, bo jak wykonasz ją w głównym to program Ci się zawiesi. No więc masz ten wątek roboczy i chcesz w nim zmodyfikować kontrolke, ale nie możesz bezpośrednio z tego wątku tak jak Ci napisał neves. Jest coś takiego jak powinowadztwo do wątku. Stąd też jak chcesz wykonać operacje na kontrolce to musisz te czynność przekierowac do wątku głównego i do tego służy m.in Dispatcher.
Dodatkowo jak masz pętlę while w tworzonym wątku to musi w niej być taki warunek, który będziesz w stanie zmienić przy zamykaniu programu, bo inaczej go nie zamkniesz. Okienko zniknie ale proces nadal będzie uruchomiony. Mógłbyś to też rozwiązać w taki sposób, że ten wątek roboczy ustawisz jako działający w tle to wtedy nawet jak w pętli będzie true to przy zamykaniu programu wątek ten zostanie usunięty i wszystko ładnie się zamknie. Co do tego rozwiązania wątku działającego w tle to pewien nie jestem, bo tylko o tym czytałem, ale nigdy nie sprawdzalem czy tak działa. Później sprawdze i napisze, bo mnie to ciekawi.

Sprawdziłem i jeżeli zrobisz tak

watek.isBackground = true;

To nawet jeśli w wątku tym będziesz miał while(true) to proces zostanie zakończony, ale i tak lepiej samemu modyfikować ten warunek w pętli przed zamknięciem aplikacji, bo jak sam tego nie zrobisz to mogą posypać się wyjątki.

0

Dzięki, szukam jeszcze tutaj odpowiedzi ale nie wiem jak to użyć w mojej sytuacji :( https://lvcharts.net/App/examples/v1/wpf/Material%20Design

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