0

I've 4 panels, having same Y and different X, that are created at the program start on a picturebox. When I click on a panel, it sets the focus and is ready to get a keysDown event so i.e. if I click on up arrow key the panel moves up.

This is the code:

public partial class FormView : Form
{
    List<CircleButton> myPanels = new List<CircleButton>(); // array of panels CircleButton
    Point[] arrayPoints_milestones; // array of X,Y
    int index;

    public FormView()
    {
        InitializeComponent();

        arrayPoints_milestones = new Point[4];
        for (int i = 0; i < 4; i++ )
        {
            arrayPoints_milestones[i] = new Point { X = 20, Y = 20 };
        }

        test();
    }

    protected void panel_Click(object sender, EventArgs e)
    {
        myPanels[index].PreviewKeyDown -= new PreviewKeyDownEventHandler(panel_KeyDown);

        CircleButton panel = sender as CircleButton;

        index = (int)panel.Tag;

        myPanels[index].Focus(); //panel.Focus();            
        myPanels[index].PreviewKeyDown += new PreviewKeyDownEventHandler(panel_KeyDown);
    }

    private void panel_KeyDown(object sender, PreviewKeyDownEventArgs e)
    {         
        if (e.KeyCode == Keys.Up)
        {
            myPanels[index].Centre = new Point(myPanels[index].Centre.X, myPanels[index].Centre.Y - 10);
            MessageBox.Show("" + myPanels[index].Centre.Y);

            Invalidate();
        }
        if (e.KeyCode == Keys.Down)
        {
            myPanels[index].Centre = new Point(myPanels[index].Centre.X, myPanels[index].Centre.Y + 10);
            MessageBox.Show("" + myPanels[index].Centre.Y);

            Invalidate();                
        }    
    }

    private void test()
    {
        //for (int i = 0; i < 4; i++)
        int i=0;
        foreach(var value in arrayPoints_milestones)
        {
            CircleButton panel = new CircleButton();
            panel.Tag = i;
            panel.Centre = new Point(arrayPoints_milestones[i].X + i * 10, arrayPoints_milestones[i].Y);
            panel.Radius = 10;
            panel.BackColor = Color.Red;
            panel.Message = "Index: " + panel.Tag.ToString();

            myPanels.Add(panel); // qui aggiungo il pannello alla lista di pannelli myPanels 

            pictureBox1.Controls.Add(myPanels[i]);
            myPanels[i].Click += new EventHandler(panel_Click);

            i++;
        }
    }

}

and this is the custom panel class:

public class CircleButton : Panel
{
    //Properties to draw circle
    float radius;
    public float Radius
    {
        get { return radius; }
        set
        {
            radius = value;
            this.Size = new Size((int)Radius, (int)Radius);
        }
    }

    public string Name
    {
        get;
        set;
    }

    Point centre;
    public Point Centre
    {
        get { return centre; }

        set
        {
            centre = value;
            this.Location = Centre;
        }
    }

    public string Message { get; set; }

    public CircleButton()
    {
        //Default Values
        Name = "panel_base";
        this.BackColor = Color.Black;
        Radius = 1;
        Centre = new Point(0, 0);
        this.DoubleBuffered = true;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        //Defines a graphic path and set it as the panel's region
        //For custom region use different path's
        if (centre != null)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddEllipse(0, 0, radius, radius);
            this.Region = new Region(path);
            path.Dispose();
        }
    }        
}
Luke
  • 503
  • 2
  • 7
  • 17
  • 1
    `Point`s are structures, so they don't are called by reference. E.g.: Calling `arrayPoints_milestones[index].Y += 10;` has no effect to `List myPanels` – Binkan Salaryman Mar 10 '15 at 11:20
  • @BinkanSalaryman ok you're right thankyou, now how can I fix the problem about the click ? – Luke Mar 10 '15 at 11:33
  • For the future I suggest you to learn more about reference and value types: http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c – Binkan Salaryman Mar 10 '15 at 12:00

