简体   繁体   中英

C# error: object reference is required for the non static field

I have little windows forms program that plays music using console.beep from strings. I have the string playing bit (which is basically a for loop that goes through the strings char by char and plays the appropriate note) set up in a new thread 't'. When you hit the "play" button the thread starts and the button changes to a "stop" button. If you hit this now "stop" button while the music is playing it will stop and the button changes back to play (by calling the "finished" method. My problem is that I want the loop running in the new thread to also call the "finished" method when the loop has run its course and the song is over. But if i put finished() after my loop i get the "object reference is required for the non static field" error. If I change the "finshed" method to static then the bit that changes the button text doesnt work...

Heres the code for when you press the button...

//This is the method for when the "start" button is clicked
public void button1_Click(object sender, EventArgs e) 
    {
        if (music == null) { return; }

        if (button1.Text == "Play")
        {
            // it makes a new thread which calls my "parse" method which 
            // interprets the music and then calls "playnote" to play it.
            Thread t = new Thread(parse); 
            t.Start();
            button1.Text = "Stop";
        }
        else 
        {
            finished();
        }
    }

    public void finished()
    {
        stop = true;
        button1.Text = "Play";
    }

Any suggestions?

Thanks a lot in advance!

Edit: Thanks all!! I dont really have time to figure out the background worker atm so I just have seperate start and stop buttons now! :p

I think this would be better accomplished with a BackgroundWorker thread . That way you can call the finished() method in the RunWorkerCompleted event.

Is the parse() method static? It seems like you are trying to call the finished() from a static method without providing the instance, which is why you are getting the "object reference is required for the non static field" error.

What you need to do is make sure that the created thread has access to the object that created it (ie "this", in the scope of your "button1_Click()" method). To do this, you can call t.Start(this) instead of t.Start(). In doing so, you will be passing to the thread the object capable of calling the "finished()" method. Next, you need to make sure the "parse" method takes an argument of type Object. In doing so, when you call "t.Start(this)", the method "parse" will receive "this" as a parameter. A simple cast will be required to convert to the appropriate type. Now, when you want the song to be stopped in the thread, simply call the "finish()" method on the casted parameter. So your code should look something like:

public void parse(object o) { MyClass c = o as MyClass; // replace MyClass with the name of your class

[...] // play music here

c.finished();  // call finished when you are done

}

public void button1_Click(object sender, EventArgs e) { [...]

Thread t = new Thread(parse); t.Start(this); // instead of t.Start()

[...] }

Static versus member method

  1. Either you have a member (non static) method and you call it
obj.SomeMethod();
  1. Or you have a static method and you call it with
ClassName.SomeMethod();

unless it is called inside the defining class itself. Then it can simply be called with

SomeMethod();

in both cases.


Threading

The only thread which is allowed to interact with the UI (eg with button1.Text ) is the UI-thread itself. The UI-thread is the main thread in which your code is normally running.

See How to update the GUI from another thread in C#? for interacting with the form from another thread.

What you need to do is raise an event on the main thread to call your finished method. Start by declaring the event and delegate in your form class.

public delegate void CallFinishedEventHandler();
public event CallFinishedEventHandler CallFinished;

Then create an event handler that will be called when the event is raised, and in the make your call to your finished method.

void Form1_CallFinished()
{
  Finished();
}

Then in your form constructor wire up your event handler to your event.

public Form1()
{
    CallFinished += Form1_CallFinished;
}

Finally, in your music playing code, when you want to call your finished method (on the UI thread) invoke your event so that it will be fired on the UI thread.

this.Invoke(CallFinished);

This is simple, create a global thread, and then access it where you want.

Thread t;
    public void button1_Click(object sender, EventArgs e) 
        {
            if (music == null) { return; }

            if (button1.Text == "Play")
            {
                // it makes a new thread which calls my "parse" method which 
                // interprets the music and then calls "playnote" to play it.
                t = new Thread(parse); 
                t.Start();
                button1.Text = "Stop";
            }
            else 
            {
                finished();
            }
        }

        public void finished()
        {
            stop = true;
            button1.Text = "Play";
        }

for calling finished, make an instance of your form class and then call the method.

Form1 frm1 = new Form1();
frm1.finished();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM