Jump to content
  • Advertisement
Sign in to follow this  

[.net] Problems Setting a Variable in a List

This topic is 4815 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having a really confounding issue. I'm trying to do something in C# that works perfectly in Java and VB 6 as far as I remember, but it refuses to do what I want in C#. The source code for the class in question is below (this is a PictureBox control array class I wrote using MSDN examples on control arrays):
using System;
using System.Windows.Forms;

namespace AStarTester
{

	public struct PictureTag
	{
		PictureBox pb;
		int tag;
		
		public PictureBox PB
		{
			get{return pb;}
			set{this.pb = value;}
		}
		public int Tag
		{
			get{return tag;}
			set{this.tag = value;}
		}		
	}

	/// <summary>
	/// Summary description for PictureBoxArray.
	/// </summary>
	public class PictureBoxArray : System.Collections.CollectionBase
	{
		private readonly System.Windows.Forms.Form HostForm;
		private int arraySquareSize;		
		private int counter;
		private int mintCurrentClickType;

		public PictureBoxArray(System.Windows.Forms.Form host, ref System.Windows.Forms.TextBox txtBox)
		{
			this.HostForm = host;						
			this.arraySquareSize = Int32.Parse(txtBox.Text);			
			this.counter = 0;			
			this.AddNewPictureBox();
		}		
			
		public void AddNewPictureBox()
		{

			for (int i = 0; i < this.arraySquareSize; i++)
			{
				for (int j = 0; j < this.arraySquareSize; j++)
				{
					//create a new instance of the picturebox class
					System.Windows.Forms.PictureBox aBox = new System.Windows.Forms.PictureBox();

					//add the button to the collections internal list
					PictureTag temp = new PictureTag();
					temp.PB = aBox;
					temp.Tag = 3;
					this.List.Add(temp);

					//add the button to the controls collection of the form
					//referenced by HostForm
					HostForm.Controls.Add(aBox);

					//handle arranging the control array to be the proper columns and rows
					aBox.Top = this.counter * 30 + 16;
					aBox.Left = j * 30 + 10;
					aBox.Tag = this.Count;
					aBox.Width = 30;
					aBox.Height = 30;
					aBox.Image = new System.Drawing.Bitmap(@"..\..\nodes.bmp");
					aBox.Click += new System.EventHandler(ClickHandler);
					
				}				
				this.counter++;
			}	
		}

		//public property accessor
		public System.Windows.Forms.PictureBox this [int Index]
		{
			get
			{
				return (System.Windows.Forms.PictureBox) this.List[Index];
			}
		}

		public int ClickValue
		{
			//Key: 0 = start location set, 1 = end location, 2 = impassable, 3 = passable
			set { this.mintCurrentClickType = value; }
		}

		public void Remove()
		{
			if (this.Count > 0)
			{
				HostForm.Controls.Remove(this[this.Count - 1]);
				this.List.RemoveAt(this.Count - 1);
			}
		}

