views:

1720

answers:

4

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.

+4  A: 

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.

Marc Gravell
This is the 2nd (but not the last time) that Gravell has saved my bacon. Just for that, you can have this Saturday off. What the heck I guess I can give you Sunday too.
Chris
+1  A: 

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

if ( this.Memo.InvokeRequired ) {
  this.Invoke((Action)(() => SetTextMemo(txt)));
}
JaredPar
And .NET 3.5 for the Action delegate type ;-p
Marc Gravell
@Marc, I keep forgetting that is a 3.5 type. Why it wasn't added in 2.0 is beyond me :)
JaredPar
A: 

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();
  }
}
Dmitri Nesteruk
This is where AOP should certainly be used before any other methods IMHO. But for those unfamiliar with PostSharp and AOP it may be difficult to understand how it works exactly from your post, and what is the actual simplicity of its usage.
Groo
Well, I'd offer links to the teaching materials relating PostSharp, but I'm actually not allowed to :(
Dmitri Nesteruk
+1  A: 

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);
    }
Paul Keister