ok, irgendwie bekomme ich das nicht hin
Ich habe insgesamt folgendes Design: Aus meiner MainApp starte ich mehrere Fenster, denen ich ein "globales" Objekt Manager mitgebe, auf dessen events sie reagieren können. Eines der Fenster startet dann eben einen Timer. Aussehen sieht das stark reduziert dann wie folgt:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| public partial class MainApp : Form { private Manager _manager = null; private WindowA _windowA = null;
public MainApp() { manager = new Manager(); OpenWindowA(); } public void OpenWindowA() { if(_windowA==null) { _windowA = new WindowA(_manager); _windowA.Disposed += _windowA_disposed; } } private void _windowA_disposed(object sender, EventArgs e) { _windowA = null; } } |
Mein WindowA besteht aus einer Form, einem Form-Interface und einem Presenter:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| public partial class WindowA: Form, IWindowA { private WindowAPresenter _presenter = null; private System.Timers.Timer _timer;
public WindowA(Manager manager) { _presenter = new WindowAPresenter(this, manager); this.Disposed += WindowA_Disposed; _timer = new System.Timers.Timer(1000); _timer.Elapsed += timer_Elapsed; } void WindowA_Disposed(object sender, EventArgs e) { _presenter.Stop(); _timer.Elapsed -= timer_Elapsed; _timer.Stop(); _timer.Dispose(); } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (textBox.InvokeRequired) textBox.Invoke(new Action(() => { textBox.Text = "Test"; })); else textBox.Text = "Test"; } internal void SetText(string value) { if (textBoxPresenter.InvokeRequired) textBoxPresenter.Invoke(new Action(() => { textBoxPresenter.Text = value; })); else textBoxPresenter.Text = value; } } |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
| public partial class WindowAPresenter { private Manager _manager = null; private IWindowA _view = null; private System.Timers.Timer _timer;
public WindowAPresenter(IWindowA view, Manager manager) { _manager = manager; _view = view; _timer = new System.Timers.Timer(1000); _timer.Elapsed += timer_Elapsed; _manager.Started += _manager_Started; _manager.Stoped += _manager_Stoped; } ~WindowAPresenter() { _timer.Dispose(); } internal void Stop() { _manager.Started -= _manager_Started; _manager.Stoped -= _manager_Stoped; _timer.Elapsed -= timer_Elapsed; _timer.Stop(); } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { _view.SetText("test"); } private void _manager_Started(object sender, EventArgs e) { _Timer.Start(); } private void _manager_Stoped(object sender, EventArgs e) { _Timer.Stop(); } } |
Jetzt bekomme ich -manchmal- folgende Fehlermeldungen. Zum einen in der WindowA.SetText - Methode die aussage, dass auf das verworfene TextFeld nicht mehr zugegriffen werden kann (Hier scheint also noch der Timer weiter zulaufe, obwohl ich alles beim FormClosing/Disposed stoppe. Und zum anderen erhalte ich im WindowsA-Designer-Code in der überschirebenen Dispose-Methode an der stelle base.Dispose folgende Fehlermeldung:
Quelltext
1:
| Es wurde versucht, einen RCW freizugeben, der derzeit benutzt wird. Der RCW wird im aktiven Thread oder einem anderen Thread verwendet. Der Versuch, einen RCW freizugeben, der gerade verwendet wird, kann Datenbeschädigung oder -verlust zur Folge haben. |
Ich hatte auch versucht in die TimerElapsed-Funktionen jeweil am Anfang eine bool-Variable timerIsActive auf true zu setzen und am Ende auf false und in der WindowA.dispose/formClosing bzw WindowAPresenter.Stop jeweil eine while(timerIsActive); vor dem timer.Dispose einzuubauen. Dabei habe ich dann aber endlosschleifen generiert...
Ich habe jetzt echt keine Idee mehr, wie ich die Timer nun korrekt nutzen muss? Kann mir jemand erklären wo mein Fehler liegt?
Vielen vielen Dank
Määx
Edit: gut das mit Endlosschleife ist ja logisch, da ich im TimerElapsed ja den GUI-Thread joinen muss. War ne dumme Idee
