1

OK I've edited everything in this original post now. I've gone back to visual studio 2010 and created a new project and coded the same thing, except only coded the bare minimum to get the same roadblock I had before. This means I am posting the ENTIRE project code here, but it is also quite short and readable. I've included comments to make it easier to follow, too. Just a recap: the problem is that I'm not able to successfully call Form1.refreshScore() from any other class than Form1 itself

public partial class Form1 : Form
{
    private Enemy enemy_;
    private Graphics paper_;
    private bool started_;


    public Form1()
    {
        InitializeComponent();
    }

    private void timer_Tick(object sender, EventArgs e)
    {
        pictureBox.Refresh();
    }
    private void pictureBox_Paint(object sender, PaintEventArgs e)
    {
        if (started_)
        {
            paper_ = e.Graphics;
            enemy_.Draw(paper_);
        }
    }

    public void refreshScore()
    {
        label.Text = "TEST";    //doesn't show
        enemy_.color = Color.Red;   //"Null Reference Exception unhandled" ?
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if(e.KeyCode == Keys.Space)
        {
            enemy_ = new Enemy(0, pictureBox.Height-20, 20, 100, 2, Color.Blue);
            paper_ = pictureBox.CreateGraphics();
            started_ = true;    //succeeds
        }
        if (e.KeyCode == Keys.K)
        {
            enemy_.Kill();
            enemy_.color = Color.Green; //succeeds.
        }
    }



}

    class Enemy
{
    private float x_;
    private float y_;
    private float diameter_;
    private float health_;
    private float walkSpeed_;
    private Color color_;

    private Form1 form_ = new Form1();

    //Overloader
    public Enemy()
    {
        x_ = 1;
        y_ = 50;
        diameter_ = 20;
        walkSpeed_ = 1;
        health_ = 100;
        color_ = Color.Blue;
    }
    //Constructor, called in Form1, keydown event ("Space")
    public Enemy(float x, float y, float diameter, float health, float walkSpeed, Color color)
    {
        x_ = x;
        y_ = y;
        diameter_ = diameter;
        health_ = health;
        walkSpeed_ = walkSpeed;
        color_ = color;
    }

    //getter/setter for 'color' property
    public Color color
    {
        get { return color_; }
        set { color_ = value; }
    }

    public void Draw(Graphics paper)
    {
        SolidBrush brush = new SolidBrush(color_);
        paper.FillRectangle(brush, x_,y_,x_ + diameter_, y_ + diameter_);
    }

    //called in Form1 under KeyDown event ("K")
    public void Kill()
    {
        form_.refreshScore();
    }
}
ZOMGbies
  • 51
  • 1
  • 1
  • 7
  • 2
    there are plenty of samples about how to call a class from another class. There is no need for a new question like this unless you have a specific problem and in your case does not look like that because it seems you are just trying to get the way to do it. Start looking at the answers to this question http://stackoverflow.com/questions/2950326/calling-a-function-in-the-form-class-from-another-class-c-sharp-net – FeliceM Feb 15 '14 at 16:16
  • Yes, you're kind of right (and I am truly sorry for doing this, I know it's annoying). But I've seen that page (and many others), they all seem to suggest the same few solutions, but none of them make sense to me. Solutions are all similar to this: turn all of your classes/methods into "static" type - I don't quite understand what this means and it instantly causes all of my code to show compile errors. I'm new to C# and cant understand what I need to do in order to have a referencable object to dot-notation call methods from (like in the above example), as that seems simplest... – ZOMGbies Feb 15 '14 at 16:25
  • Btw you can just paste a block of code into the text editor then highlight it and click on the `{}` button to make it a code sample. – JW Lim Feb 15 '14 at 17:00
  • Just found that! Thank you. – ZOMGbies Feb 15 '14 at 17:16
  • Ok.. There doesn't seem to be anything wrong with the code that will cause a compiler error. What exactly is not working? What do you wish the program to achieve and output? – JW Lim Feb 15 '14 at 17:20
  • I want the label (`labelKilledCount`) to output the variable passed as a parmeter of `refreshKillCount()`. When this method is called from the Enemy class, nothing happens, even when I have that sanity check line in. But there is nothing wrong with the method itself, as it works perfect when I call `refreshKillCount()` from within the Form1 class. Hence my conclusion that my form1 reference/instance is referencing the wrong object/ referencing incorrectly – ZOMGbies Feb 15 '14 at 17:32
  • @ZOMGbies Who is calling `DeathCheck`? According to your current code, `refreshKillCount` will only be called from within the `DeathCheck` method in the `Enemy` class, and only when `(isDead && (form1.timePassed) >= (deadTime_+2))` returns true. But I don't see any code calling `DeathCheck`. – JW Lim Feb 15 '14 at 17:37
  • Ah I understand the confusion. I removed the Method calling Deathcheck for simplicity. It is being called by the method responsible for moving the Enemy object (in Form). I felt it was safe to remove it from the code I pasted here, because I confirmed the `refreshKillCount()` line was being called by modifying the `Color` variable before and after that line in `DeathCheck()`. – ZOMGbies Feb 15 '14 at 17:43
  • In that case, place a breakpoint on the `{` after this line `else if(isDead && (form1.timePassed) >= (deadTime_+2))`. Run in debug mode & check if the method calling `DeathCheck` is actually going into that block of code inside the condition. – JW Lim Feb 15 '14 at 17:46
  • I've not heard of what you suggested, sorry? Is a semi colon a breakpoint? Could you please clarify for me what exactly im doing and where?? :) (sorry) Although it might not be necessary for you to - I've put the line `color_ = Color.Pink;` in before and after the line calling `refreshKillCount()`; and it changes the object to pink successfully... – ZOMGbies Feb 15 '14 at 17:51
  • I also tried calling `form1.labelKilledCount.Text = "TEST";` and that did nothing too. – ZOMGbies Feb 15 '14 at 17:57
  • Strange. Could there be some other code that's setting `labelKilledCount.Text = ""` after you call `DeathCount`? Try adding a new label to the form, and add code to change the text of the new label in `refreshKillCount`. Btw breakpoints: http://www.dotnetperls.com/debugging – JW Lim Feb 15 '14 at 18:01
  • I've tried that :( I ALSO tried putting the line `form1.newLabel.Text = "TEST"`; into a Movement method thats called repeatedly. The label accessibility is set to public, thats all i changed beyond default settings. – ZOMGbies Feb 15 '14 at 18:07

