C#: String as parameter to event?
Asked Answered
G

5

16

I have a GUI-thread for my form and another thread that computes things.

The form has a richtTextBox. I want the worker-thread to pass strings to the form, so that every string is displayed in the textbox.

Everytime a new string is generated in the worker thread I call an event, and this should now display the string. But I don't know how to pass the string! This is what I tried so far:

///// Form1
private void btn_myClass_Click(object sender, EventArgs e)
{
    myClass myObj = new myClass();
    myObj.NewListEntry += myObj_NewListEntry;
    Thread thrmyClass = new Thread(new ThreadStart(myObj.ThreadMethod));
    thrmyClass.Start();
}

private void myObj_NewListEntry(Object objSender, EventArgs e)
{
    this.BeginInvoke((MethodInvoker)delegate
    {
        // Here I want to add my string from the worker-thread to the textbox!
        richTextBox1.Text += "TEXT"; // I want: richTextBox1.Text += myStringFromWorkerThread;
    });
}

///// myClass (working thread...)
class myClass
{
    public event EventHandler NewListEntry;

    public void ThreadMethod()
    {
        DoSomething();
    }

    protected virtual void OnNewListEntry(EventArgs e)
    {
        EventHandler newListEntry = NewListEntry;
        if (newListEntry != null)
        {
            newListEntry(this, e);
        }
    }

    private void DoSomething()
    {
        ///// Do some things and generate strings, such as "test"...
        string test = "test";


        // Here I want to pass the "test"-string! But how to do that??
        OnNewListEntry(EventArgs.Empty); // I want: OnNewListEntry(test);
    }
}
Gastroenteritis answered 21/8, 2012 at 13:1 Comment(1)
Subclass EventArgs and add your string as a property.Capacitance
C
26

Like this

public class NewListEntryEventArgs : EventArgs
{
    private readonly string test;

    public NewListEntryEventArgs(string test)
    {
        this.test = test;
    }

    public string Test
    {
        get { return this.test; }
    }
}

then you declare your class like this

class MyClass
{
    public delegate void NewListEntryEventHandler(
        object sender,
        NewListEntryEventArgs args);

    public event NewListEntryEventHandler NewListEntry;

    protected virtual void OnNewListEntry(string test)
    {
        if (NewListEntry != null)
        {
            NewListEntry(this, new NewListEntryEventArgs(test));
        }
    }
}

and in the subscribing Form

private void btn_myClass_Click(object sender, EventArgs e)
{
    MyClass myClass = new MyClass();
    myClass.NewListEntry += NewListEntryEventHandler;
    ...
}

private void NewListEntryEventHandler(
    object sender,
    NewListEntryEventArgs e)
{
    if (richTextBox1.InvokeRequired)
    {
        this.Invoke((MethodInvoker)delegate
            {             
                this.NewListEntryEventHandler(sender, e);
            });
        return;
    }

    richTextBox1.Text += e.Test;
}

I've taken the liberty of making the NewListEntryEventArgs class immutable, since that makes sense. I've also partially corrected your naming conventions, simplified and corrected where expedient.

Capacitance answered 21/8, 2012 at 13:20 Comment(3)
Thanks, but I get error "The best overloaded method match for 'declaration' has some invalid arguments" at this.BeginInvoke(NewListEntryEventHandler, sender, e);Gastroenteritis
My error, that should take a delegate instead of a method group. I've improved my code.Capacitance
OMG events are a PITAClaudication
P
5

You need to create a new class by inheriting off EventArgs.

Patricapatrice answered 21/8, 2012 at 13:2 Comment(0)
D
3

Create your own version of the EventArgs.

Do it like this:

public class MyEventArgs : EventArgs
{
   public string MyEventString {get; set; }

   public MyEventArgs(string myString)
   {
       this.MyEventString = myString;
   }
}

Then in your code replace the EventArgs with MyEventArgs and create an MyEventArgs object with your string in it.

Then you can access it by using the MyEventArgs instance .MyEventString.

So you would do something like this:

///// myClass (working thread...)
class myClass
{
    public event EventHandler NewListEntry;

    public void ThreadMethod()
    {
        DoSomething();
    }

    protected virtual void OnNewListEntry(MyEventArgs e)
    {
        EventHandler newListEntry = NewListEntry;
        if (newListEntry != null)
        {
            newListEntry(this, e);
        }
    }

    private void DoSomething()
    {
        ///// Do some things and generate strings, such as "test"...
        string test = "test";

        OnNewListEntry(new MyEventArgs(test));
    }
}

And in your form:

private void myObj_NewListEntry(Object objSender, MyEventArgs e)
{
    this.BeginInvoke((MethodInvoker)delegate
    {
        // Here I want to add my string from the worker-thread to the textbox!
        richTextBox1.Text += e.MyEventString;
    });
}
Delusion answered 21/8, 2012 at 13:7 Comment(1)
When I add crawler.NewListEntry += crawler_NewListEntry; to my Form1, I get error: No overload that matches the delegate System.EventHandler'. ??Gastroenteritis
T
1

In general you need to inherit EventArgs and add a string property, and then make your event of type EventHandler<YourEventArgs>, but that is a classic case for the BackgroundWorker.

Sample here: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

and here: C# backgroundWorker reports string?

Thaddeusthaddus answered 21/8, 2012 at 13:5 Comment(0)
S
0

I was looking for a similar solution. Here is a more modern syntax than the other answers:

event args with string

public class StringEventArgs: EventArgs
{
   public StringEventArgs(string myString)
   {
       MyString = myString;
   }

   public string MyString { get; } // private set: only ctor can set it
}

myClass (working thread...)

class myClass
{
    public event EventHandler<StringEventArgs> NewListEntry; // no delegate declaration anymore

    public void ThreadMethod()
    {
        DoSomething();
    }

    private void DoSomething()
    {
        string test = "test";
        NewListEntry?.Invoke(this, new StringEventArgs(test)); // no OnNewListEntry() anymore
    }
}

Form1

private void btn_myClass_Click(object sender, EventArgs e)
{
    var myObj = new myClass();
    myObj.NewListEntry += OnNewListEntry;
    var myThread = new Thread(new ThreadStart(myObj.ThreadMethod));
    myThread.Start();
}

private void OnNewListEntry(Object sender, StringEventArgs e)
{
    this.BeginInvoke((MethodInvoker)delegate
    {
        // Here I want to add my string from the worker-thread to the textbox!
        richTextBox1.Text += e.MyString;  
    });
}
Stall answered 1/4 at 21:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.