multi thread issue

纵饮孤独 提交于 2019-12-12 20:27:30

问题


I'm using a timer to reset a lable I use as a warning box. Basically, if the user does something (more specifically, something goes wrong, ex : He uses a word not recognized by the program), this catches what went wrong early and returns to him what happened so he can change the input.

The reset blanks out the label after 5 seconds to prevent him from seeing something like "please do not use chinese characters" and maybe still thinking an old error is still up. This is what I got reading the invoke (since I hear begininvoke requires an endinvoke, I chose invoke).

private void lblWrn_TextChange(object sender, EventArgs e)
{
    Timee = new System.Timers.Timer(5000);
    Timee.Elapsed += new ElapsedEventHandler(timerClearWrn);
    Timee.Enabled = true;
}

string empty = "";
private void timerClearWrn(object sender, ElapsedEventArgs elapsed)
{
    lblWrn.Invoke(new Action<Label>(lblWrn), new object[] { lblWrn, "" });
}

I am not too sure where I am going wrong with this, and looking up examples, cannot figure out which part to change. Can someone explain to me the error or invoke a bit more?


回答1:


If it's a Windows Forms application, use System.Windows.Forms.Timer, then you don't need Invoke, as the timer callback is executed on the main thread.

Also, don't create a new timer on every text change.




回答2:


Actually, Control.BeginInvoke does not need an EndInvoke; it is Delegate.BeginInvoke that does.

First, I would also recommend using a Windows.Forms.Timer, since it looks like you are using winforms - that will automatically fire on the UI thread, making all the problems go away - just run the code you want to run in the handler (don't use Invoke etc)

The problem in your example is that the parameters don't match; an Action<> expects a method name (more accurately: a method group) to be invoked, and the parameters in the array must be suitable. Since you don't show the method you plan to invoke, I can't help there - but lblWarn isn't a method (it is a field).




回答3:


on this line lblWrn.Invoke(new Action(lblWrn), new object[] { lblWrn, "" });

shouldn't the bold part be a function and not a object?




回答4:


You have a few options. Option 1 is a little clunky. Options 2 and 3 are better.

Option 1: Continue with general strategy of using Control.Invoke but use code that calls Invoke correctly, disable auto resetting of the timer, and removes the event handler.

private void lblWrn_TextChange(object sender, EventArgs e)
{
    var Timee = new System.Timers.Timer(5000);
    Timee.Elapsed += this.timerClearWrn;
    Timee.AutoReset = false; // Raise the Elapsed event only once
    Timee.Enabled = true;
}

private void timerClearWrn(object sender, ElapsedEventArgs elapsed)
{
    lblWrn.Invoke(
      (MethodInvoker)(()=>
      {
        lblWrn.Text = "";
      }), null);
    var Timee = (System.Timers.Timer)sender;
    Timee.Elapsed -= this.timerClearWrn;
}

Option 2: Use a System.Windows.Forms.Timer instead of System.Timers.Timer.

Option 3: Use the SynchronizingObject property of System.Timers.Timer. This is my preferred option when timers are to be created and used dynamically from a UI thread.

private void lblWrn_TextChange(object sender, EventArgs e)
{
    var Timee = new System.Timers.Timer(5000);
    Timee.Elapsed += this.timerClearWrn;
    Timee.AutoReset = false; // Raise the Elapsed event only once
    Timee.SynchronizingObject = this; // Tell the Timer to raise the Elapsed event on the UI thread
    Timee.Enabled = true;
}

private void timerClearWrn(object sender, ElapsedEventArgs elapsed)
{
    lblWrn.Text = "";
    var Timee = (System.Timers.Timer)sender;
    Timee.Elapsed -= this.timerClearWrn;
}


来源:https://stackoverflow.com/questions/6610429/multi-thread-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!