Question

Note: Part of a series: C#: Accessing form members from another class and How to access form objects from another cs file in C#.


Hello,

The Idea is to notify the user using the memo when a packet is received/sent in a TCP Client.

After couple of fixes,the most suitable solution seemed to be this one

    public string TextValue
    {
        set
        {
            this.Memo.Text += value + "\n";
        }
    }

That's how it's being called

    var form = Form.ActiveForm as Form1;
    if(form != null)
        form.TextValue = "Test asdasd";

However,calling the code throws an exception ,because of Unsafe thread call.I found a solution at msdn,but I can't seem to acquire the method they've used there.

This is my remake,which doesn't work.

    private void SetTextMemo(string txt)
    {
        if(this.Memo.InvokeRequired)
        {
            this.Invoke(SetTextMemo,txt); //error here
        }
        else
        {
            this.Memo.Text += txt + "\n";
        }
    }

errors:

Argument '1': cannot convert from 'method group' to 'System.Delegate'

Argument '2': cannot convert from 'string' to 'object[]'

Basically,I'm trying to access the Memo(or more likely said,add text to the memo) from another thread using Invoke.I never used it before,maybe that's why I misunderstand my mistake.

Was it helpful?

Solution

The easy way is:

this.Invoke((MethodInvoker)delegate {
    this.Memo.Text += txt + "\n";
});

Which uses an anonymous method to do the job inline. Since you expect to be on another thread, you may as well just call Invoke - it is safe even from the UI thread.

OTHER TIPS

If you're using C# 3.0 and the 3.5 framework try the following

if ( this.Memo.InvokeRequired ) {
  this.Invoke((Action)(() => SetTextMemo(txt)));
} 

Your implementation assumes that the method will not infinitely recurse because the behavior of the InvokeRequired property will prevent it. This assumption may proove to be true, but there's no problem coding the function to avoid this possibility entirely. Here's what I suggest:

    private void SetMemo(string txt)
    {
        Memo.Text = txt;
    }

    private delegate void MemoSetter(string txt);

    public void ThreadSafeSet(string txt)
    {
        Invoke(new MemoSetter(SetMemo), txt);
    }

I used to handle all this cross-thread business, but recently I went with AOP, where you simply decorate a method to execute on the UI thread. Here's an example (from PostSharp):

public class FormsThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    Form f = (Form)eventArgs.Delegate.Target;
    if (f.InvokeRequired)
      f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray());
    else
      eventArgs.Proceed();
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top