3 Answers3

1

You have to add static to the class methods

public class Class1
{
    public static void MyMethod(float x)
    {
        return x*x ;
    }
}

and you call your method like this :

float y = Class1.MyMethod(5.24);
Karam Najjar
  • 527
  • 5
  • 21
  • Thats what my googling has told me, too. BUt whenever I do that I get this compile error for every variable: "An object reference is required for the non-static field, method, or property..." – ZOMGbies Feb 15 '14 at 16:45
1

I'm assuming that you've got a WinForms app and Form1 is the default form class created in your project.

In this case what's likely going on is your application Main method is creating an instance of Form1 and displaying it. However, your Enemy class is creating its own instance of the Form1 class:

Form1 form1 = new Form1();

That's a completely different instance from the one that's being displayed. You need to give your Enemy the instance that's being displayed. Perhaps the easiest way to do that is by having Form1 create an instance of Enemy and pass this to it. For example:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        _enemy = new Enemy( this );
    }

    private Enemy _enemy;
}

And then your Enemy class would look something like this:

public class Enemy
{
    public Enemy( Form1 form )
    {
        _form1 = form;
    }

    // DON'T initialize this with new Form1();
    private Form1 _form1;
}

Now when your Form1 gets created, it will create an instance of Enemy which will then get a reference to the form.

Kyle
  • 6,500
  • 2
  • 31
  • 41
  • +1 LOL I didn't think of that! How stupid of me. Would it be more appropriate to pass the form instance in the `DeathCheck` method instead of the `Enemy` class? :) – JW Lim Feb 15 '14 at 18:16
  • Well, that really depends on how all of this is going to be used. If that method is the only time the `Enemy` needs to interact with the form, then I would say yes. If `Enemy` needs to interact with the form a lot more frequently, I would say no. In general I don't think I would have a non-form class directly operate on the form. Instead I'd likely have the form get data from `Enemy` and then take care of how and where to display that itself. – Kyle Feb 15 '14 at 18:20
  • I agree in that I'd have the form take care of the display itself. In this scenario, I would probably pass a parameter by reference to the method to return the `killedCount`, or pass the label control instead of the entire form. Or is there a better way to approach it, considering that the method itself returns bool? – JW Lim Feb 15 '14 at 18:26
  • This has prima facie solved the problem, it just took me an embarrassingly long time to figure out what you were saying (granted it was 6am when I last read it). – ZOMGbies Feb 16 '14 at 03:53
0

The answer is already in the code you provided.

  1. Instantiate the class containing the method you want to call. ClassName object = new ClassName();
  2. Call the method using the class instance you created. object.MethodName().

Another way of doing it is to declare your method as static. If you declare your method as static, you do not need to instantiate your class before calling the method (i.e. do not perform step 1). Example:

public class Class1
{
    public static void Method1()
    {
        //some code
    }
}

public class Class2
{
    Class1.Method1(); //you do not need to instantiate the class if your method is static
}

PS: If you declare your method as static but try to call the method using an instance of the class (object.MethodName), you will get a compiler error saying that you should not use an instance to call a static method.

I suggest you go through these references for a better understanding: ref 1, ref 2, ref 3. Better still, you should pick up a book on object-oriented programming.

Community
  • 1
  • 1
JW Lim
  • 1,794
  • 3
  • 21
  • 41
  • Yeah I am trying to instance the classes as you see in my dummy code above, im doing so by following myriad tutorials word for word, and its simply not calling the methods. Its compiling and running, but my only conclusion is that its trying to call an object that isnt the form; i.e. a 'blank' new one that isnt the actual one? Urgh, sorry I don't quite have the coding vocab yet ;P Whenever I add static to anything I get the compile error: "An object reference is required for the non-static field, method, or property..." – ZOMGbies Feb 15 '14 at 16:45
  • @ZOMGbies I'm not sure I understand what you meant by the "blank new form". However, make sure that you are declaring your *method* as static. And please check that you are not trying to call a non-static method from within a static one. That will not work because the static method has no instance of the class to call on. – JW Lim Feb 15 '14 at 16:48
  • `public static void refreshKillCount() { label.Text = "TEXTHERE"; }` This is giving me the compile error mentioned above... – ZOMGbies Feb 15 '14 at 16:54
  • @ZOMGbies Please edit your question to include the actual code that's producing the error. Include both the the method you wish to call and the caller method itself, along with their classes. – JW Lim Feb 15 '14 at 16:55