Bez kategorii

Windows Forms i jak zaktualizować wartość kontrolki pomiędzy wątkami

Ano przyszedł czas, że musiałem popełnić małą aplikacyjkę do backupowania danych z serwera. Idea prosta jak budowa cepa. Aplikacja wykrywa włożenie napędu USB do komputera, a jeżeli w głównym katalogu znajduje się folder o określonej nazwie to zasysa z serwera wszystko. Kilka obwarowań zapisanych jest w pliku konfiguracyjnym tego katalogu. Wsio.
Samo wykrywanie napędu USB oparte jest na eventach opisanym pod tym linkiem. Z tym, że u mnie zadziałała kombinacja kilku odpowiedzi:

private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e)
{
   string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
   MessageBox.Show(driveName + " inserted");
}

private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e)
{
   string driveName = e.NewEvent.Properties["DriveName"].Value.ToString();
   MessageBox.Show(driveName + " removed");
}

void bgwDriveDetector_DoWork(object sender, DoWorkEventArgs e)
{
   var insertQuery = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2");
   var insertWatcher = new ManagementEventWatcher(insertQuery);
   insertWatcher.EventArrived += DeviceInsertedEvent;
   insertWatcher.Start();
 
   var removeQuery = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 3");
   var removeWatcher = new ManagementEventWatcher(removeQuery);
   removeWatcher.EventArrived += DeviceRemovedEvent;
   removeWatcher.Start();
}

Chciałem jednak informować użytkownik o statusie wykonywanych operacji:

  • napęd wykryty
  • napęd usunięty
  • ściąganie danych z serwera
  • informacja o nazwie ściąganego pliku
  • postęp
  • zakończenie pracy

Do wyświetlania tych informacji użyłem zwykłej kontrolki Label, ale podczas zwykłej aktualizacji property Text dostawałem błąd: The function evaluation requires all threads to run.
Pierwszy efekt poszukiwań odpowiedzi na pytanie dlaczego tak się dzieje zaprowadził mnie do strony, na której stwierdzono, że to jest normalne zachowanie debuggera wynikające z utworzenia kontrolki w innym wątku niż ten, z którego próbuje się dokonać modyfikacji. Ja to rozumiem, ale propozycja rozwiązania problemu mieszcząca się za tym adresem nie spełniała moich oczekiwań.
Ale kolejny wynik już był rozwiązaniem mojego problemu:

public void SetLabel(String text)
{
   if(this.lblStatus.InvokeRequired)
   {
      StringArgReturningVoidDelegate d = new SetLabel;
      this.Invoke(d, new object[] { text });
   }
   lblStatus.Text = text;
}

Można również zaktualizować tą propertę używając BackgroundWorkera, ale to już można wyczytać z tego linka.

Leave a Reply

Your email address will not be published. Required fields are marked *