views:

225

answers:

3

Hello,

I'm an extreme newbie at C#, but I've been slowly moving through the Head Start C# tutorial book (and finding it extremely enjoyable so far). However, I've hit a wall on the first "lab" assignment: They give code for controlling a PictureBox, and I can get that code to work on the main Form, but I can't get it to work from within a Class. I've gone back over the old lessons, and I've got a fairly good idea of what I'm missing, but for the life of me I can't figure out how to access the main Form's PictureBox from within my class (as the tutorial is telling me I should do).

It's a bit frustrating, because I didn't jump ahead in the book at all, but I'd swear we haven't covered this yet. Anyway, appealing to Real programmers.

Here's the code provided in the tutorial, in a section called "Your object can control things on your form" (p208 for anyone with the book).

Point p = MyPictureBox.Location 
p.x += distance;
MyPictureBox.Location = p

Below I'm posting the relevant (I think?) parts of my code below. Button1 works for me when compiled, Button2 "works," in the sense that the current class just tells it to print the passed INT because I've commented out the code I can't get to work.

Thanks in advance!

Code for the Form1:

//


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
// Namespaces I'll need.

namespace Troubleshooting_PicBoxes
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent(); // Start all the Form1 stuff (all IDE-generated)

    }

    private void button1_Click(object sender, EventArgs e) //method from clicking the first button
    {
        int distance = 5; // Create this variable called "distance"

        Point BoxMovement = MyPictureBox.Location; //create a point called BoxMovement

        BoxMovement.X += distance; // Adjust the X of BoxMovement by my distance int.

        MyPictureBox.Location = BoxMovement; // now adjust the Box by the Point's location.

    }

    private void button2_Click(object sender, EventArgs e)
    {
        PicMover PicMoverObject1 = new PicMover(); // Reserve Space for&Create object
        PicMoverObject1.MoveThatPic(5); // Execute Object Method with a value of 5




    }


}
}

Code for the PicMover class:

//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Troubleshooting_PicBoxes
{
class PicMover
{


    public void MoveThatPic(int distance) // New method, 
                                          // takes a variable called Distance.

    {
        MessageBox.Show(distance.ToString()); // Just show us that Variable.


        // I need to be able to access Form1's picture box before I can use this. :(
        /*           Point BoxMovement = MyPictureBox.Location; //create a point called BoxMovement
                    BoxMovement.X += distance; // Adjust the X of that by distance.
                    MyPictureBox.Location = BoxMovement; // now adjust the Box by the Point's location.
        */


    }
}

}

+1  A: 

If you need to access something, why don't you just give it access? Like passing it as a argument to the method.

public void MoveThatPic(PictureBox picBox, int distance) // New method, 
                                      // takes a variable called Distance.

{
    MessageBox.Show(distance.ToString()); // Just show us that Variable.


    // I need to be able to access Form1's picture box before I can use this. :(
    Point BoxMovement = picBox.Location; //create a point called BoxMovement
    BoxMovement.X += distance; // Adjust the X of that by distance.
    picBox.Location = BoxMovement; // now adjust the Box by the Point's location.
}

now in button2 click event handler:

private void button2_Click(object sender, EventArgs e)
{
    PicMover PicMoverObject1 = new PicMover(); // Reserve Space for&Create object
    PicMoverObject1.MoveThatPic(MyPictureBox, 5); // Execute Object Method with a value of 5
}
deerchao
That did it! I hadn't realized I could pass the PictureBox object like an INT variable, but I should have realized that they were both just objects. Thanks much. :)
A: 

The tutorial code LOOKS like you are grabbing the location from your class (MyPictureBox.Location) then changing the location, then moving your object to that new location.

Point p = MyPictureBox.Location // Save the location of your object
p.x += distance; // Increase the distance
MyPictureBox.Location = p // Set your object to the new location

The second button press event is different. Perhaps you should be returning a location from the function? So, when you call the function, you set the PictureBox on the main form to the value returned.

ShaunLMason
I was considering something like that, but it requires leaving the PictureBox controls on the main Form, and I needed to use them from within the Class to fit the criteria of the tutorial. Deerchao tipped me off on how to do that, but I appreciate the answer!
A: 

If you want to create a general purpose class that can be accessed from any Form ... that creates an instance of it ... to move any PictureBox on that Form, then 'Deerchao's answer shows you how to do it.

Although ... consider ... every Form is going to have declare its own instance of PicMover; Form1's instance of PicMover is not "visible" to any other Form unless you also somehow publish it.

To put it more technically : the PicMover class, as defined here, exists in the Scope of the Application NameSpace; it's a template for creating type of object that every other Class in the Application can use to make an instance of, but that no Class in the Application "has" an instance of by default.

Here's an alternative to Deerchao's excellent answer that demonstrates "injection" : injection is appropriate when you want an instance of a class to "hold onto" a reference : in this example we say that the Form's instance of a PictureBox gets "bound" to an instance of the 'PicMover class :

We declare a Public Property within the class 'PicMover that will hold a reference to Form1's PictureBox :

public class picMover
{
    // note use of C# 3.0 automatic property feature here
    public PictureBox myPictureBox { get; set; }

    public void movePic(int distance)
    {
        // note test for null here
        if (myPictureBox != null)
        {
            myPictureBox.Left += distance;
        }
    }
}

So in Form1 after you create the instance of 'PicMover, you set its internal PictureBox Property, and then use its internal 'movePic method : like this :

// instance of PicMover created in the Form's scope
picMover myPicMover = new picMover();

private void Form1_Load(object sender, EventArgs e)
{
    // when the Form loads inject the reference to the PictureBox instance into the instance of 'PicMover
    myPicMover.myPictureBox = pictureBox1;
}

private void button1_Click(object sender, EventArgs e)
{
    myPicMover.movePic(23);
}

Note that, imho, testing to make sure an "injected" reference to an object exists, by testing for null before using it is a good habit to get into.

Another way you can get an instance of the PictureBox object "bound" into an instance of 'PicMover is to pass the instance of the PictureBox to the Constructor of the class as a parameter : I bet by the time I finish posting this, someone else will have already posted an answer showing that technique. You might want to "inject" using a Public Property as shown here when you expect the internal reference to be changed vs. passing the PictureBox in to the Constructor of the Class when you don't expect it to be changed.

Another strategy is to make 'PicMover a public static class, with public static methods : then every Form can "see it," and there's no need for any form to make an instance of it (in fact you can't "instance" a static class if you wanted to : that's what a static class is).

BillW