W tym poście chciałbym opisać sposób aktualizacji kontrolek w aplikacji napisanej w języku C#.
Sposób będzie przedstawiony na przykładzie aplikacji wykonującej komunikacje z płytą STM32 po SSL. Przesyłane są rozkazy pomiędzy płytą a aplikacją z danymi do odczytania z układu, lub do wprowadzenia parametrów do płytki.
Na samym początku tworzymy klasę do której będę przekazywał dane:
- public class Strefa
- {
- public byte HourOn { get; set; }
- public byte MinuteOn { get; set; }
- public byte SecondOn { get; set; }
- public byte HourOff { get; set; }
- public byte MinuteOff { get; set; }
- public byte SecondOff { get; set; }
- public bool ActiveState { get; set; }
- public byte WeekDays { get; set; }
- public string Password { get; set; }
- public bool BlockEntrance { get; set; }
- }
- public static class GetStrefa_Data
- {
- public static bool strefa_ReceiveResponse { get; set; }
- static Int16 msgError = 0;
- static Strefa[] s_Data = new Strefa[8];
- public static bool MsgError { get; }
- public static bool PutDataIntoBuffer(string recData)
- {
- /*
- * Uzupełnienie danych w klasie, z otrzymanej ramki danych
- */
- /* Ustawienie flagi, */
- strefa_ReceiveResponse = true;
- return true;
- }
- public static Strefa GetData(byte s_Number)
- {
- if (s_Number == 0 || s_Number > 8)
- {
- return null;
- }
- return s_Data[s_Number - 1];
- }
- }
Teraz w głównym oknie musimy stworzyć asynchroniczne zadanie oczekujące ustawienie flagi. Można je wywołać z okna form load.
- private async void FormStrefa_Load(object sender, EventArgs e)
- {
- await UpdateControlBasedOnVariableAsync();
- }
Niestety w formie jakiej mam to zadanie przygotowane, zadziało ono w takim przypadku tylko raz. Kolejne próby odczytu danych będą wymagały ponownego otwarcia okna. Wobec tego najrozsądniej jest wywołać to zadanie z metody Button Click, która wysyła do urządzenia informację o konieczności odczytania danych.
- CancellationTokenSource cts = null;
- public FormStrefa()
- {
- InitializeComponent();
- cts = new CancellationTokenSource();
- }
- private void readDataNumberBtn_Click(object sender, EventArgs e)
- {
- Program form = new Program();
- if (cts != null)
- {
- cts.Cancel();
- cts = null;
- UpdateControlBasedOnVariableAsync();
- }
- SendReadDataToDevice();
- }
Ewentualnie można zmodyfikować funkcję asynchroniczną, tak aby po odczycie i wprowadzeniu danych do kontrolek zaczynał on działać ponownie np. czyścimy flagę odbioru danych i wracamy do oczekiwania na jej ponowne ustawienie.
Teraz samo zadanie asynchroniczne:
- private async Task UpdateControlBasedOnVariableAsync()
- {
- if (cts == null)
- {
- await Task.Run(() =>
- {
- while (!GetStrefa_Data.strefa_ReceiveResponse)
- {
- if (cts == null)
- {
- Thread.Sleep(500);
- }
- else
- {
- break;
- }
- }
- });
- if (GetStrefa_Data.strefa_ReceiveResponse)
- {
- for(byte i = 0; i<8; i++)
- {
- Strefa strefa = GetStrefa_Data.GetData((byte)(i + 1));
- if (GetStrefa_Data.MsgError == 0)
- {
- strefa1Active_CheckBox.Invoke((MethodInvoker)delegate
- {
- strefa1Active_CheckBox.Checked = false;
- MessageBox.Show("Blad podczas odczytu danych", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
- });
/* Uzupełnienie reszty danych */
- }
- else
- {
- strefa1Active_CheckBox.Invoke((MethodInvoker)delegate
- {
- strefa1Active_CheckBox.Checked = strefa.ActiveState;
- });
- }
- GetStrefa_Data.strefa_ReceiveResponse = false;
- cts = new CancellationTokenSource();
- }
- }
- }
- }
W zadaniu oczekujemy na ustawienie flagi, jak jest ustawiona to sprawdzam czy nie ma błędów i odpowiednio do otrzymanej odpowiedzi wprowadzam dane do komórek.
Należy także pamiętać o zakończeniu zadania przy zamykaniu okna. Do tego celu wykorzystałem CancellationToken.
- private void FormStrefa_FormClosing(object sender, FormClosingEventArgs e)
- {
- cts = new CancellationTokenSource();
- }
Jest to o tyle istotne, że w przypadku gdy zadanie oczekuje na odebranie i ustawienia danych, a one nie zostaną odebrane to nie nastąpi jego zakończenie. Można do funkcji oczekujące na odebranie danych dołożyć licznik. Tak aby po zadanym maksymalnym czasie samo się zakończyło.