1 Answers1

1

Each time you click a panel, a PreviewKeyDownEventHandler is added - so 3 clicks will trigger 3 (different) eventhandlers with the same invocation target, and each will move your panel for 10 pixels up/down:

protected void panel_Click(object sender, EventArgs e) {
    CircleButton panel = sender as CircleButton;

    index = (int)panel.Tag;

    myPanels[index].Focus(); //panel.Focus();
    myPanels[index].PreviewKeyDown += new PreviewKeyDownEventHandler(panel_KeyDown);
}


Updated code for FormView:

public partial class FormView : Form {
    List<CircleButton> myPanels = new List<CircleButton>(); // local use only in my example
    Point[] arrayPoints_milestones; //not needed anymore
    int index; //not needed anymore

    public FormView() {
        InitializeComponent();
        this.Load += FormView_Load;
    }

    void FormView_Load(object sender, EventArgs args) {
        Point panelOffset = new Point(20, 20);
        for (int i = 0; i < 4; i++) {
            var panel = new CircleButton() {
                Name = "panel" + i, //Attention! You have hidden the property "Name" in "Control" with a re-declaration in "CircleButton"
                Tag = i, //not needed anymore, right?
                Centre = new Point(panelOffset.X + i * 10, panelOffset.Y),
                Radius = 10,
                BackColor = Color.Red,
                Message = "Index: " + i.ToString(),
            };
            panel.Click += (s, e) => {
                panel.Focus();
            };
            panel.PreviewKeyDown += (s, e) => {
                if(e.KeyCode == Keys.Up) {
                    Point centre = panel.Centre; //copy value
                    centre.Y -= 10;
                    panel.Centre = centre; //assign modified copy
                    Invalidate();
                }
                if(e.KeyCode == Keys.Down) {
                    Point centre = panel.Centre; //copy value
                    centre.Y += 10;
                    panel.Centre = centre; //assign modified copy
                    Invalidate();
                }
            };
            myPanels.Add(panel);
            pictureBox1.Controls.Add(panel);
        }
    }
}
Binkan Salaryman
  • 3,008
  • 1
  • 17
  • 29
  • I did something like the following and seems to work.. I appreciate other different solutions if you have one, thank you. Inside `private void panel_KeyDown(object sender, PreviewKeyDownEventArgs e)` after the `Invalidate();` i added this: `myPanels[index].PreviewKeyDown -= new PreviewKeyDownEventHandler(panel_KeyDown);` – Luke Mar 10 '15 at 13:41
  • thank you for your comments in the solution, it helps me a lot. – Luke Mar 10 '15 at 13:48
  • by the way I can't run your solution.. it doesn't create the 4 panels on the picturebox.. – Luke Mar 10 '15 at 13:53
  • 1
    The line `Message = "Index: " + Tag.ToString(),` throws a NPE, replace `Tag` with `i`, sorry for that. In fact, I expected `Tag = i` to come first. Well, that was a premature precondition :/ – Binkan Salaryman Mar 10 '15 at 14:05
  • ok now it works, thanks for the tip. Anyway I found another way to use my solution without problems, check it out looking at my code updated. Can you tell me if it correct too? – Luke Mar 10 '15 at 14:32
  • I added this: `myPanels[index].PreviewKeyDown -= new PreviewKeyDownEventHandler(panel_KeyDown);` in `panel_Click()` method. – Luke Mar 10 '15 at 14:43
  • 1
    Simply add the EventHandler **once** and not every time you click or similar: in `private void test()` you have the line `myPanels[i].Click += new EventHandler(panel_Click);`. Do the same thing for the `PreviewKeyDown` event and you're done. What you did is roughly that: `var panel = new CircleButton(); panel.Click += (s, e) => {panel.PreviewKeyDown += (s, e) => {...*MADNESS*...}};` – Binkan Salaryman Mar 10 '15 at 14:56