Vorweg: Was Du mit Frage 1 meinst, wird mir nicht ganz klar.
Frage 3 und 2:
Was Du hier anschneidest, ist vermutlich das ekligste Thema, was Du dir als Einstieg aussuchen konntest: Multithreading
Grob umschrieben:
Dein Programm hat einen Thread, dieser Thread arbeitet die Befehle ab. Willst Du parallel dazu etwas anderes machen lassen, brauchst Du einen zweiten Thread. Threads können auch untereinander kommunizieren, aber das ist nicht ganz so einfach, da Du nie weißt, was der andere Thread gerade tut und ob er mit deinen Aktionen klar kommt, oder nicht. Aus dem Grund ist es elementar wichtig, dass ein Thread nie ungeprüft, auf etwas zugreift, was der andere Thread bearbeiten kann und wahlweise dem anderen Thread signalisiert, dass er kurz warten muss, wenn er mit den selben Daten arbeiten will.
Die Benutzeroberfläche hat einen eigenen Thread (UI-Thread), der alle UI-Aktionen abarbeitet, wie z.B. die Button-Clicks oder Aktualisierungen, allerdings mit einem Nachteil: Die UI mag es gar nicht, wenn ein anderer Thread an den Controls herum spielt.
Wenn Du nun einen Button Click und dadurch eine unendliche While-Schleife startet, dann arbeitet dein Thread unendlich lange an dieser While-Schleife und hat nie wieder Zeit für die Benutzeroberfläche.
Das kann man umgehen, indem man einen zweiten Thread startet und die Schleife darin laufen lässt, allerdings kann man darin nichts tun, da immer die UI betroffen wäre. Du musst also alle für die UI relevanten Aktionen wieder in den UI-Thread synchronisieren.
Doch auch dafür gibt es eine Lösung: Der UI-Thread ist im Prinzip auch eine Schleife, der ständig guckt, ob es etwas zu tun gibt, man nennt das ganze Konstrukt den Dispatcher. Wenn Du etwas für den UI-Thread hast, kannst Du diese Aufgabe nehmen und dem Dispatcher hin stellen, der wird das dann zum nächstmöglichen Zeitpunkt im UI-Thread abarbeiten. Darauf kannst Du dann warten, oder auch nicht.
Aber in jedem Fall gilt: Länger andauernde Aufgaben sollten nicht im UI-Thread laufen, da die UI solange blockiert wird.
Das klingt alles super kompliziert, aber dafür hat sich Microsoft was cooles ausgedacht: Der Timer
Der macht das alles ganz automatisch, der wartet in einem anderen Thread die angegebene Zeit und im Anschluss gibt er die von dir bestimmte Aufgabe an den Dispatcher, sodass Du dich nicht um den UI-Thread sorgen musst.
Aus dem Grund solltest Du auch erst beim Timer bleiben.
Aber ganz ehrlich: Eine Millisekunde?
Du wärst der erste Mensch, der den Unterschied wahrnehmen kann, besonders da die Zeit für normale Menschen in Sekunden gemessen wird. Ich würde das auch 500ms oder gleich 1s setzen, das spart Leistung.
Und ob es eine bessere Herangehensweise gibt: Die Frage kann man ausnahmslos immer mit Ja beantworten.
Es gibt immer und für alles einen besseren Weg, die Frage ist, ob es sich lohnt, nach einem besseren Weg zu suchen.
Wenn Du dazu aber noch die Uhrzeit aktualisiert haben möchtest, kommst Du unter WinForms nicht um einen Timer herum - außer Du baust etwas, was ein ähnliches Ergebnis liefert.
Komplexere Ideen hab ich viele
Eine Idee, grob umschrieben:
In dem anderen Thread:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| while (IsLoopRunning) { } |
Im UI-Thread, wenn ein Eintrag hinzugefügt wird:
C#-Quelltext
Das Ergebnis wäre, dass der Thread solange nichts tut, bis es einen Eintrag zum Entfernen gibt, oder ein neuer Eintrag hinzugekommen ist.
Er berechnet dabei eigenständig die nächste Wartezeit und für den Marker gibt es verschiedene Klassen, die solche Signale zuverlässig zwischen zwei Thread transportieren können.