Hello. Recently started learning C #. Before that, he worked in Delphi and in Qt (C ++). During a workout, I ran into a big problem that may seem very silly.
This is a very long story, I will try to describe everything briefly and accurately.
We consider three objects: 1) TextBox ; 2) MyClass with a timer inside; 3) the shape of the main window that encapsulates them.
MyClass starts a timer that generates an UpdateDuration event at intervals of about two times per second.
// Обработчик события таймера private void TickerCheck(Object source, System.Timers.ElapsedEventArgs e) { if (Animation) { Invalidate(); } if (Field.GameIsRunning) { if (Updater == TimerUpdateTicks) { Updater = 0; GameDuration = Field.RunningGameDuration; OnUpdateDuration(); } ++Updater; } } // внутренний обработчик события UpdateDuration protected void OnUpdateDuration() { UpdateDurationEventArgs ud = new UpdateDurationEventArgs(); EventHandler<UpdateDurationEventArgs> h = UpdateDuration; if (h != null) { ud.Duration = GameDuration; h(this, ud); } System.Diagnostics.Debug.WriteLine("Посылка отправлена: " + ud.Duration.ToString()); } The signers of the UpdateDuration event receive an argument containing inside the TimeSpan
public class UpdateDurationEventArgs : EventArgs { private TimeSpan duration; public UpdateDurationEventArgs() { duration = TimeSpan.Zero; } public TimeSpan Duration { get { return duration; } set { duration = value; } } } I was going to use this TimeSpan to update the text in the TextBox. This textbox looks like this:
I think you already understand what I want to do :) It should update the current game time. For the user, he plays the role of a stopwatch.
The signer of the UpdateDuration event is the form of the main window. It accepts an event and should (as planned) update the text inside the TextBox.
void UpdateTimer(object sender, UpdateDurationEventArgs ud) { System.Diagnostics.Debug.WriteLine("Посылка получена: " + ud.Duration.ToString()); uint t_Seconds = (uint)ud.Duration.TotalSeconds, t_Minutes = t_Seconds/60, t_Hours = t_Minutes/60; t_Seconds = t_Seconds%60; t_Minutes = t_Minutes%60; t_Hours = t_Hours %100; string newText = t_Hours.ToString("D2") + ':' + t_Minutes.ToString("D2") + ':' + t_Seconds.ToString("D2"); textBox_timer.Text = newText; // вот здесь она должна обновлять его System.Diagnostics.Debug.WriteLine("Посылка распакована: " + ud.Duration.ToString()); } But! It was not there. Does anyone already see the error? Not? I do not see: T
When I started the timer, TextBox always remained in zeros. Then I created a button and tried to start the event handler manually:
void Button_Rec_Click(object sender, System.EventArgs e) { UpdateDurationEventArgs ud = new UpdateDurationEventArgs(); ud.Duration = System.TimeSpan.FromSeconds(new System.Random().Next(8000)); UpdateTimer(this, ud); } And now, on the button, everything works fine: in TextBox, randomly exhibited different times. Before that, I have not tried to catch exceptions in C #. Rummaged in MSDN and did this:
void UpdateTimer(object sender, UpdateDurationEventArgs ud) { System.Diagnostics.Debug.WriteLine("Посылка получена: " + ud.Duration.ToString()); uint t_Seconds = (uint)ud.Duration.TotalSeconds, t_Minutes = t_Seconds/60, t_Hours = t_Minutes/60; t_Seconds = t_Seconds%60; t_Minutes = t_Minutes%60; t_Hours = t_Hours %100; string newText = t_Hours.ToString("D2") + ':' + t_Minutes.ToString("D2") + ':' + t_Seconds.ToString("D2"); try { // добавил блок try catch textBox_timer.ResetText(); // и подставил строчки для дебага System.Diagnostics.Debug.WriteLine(" resetText"); textBox_timer.Text = newText; System.Diagnostics.Debug.WriteLine(" newText"); } catch (System.Exception) { System.Diagnostics.Debug.WriteLine("Звездец, граждане!"); } System.Diagnostics.Debug.WriteLine("Посылка распакована: " + ud.Duration.ToString()); } What did I see?

Star Frustration in its purest form. The parcel is sent (an event is generated, see the OnUpdateDuration code), it is accepted by the signer, but an exception is thrown, even when the text is reset . At the same time, by the same button, manually, everything works fine:

Do you already see the error? What have I done wrong? : T
I called this poor button to death (more than 10 clicks per second), but the "star" did not come out to the console - the processing goes well.
Here you have the right to assume that MyClass sends some kind of invalid TimeSpan. I dare to assure that this is not at all the case: for the same timer, the handler outputs time to the debug console without any problems:

An interesting point: I made it so that when the timer was manually stopped, MyClass sent the UpdateDuration event one more time, after the timer was stopped, to send the timers to zero TimeSpan.Zero . So I intended to reset the time on Textbox. So, this final event is also accepted without any problems.

Funny, but if you replace the textbox with a label, the situation does not change. And only if you use a timer directly belonging to the form , everything works well. But does a timer working in another class violate some principles of OOP? After all, MyClass objects, form and TextBox are all in one main thread! I'm at a loss.
The program does what the programmer wrote, not what he wanted. Where is my mistake? I ditched yesterday a few hours in search of a solution, before it cuts in my eyes. Even put the handler in the mutex, although it seems to be useless here. Help me please.
WindowsXP, NetFramework 4, SharpDevelop.
You have earned an achievement! You have read my question completely! Thank :)