wpf odświeżanie danych z automatyki a zamrażanie GUI

0

Witam
Problem jest taki: mam ~ 30 sterowników automatyki (30 usercontrols i odczyt danych co 30ms w osobnym tasku dla każdej kontrolki). Niestety odświeżanie odbywa się na kontrolkach (devexpress) zegarowych plus wyświetlacze cyfrowe itp. Jest to czasochłonne więc występuje blokowanie interfejsu. Nie wiem jak do tematu podejść odpowiednio, gdyż dopiero co uczę się WPF. Pierwszą rzeczą było użycie Binding z DependencyProperty i wykorzystanie .Delay w ms. Jest w miarę ok. Drugie moje podejście to skorzystanie z Dispatcher.BeginInvoke i odpowiednie ustawienie DispatcherPriority. Też to działa w miarę, ale wolę Was się spytać jakie byłoby optymalne rozwiązanie mojego problemu. Za wszelkie :Re z góry dzięki.

1

Mhh jesteś pewien ze lagi nie są spowodowane na dostępie do sterowników. One są przeznaczone do pracy ze sprzetem który ma setki ms opóźnienia i z natury rzeczy są dość woln. Samo wyświetlenie danych nie powinno być problemem.

0
topik92 napisał(a):

Mhh jesteś pewien ze lagi nie są spowodowane na dostępie do sterowników.

Witam
Nie, używam modbus tcp/ip (~20ms opóźnień to standard ja i tak dla bezpieczeństwa odbieram co ~100ms ) i jak wspomniałem problemem nie jest ściąganie danych (każde IP sterownika to połączenie w osobnym wątku dla każdej kontrolki). Problemem jest (?chyba), że te 30 kontrolek w różnym czasie próbują odświeżyć interfejs i się to dosyć opóźnia. W pierwszej wiadomości podałem to co testowałem i to daje radę, ale nie wiem czy lepszym sposobem nie będzie co 100 ms w jednej pętli odświeżyć zawartość wszystkich kontrolek.

0

Najpierw piszesz o task'ach potem o wątkach i raz je odświeżasz co 30 ms. a raz co 100ms i gdyby odczyt działał dobrze to raczej wątek UI by się nie wieszał. Szczerze mówiąc nie wiem co robisz ale na pewno będzie dobrym pomysłem nie zakładać w wątku UI( tym od kontrolek) 30 wątków co 30 ms. i rozdzielić odświeżanie kontrolek tak bardzo jak się da od wczytywania danych z internetu, np. jakimś view model. Zwłaszcza że devexpres lubi sam się odświeżać swoimi wewnętrzni magicznymi timerami,

0

A jakie to sterowniki? W jaki sposób odczytujesz z nich dane (pokaż kawałek kodu). Może masz jakiś event i odczytuje niepotrzebnie wiele razy, albo próbuje coś w drugą stronę i zamula go odpowiedź ze sterownika. Może sterownik umożliwia subskrybowanie danych, nie odczytywanie z opóźnieniem.

0

Witam,

Pokaż może fragment kodu który służy odebraniu danych i ich wyświetlaniu. Może zastosowanie MVVM rozwiąże twój problem?

Pozdrawiam,

mr-owl

0

Witam
Już znalazłem przyczynę.
po Dispatcher.begininvoke od razu odpalałem kolejny odczyt ze sterownika w tasku więc gui nie miało chyba zbytnio czasu .
Dodałem DispatcherOperation i dopiero gdy otrzymam status=DispatcherOperationStatus.Completed odpalam kolejny odczyt ze sterownika.
Mój oczywisty błąd.
Tyle, że jeszcze takie małe pytanie: czym się różni wywołanie MojaKontrolka.Dispatcher od Application.Current.Dispatcher ?

Skoro "generowałem" (nie w xaml) kontrolki w pętli podczas inicjacji okna, to powinienem do odświeżania użyć głównego wątku aplikacji? Sory, ale przechodzę dopiero z forms.

0

Witam,

A możesz mi zdradzić dlaczego z poziomu GUI decydujesz o odczytywaniu danych? Nie możesz tego robić np timerem co zadany czas i dopiero pobrane i ewentualnie zmienione dane wyświetlać? Masz klasę która odpowiada za odczyt danych z portu/sieci co zadany czas, po dokonaniu odczytu generuje zdarzenie. W klasie ViewModel dodajesz używanie tej klasy i obsługę twoje zdarzenie aktualizując property które będzie reprezentowało twoje odczytane dane. Twój ViewModel używany jest jako źródło danych dla widoku i tyle. MVVM bardzo fajnie pomaga w pracy przy WPF.

Pozdrawiam,

mr-owl

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>    
    <Grid>
        <Label Padding="0" Content="{Binding Time}" />
    </Grid>
</Window>
namespace WpfApp1
{
    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows.Threading;

    using WpfApp1.Annotations;

    public sealed class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.Send);

        public ViewModel()
        {
            this.timer.Interval = TimeSpan.FromMilliseconds(250);
            this.timer.Tick += (sender, e) => { this.Time = string.Format("{0:HH:mm:ss}", DateTime.Now); };
            this.timer.Start();
        }

        private string time = string.Empty;

        public string Time
        {
            get
            {
                return this.time;
            }

            set
            {
                if (!value.Equals(this.time))
                {
                    this.time = value;
                    this.OnPropertyChanged("Time");
                }
            }
        }
    }
}

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