		public void ClickHandler(Object sender, System.EventArgs e)
		{
			//System.Windows.Forms.MessageBox.Show("You have clicked on picturebox " +
				//((System.Windows.Forms.PictureBox) sender).Tag.ToString());			
			//on click change the image of the clicked on object to be the correct image
			//based on the this.mintCurrentClickType value
			//Key: 0 = start location set, 1 = end location, 2 = impassable, 3 = passable
			if (this.mintCurrentClickType == 0)
			{
				//we need to search through the picturebox array and get rid of the old start node first
				for (int i = 0; i < this.List.Count; i++)
				{
					if(((PictureTag)this.List).Tag == 0)
						((PictureTag)this.List).PB.Image = new System.Drawing.Bitmap(@"..\..\nodes.bmp");					
				}
			} 
			else if (this.mintCurrentClickType == 1)
			{
				//we need to search through and remove the old goal node first!

			}
			PictureTag temp;
			int intTemp;
			switch (this.mintCurrentClickType)
			{
				case 0:
					//start location
					//attempt to change the image to be the startlocation image
					((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\startpoint.bmp");
					
					//attempt to change the tag to match
					intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
					((PictureTag)this.List[intTemp - 1]).Tag = 0;
					
					//change did NOT take effect, intTemp will be the old value of 3 still
					temp = (PictureTag)this.List[intTemp - 1];
					intTemp = temp.Tag;

					break;
				case 1:
					//goal location
					((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\goalpoint.bmp");
					intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
					temp = (PictureTag)this.List[intTemp];
					temp.Tag = 1;
					break;
				case 2:
					//impassable
					((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\impassable.bmp");
					intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
					temp = (PictureTag)this.List[intTemp];
					temp.Tag = 2;
					break;
				case 3:
					//passable
					((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\nodes.bmp");
					intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
					temp = (PictureTag)this.List[intTemp];
					temp.Tag = 3;
					break;
			}
		}
	}
}


The issue occurs in case 0 of the ClickHandler method (very last method in that code). The problem is that i'm loading a PictureTag struct object from out of the control array's list based on which control they clicked on. So, I should now have access to both the Tag and Image properties of the PictureTag object. I set these properties and it seems to go through, but then when I load the tag's properties again to check, they are still the same as they were before. I tried doing it by ref, instead of making a local copy to work with, but C# complains that doing that is considered unsafe! Since when is working with pointers unsafe? I'm hoping this is a really easy fix but i've hammered my head against it for several days trying different ideas and can't seem to get it to work. Maybe i'm just thinking about the problem wrong. If you need any more information let me know. This control array is for an A* Test Implementation i'm doing outside of my game code so I can debug the stuff I need before plugging it into the main game code. Thanks, Nathan

Share this post


Link to post
Share on other sites
Advertisement
This is a classic! :)

You created a struct, which is a value type.

Now, when you want change a value type that is stored in a list you should REPLACE it or change the struct into a class (reference type)

What is actually happening is this:
(valuetype)MyList creates a COPY of the stored item
Changing the copy does NOT change the stored item but changes the copy.

The copy was made because the list is a list of Object. When you store a value type in an Object reference the value is boxed.
Unboxing takes place when you cast the reference back to a value type; this is where the actual copy is made.

Look up boxing!

Cheers

Share this post


Link to post
Share on other sites
Thanks!

The value itself is changing now, but i'm trying to get the Image of the object changed as well when they change the start location. The newest code of that method is posted below:


public void ClickHandler(Object sender, System.EventArgs e)
{
//System.Windows.Forms.MessageBox.Show("You have clicked on picturebox " +
//((System.Windows.Forms.PictureBox) sender).Tag.ToString());
//on click change the image of the clicked on object to be the correct image
//based on the this.mintCurrentClickType value
//Key: 0 = start location set, 1 = end location, 2 = impassable, 3 = passable
if (this.mintCurrentClickType == 0)
{
//we need to search through the picturebox array and get rid of the old start node first
for (int i = 0; i < this.List.Count; i++)
{
if(((PictureTag)this.List).Tag == 0)
{
PictureTag tempTag = new PictureTag();
tempTag.PB = ((System.Windows.Forms.PictureBox) sender);
tempTag.PB.Image = new System.Drawing.Bitmap(@"..\..\nodes.bmp");
tempTag.Tag = 3;
this.List = tempTag;
}
}
}
else if (this.mintCurrentClickType == 1)
{
//we need to search through and remove the old goal node first!

}
PictureTag temp;
int intTemp;
switch (this.mintCurrentClickType)
{
case 0:
//start location
//attempt to change the image to be the startlocation image
//startpoint.bmp maybe?
intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
PictureTag tempTag1 = new PictureTag();
tempTag1.PB = ((System.Windows.Forms.PictureBox) sender);
tempTag1.PB.Image = new System.Drawing.Bitmap(@"..\..\startpoint.bmp");
tempTag1.Tag = 0;
this.List[intTemp] = tempTag1;

//change did NOT take effect, intTemp will be the old value of 3 still
//temp = (PictureTag)this.List[intTemp - 1];
//intTemp = temp.Tag;

break;
case 1:
//goal location
((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\goalpoint.bmp");
intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
temp = (PictureTag)this.List[intTemp];
temp.Tag = 1;
break;
case 2:
//impassable
((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\impassable.bmp");
intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
temp = (PictureTag)this.List[intTemp];
temp.Tag = 2;
break;
case 3:
//passable
((System.Windows.Forms.PictureBox) sender).Image = new System.Drawing.Bitmap(@"..\..\nodes.bmp");
intTemp = (int) ((System.Windows.Forms.PictureBox) sender).Tag;
temp = (PictureTag)this.List[intTemp];
temp.Tag = 3;
break;
}



Note cases 1, 2, 3 have not been rewritten yet as they arent being used for much currently. Basically in the first for loop where I search through to find objects who are set as the start location, I want to both change the tags of those objects as well as the images themselves (only 1 start location is allowed). However, whenever I change it, it does not seem to "stick" with the new image. Would it be better to use a class instead of a struct for this? I basically need to set the .Image property of the picturebox in question during that for loop.

Thanks for any more help you can provide,
Nathan

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!