public void ItemGot()
{
number = number + 1; //Increment by 1
quantity.Text = ("x" + number); //Overwrite Text
quantity.Refresh(); //Updates the text
}
Hello, I have this code above. When this method runs, the text of a label I set up earlier should change the text to the one i set below. However, its not doing it. Furthermore, by setting breakpoints in Visual Studio, I have determined that:
The method is being called,
Number is being incremented properly.
There should be NO reason why this not working, because the program is recognizing that number is increasing by one. My friend said a similar question here. Still no help, and now that code is outdated. Please help!
EDIT: how I added the quantity label
First, I initialized it in the constructor: public Label quantity;
Then I did this: quantity = new Label();
Lastly, in another method, I gave the quantity the following properties:
quantity.Size = new Size(24, 24);
quantity.Text = ("x" + number);
quantity.Left = 48;
Controls.Add(quantity);
number is also in the constructor and is set to 0.
EDIT 2 : I'll Post my whole method
public InventoryScreen()
{
btnItems = new Button();
quantity = new Label();
//call the methods for spawning the buttons
ButtonGenItems(cNumber, btnItems, quantity);
InitializeComponent();
}
public void InventoryScreen_Load(object sender, EventArgs e)
{
}
#region ButtonGenItems Method
public void ButtonGenItems(int cNumber, Button btnItems,Label quantity)
{
int xPos = 126;
int yPos = 25;
for (int n = 0; n < 1; n++)
{
btnItems.Tag = n;
btnItems.Size = new Size(48, 52); //Button size X and Y
btnItems.BackColor = Color.CornflowerBlue;
quantity.Size = new Size(24, 24);
quantity.Text = ("x" + number);
if (yPos > 60) // Five Buttons in one column
{
yPos = 25; //spawn position Y
xPos = xPos + btnItems.Width + 10; //spacing X
}
btnItems.Left = xPos; //Start Button spawn at the Left side
btnItems.Top = yPos; //Start spawn at the top side
quantity.Left = 48;
quantity.Top = 60;
yPos = yPos + btnItems.Height + 10;
btnItems.Text = "Use";
Controls.Add(btnItems); //place Buttons
Controls.Add(quantity);
// the Event of click Button
//btnItems.Click += new System.EventHandler(ItemUse); //to be implimented
}
}
#endregion
public void ItemGot()
{
//*Interestingly, the program recognizes that 'number' is increasing by 1, but label won't update the text
//Furthermore, pressing the actual button will trigger the text update, but simulating a buttonclick WONT DO ANYTHING
Console.WriteLine("Text should now increment by 1"); //Debugging to test method
number = number + 1; //Increment by 1
quantity.Text = ("x" + number); //Overwrite Text
}
}
2.5 This is how the method is being called. This method is located in another class
public void Update(Vector2 pos)
{
this.position = pos; //get char position
Inv = new InventoryScreen(); //create instance of object
charRange = new Rectangle((int)position.X, (int)position.Y, 64, 57); //create rectangle
//Intersection Code, If the character intersects with the item while the item is showing, run below
if (alive && charRange.Intersects(itemRect))
{
alive = false; //stop showing the item
Inv.ItemGot(); //Call the ItemGot class, which adds the item to the inventory screen
}
}
As I understand you have already open/showed form(instance of class InventoryScreen) with your label when you calling Update method, But...
Inside of method Update you creating a new instance of InventoryScreen, and calling function ItemGot with this new instance of form.
I think you need to pass reference of your current instance of InventoryScreen in method Update, then use that reference for calling ItemGot method
public void Update(Vector2 pos, InventoryScreen invscreen)
{
this.position = pos;
charRange = new Rectangle((int)position.X, (int)position.Y, 64, 57);
if (alive && charRange.Intersects(itemRect))
{
alive = false;
invscreen.ItemGot();
}
}
Related
Hi my problem is i want to add buttons to array size: 65
and there is a problem here's my code:
Button[] buttonsa = new Button[65];
for (int d = 0; d <= buttonsa.Length; d++)
{
try
{
buttonsa[d].Text = "Runned!";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
My all code for creating button to scene:
private void CreateButton(int xh, int yh, int width, int height)
{
Button newButton = new Button();
if (width < 100)
{
newButton.Width = 100;
}
else
{
newButton.Width = width;
}
if (height < 30)
{
newButton.Height = 30;
}
else
{
newButton.Height = height;
}
newButton.Text = "button" + btnIndex;
newButton.ForeColor = Color.FromArgb(35,35,35,0);
newButton.Name = "btn" + btnIndex.ToString();
newButton.AccessibleName = btnIndex.ToString() + "|FlatStyle=" + FlatStyle.System.ToString() + "|Pussy=sussy";
newButton.ContextMenuStrip = btnContext;
newButton.Tag = "button" + btnIndex;
newButton.FlatStyle = FlatStyle.Flat;
newButton.BackColor = Color.White;
newButton.Location = new Point(xh, yh);
newButton.Click += newButton_Click2;
buttonsa[btnIndex] = newButton;
btnIndex++;
int x = rand.Next(10, pic.ClientSize.Width - newButton.Width);
int y = rand.Next(10, pic.ClientSize.Height - newButton.Height);
newButton.Location = new Point(xh, yh);
pic.Controls.Add(newButton);
buttonsInScene.Add(newButton);
this.CenterToScreen();
g.Clear(Color.FromArgb(35, 35, 35, 0));
pic.Refresh();
}
Im working on big project if anyone can help me Thanks alot! <3
I tried a few times to fix it i needed to get all my buttons in form and set text to "Runned!"
You can use the recursive method for getting all buttons on the form. You don't need to add all buttons to the array type, anytime you can use your function and gets all buttons on the form and on the child controls.
But, if you want, you can write easy code inside the function, for adding buttons to an array or to the List.
Example:
private void ButtonList (Control cont)
{
foreach (Control c in cont.Controls)
{
if (c is Button)
{
(c as Button).Text = "Hello";
(c as Button).Visible = true;
// and etc...
/*************** example adding button object to list *************
declare listButton property of type List<Button> on your code
listButton.Add((c as Button));
*******************************************************************/
}
if (c.Controls.Count > 0)
{
ButtonList(c);
}
}
}
And you can use this function calling that
ButtonList (MainForm);
I'm developing a theatre reservation software. I'm using Windows Forms, the seats is represented by a 2-dimensioned array. And I draw the buttons as following:
public void DrawSeats()
{
// pnl_seats is a Panel
pnl_seats.Controls.Clear();
// Here I store all Buttons instance, to later add all buttons in one call (AddRange) to the Panel
var btns = new List<Control>();
// Suspend layout to avoid undesired Redraw/Refresh
this.SuspendLayout();
for (int y = 0; y < _seatZone.VerticalSize; y++)
{
for (int x = 0; x < _seatZone.HorizontalSize; x++)
{
// Check if this seat exists
if (IsException(x, y))
continue;
// Construct the button with desired properties. SeatSize is a common value for every button
var btn = new Button
{
Width = SeatSize,
Height = SeatSize,
Left = (x * SeatSize),
Top = (y * SeatSize),
Text = y + "" + x,
Tag = y + ";" + x, // When the button clicks, the purpose of this is to remember which seat this button is.
Font = new Font(new FontFamily("Microsoft Sans Serif"), 6.5f)
};
// Check if it is already reserved
if (ExistsReservation(x, y))
btn.Enabled = false;
else
btn.Click += btn_seat_Click; // Add click event
btns.Add(btn);
}
}
// As said before, add all buttons in one call
pnl_seats.Controls.AddRange(btns.ToArray());
// Resume the layout
this.ResumeLayout();
}
But already with a seat zone of 20 by 20 (400 buttons), it spent almost 1 minute to draw it, and in debug I checked that the lack of performance, is the instantiation of the buttons.
There is a way to make it faster? Perhaps disable all events during the instatiation or another lightweight Control that has the Click event too?
UPDATE:
lbl was a test, the correct is btn, sorry.
UPDATE 2:
Here is the IsException and ExistsReservations methods:
private bool IsException(int x, int y)
{
for (var k = 0; k < _seatsExceptions.GetLength(0); k++)
if (_seatsExceptions[k, 0] == x && _seatsExceptions[k, 1] == y)
return true;
return false;
}
private bool ExistsReservation(int x, int y)
{
for (var k = 0; k < _seatsReservations.GetLength(0); k++)
if (_seatsReservations[k, 0] == x && _seatsReservations[k, 1] == y)
return true;
return false;
}
Suppose that you change your arrays for reservations and exclusions to
public List<string> _seatsExceptions = new List<string>();
public List<string> _seatsReservations = new List<string>();
you add your exclusions and reservations in the list with something like
_seatsExceptions.Add("1;10");
_seatsExceptions.Add("4;19");
_seatsReservations.Add("2;5");
_seatsReservations.Add("5;5");
your checks for exclusions and reservations could be changed to
bool IsException(int x, int y)
{
string key = x.ToString() + ";" + y.ToString();
return _seatsExceptions.Contains(key);
}
bool ExistsReservation(int x, int y)
{
string key = x.ToString() + ";" + y.ToString();
return _seatsReservations.Contains(key);
}
of course I don't know if you are able to make this change or not in your program. However consider to change the search on your array sooner or later.
EDIT I have made some tests, and while a virtual grid of 20x20 buttons works acceptably well (31 millisecs 0.775ms on average), a bigger one slows down noticeably. At 200x50 the timing jumps to 10 seconds (1,0675 on average). So perhaps a different approach is needed. A bound DataGridView could be a simpler solution and will be relatively easy to handle.
I also won't use such a myriad of controls to implement such a thing. Instead you should maybe create your own UserControl, which will paint all the seats as images and reacts on a click event.
To make it a little easier for you i created such a simple UserControl, that will draw all the seats and reacts on a mouse click for changing of the state. Here it is:
public enum SeatState
{
Empty,
Selected,
Full
}
public partial class Seats : UserControl
{
private int _Columns;
private int _Rows;
private List<List<SeatState>> _SeatStates;
public Seats()
{
InitializeComponent();
this.DoubleBuffered = true;
_SeatStates = new List<List<SeatState>>();
_Rows = 40;
_Columns = 40;
ReDimSeatStates();
MouseUp += OnMouseUp;
Paint += OnPaint;
Resize += OnResize;
}
public int Columns
{
get { return _Columns; }
set
{
_Columns = Math.Min(1, value);
ReDimSeatStates();
}
}
public int Rows
{
get { return _Rows; }
set
{
_Rows = Math.Min(1, value);
ReDimSeatStates();
}
}
private Image GetPictureForSeat(int row, int column)
{
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
return Properties.Resources.emptySeat;
case SeatState.Selected:
return Properties.Resources.choosenSeat;
default:
case SeatState.Full:
return Properties.Resources.fullSeat;
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
var row = (int)(e.X / widthPerSeat);
var column = (int)(e.Y / heightPerSeat);
var seatState = _SeatStates[row][column];
switch (seatState)
{
case SeatState.Empty:
_SeatStates[row][column] = SeatState.Selected;
break;
case SeatState.Selected:
_SeatStates[row][column] = SeatState.Empty;
break;
}
Invalidate();
}
private void OnPaint(object sender, PaintEventArgs e)
{
var heightPerSeat = Height / (float)Rows;
var widthPerSeat = Width / (float)Columns;
e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
for (int row = 0; row < Rows; row++)
{
for (int column = 0; column < Columns; column++)
{
var seatImage = GetPictureForSeat(row, column);
e.Graphics.DrawImage(seatImage, row * widthPerSeat, column * heightPerSeat, widthPerSeat, heightPerSeat);
}
}
}
private void OnResize(object sender, System.EventArgs e)
{
Invalidate();
}
private void ReDimSeatStates()
{
while (_SeatStates.Count < Rows)
_SeatStates.Add(new List<SeatState>());
if (_SeatStates.First().Count < Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count < Columns)
columnList.Add(SeatState.Empty);
while (_SeatStates.Count > Rows)
_SeatStates.RemoveAt(_SeatStates.Count - 1);
if (_SeatStates.First().Count > Columns)
foreach (var columnList in _SeatStates)
while (columnList.Count > Columns)
columnList.RemoveAt(columnList.Count - 1);
}
}
This will currently draw forty rows and columns (so there are 800 seats) and you can click on each seat to change its state.
Here are the images i used:
EmtpySeat:
ChoosenSeat:
FullSeat:
If you anchor this control and resize it or you click on a seat to change its state there can be some minor lacking for the repainting if you further increase the number of rows or columns, but that is still somewhere far below one second. If this still hurts you, you have to improve the paint method and maybe check the ClipRectangle property of the paint event and only paint the really needed parts, but that's another story.
Rather than using actual button controls, just draw the image of the seats then when the user clicks on a seat translate the mouse X,Y coordinates to determine which seat was clicked. This will be more efficient. Of course, the drawback is that you have to write the method to translate x,y coordinates to a seat, but that really isn't that difficult.
EDIT; it has been pointed out to me this will not work in Windows Forms!
Well, you are Sequentially working through it.
if one iteration costs 1 sec, the full process will take 400*1 in time.
Perhaps you should try and make a collection of your objects, and process it 'parallel'.
try the .Net framework (4 and above) 'parallel foreach' method:
http://msdn.microsoft.com/en-s/library/system.threading.tasks.parallel.foreach(v=vs.110).aspx
edit: so, if you have a list buttonnames, you can say
buttonNames.ForEach(x=>CreateButton(x));
while your CreateButton() method is as following:
private Button CreateButton(string nameOfButton) { Button b = new
Button(); b.Text = nameOfButton; //do whatever you want...
return b; }
How to get value of checkboxes (and the textbox upon change in text) in real time with form particulars that are all generated via code?
This following code produces a form upon button press, the form has checkboxes and a richtextbox. Ideally I want any interaction to have an effect, so if I paste in a grid of ones and zeros the checkboxes update, and once a checkbox gets click, the corresponding one or zero in the textarea will update (So that I can then copy the grid (matrix) out and into another program.
I know how to get the events using the visual studio GUI maker, but not from a programmatically created form like this.
private void begin_button_Click(object sender, EventArgs e)
{
// Build the child form
Form check_box = new Form();
check_box.FormBorderStyle = FormBorderStyle.FixedSingle;
// Get the values from the textboxes
int height = Convert.ToInt16(this.height_input.Text);
int width = Convert.ToInt16(this.width_input.Text);
// Set the dimensions of the form
check_box.Width = width * 15 + 40;
check_box.Height = ( height * 15 + 40 ) * 3;
// Build checkboxes for the checkbox form
CheckBox[] chk;
chk = new CheckBox[height * width];
int count = 0;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
chk[count] = new CheckBox();
chk[count].Name = count.ToString();
chk[count].Width = 15; // because the default is 100px for text
chk[count].Height = 15;
chk[count].Location = new Point(j * 15, i * 15);
chk[count].CheckedChanged += new EventHandler(this.CheckedChanged);
check_box.Controls.Add(chk[count]);
count += 1;
//Console.WriteLine(" i: " + i + " j: " + j + " Count: " + count);
}
}
RichTextBox output_area;
output_area = new RichTextBox();
output_area.Location = new Point(chk[0].Location.X, chk[count-1].Location.Y + 30);
check_box.Controls.Add(output_area);
output_area.Text = "hello world\n1,1,1,1,1,1,1,1,1\n0,0,0,0,0,1,0,1\nthese ones and zeros are meant to update in real time!";
output_area.Width = check_box.Width - 40;
output_area.Height = check_box.Height / 2;
// Run the form
check_box.ShowDialog();
}
EDIT:
I have added the event handler and it's working, however I can't access the checkbox form, only the main form.
private void CheckedChanged(object sender, EventArgs e)
{
//throw new NotImplementedException();
CheckBox x = (CheckBox)sender;
Console.WriteLine(x);
Console.WriteLine(x.Name.ToString());
}
Have a look at the .Designer file that the form designer generates for you!
Anyway, in your loop, try something like this:
chk[count].CheckedChanged += MyFancyHandler;
And the handler itself will look just like a normal handler:
private void MyFancyHandler( object sender, EventArgs e )
{
// ...
}
Also notice that the sender argument there will contain a reference to whichever checkbox/control the event refers to.
Below code updates matrix text in the rich text box when check box check state changed.
RichTextBox output_area;
CheckBox[] chk;
Size MatrixSize;
private void begin_button_Click()
{
// Build the child form
Form check_box = new Form();
check_box.FormBorderStyle = FormBorderStyle.FixedSingle;
check_box.StartPosition = FormStartPosition.CenterScreen;
// Get the values from the textboxes
int height = Convert.ToInt16("10");
int width = Convert.ToInt16("7");
MatrixSize = new Size(width, height);
// Set the dimensions of the form
check_box.Width = width * 15 + 40;
check_box.Height = (height * 15 + 40) * 3;
// Build checkboxes for the checkbox form
chk = new CheckBox[height * width];
int count = 0;
for (int i = 1; i <= height; i++)
{
for (int j = 1; j <= width; j++)
{
chk[count] = new CheckBox();
chk[count].Name = count.ToString();
chk[count].Width = 15; // because the default is 100px for text
chk[count].Height = 15;
chk[count].Location = new Point(j * 15, i * 15);
check_box.Controls.Add(chk[count]);
chk[count].CheckedChanged += new EventHandler(CheckBox1_CheckedChanged);
count += 1;
//Console.WriteLine(" i: " + i + " j: " + j + " Count: " + count);
}
}
output_area = new RichTextBox();
output_area.Location = new Point(chk[0].Location.X, chk[count - 1].Location.Y + 30);
check_box.Controls.Add(output_area);
output_area.Text = "hello world\n1,1,1,1,1,1,1,1,1\n0,0,0,0,0,1,0,1\nthese ones and zeros are meant to update in real time!";
output_area.Width = check_box.Width - 40;
output_area.Height = check_box.Height / 2;
// Run the form
check_box.ShowDialog();
}
private void CheckBox1_CheckedChanged(Object sender, EventArgs e)
{
CheckBox c = (CheckBox)sender;
Debug.WriteLine(c.Name);
StringBuilder sb = new StringBuilder();
int count = 0;
for (int i = 1; i <= MatrixSize.Height; i++)
{
for (int j = 1; j <= MatrixSize.Width; j++)
{
if (chk[count].Checked)
{
sb.Append("1,");
}
else
{
sb.Append("0,");
}
count += 1;
}
sb.Append("\r\n");
}
output_area.Text = sb.ToString();
}
I'm fairly new to OOP and am not sure how I would go about implementing something in my program. My program is pretty much similar to whack a mole and has an array of picture boxes with an image in and an image of a monster moves randomly between the picture boxes with a time interval applied or will move to a new random picture box whenever the user clicks on the monster in time. I have created an monster and a player sub class to try and add some OOP concepts to the program but am not sure how to implement what I want. Basically I have a label for score on my main form and a score variable in my animal class with a value. I want to be able to add the value of score from the label on my form when the user clicks on the picture box with the mole in and take away the value of score from the label when they don't click on it in time.
Here is my code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
PictureBox[] boxes;
int initialscore = 0;
int time = 0;
int randPos;
public Form1()
{
InitializeComponent();
}
private void boxes_MouseClick(object sender, MouseEventArgs e)
{
PictureBox pb2 = new PictureBox() { Image = Image.FromFile("sword2.png") };
this.Cursor = new Cursor(((Bitmap)pb2.Image).GetHicon());
for (int x = 0; x < 27; x++)
{
if (sender.Equals(boxes[x]))
{
Image grass = Image.FromFile("swamp.png");
PictureBox temp = (PictureBox)sender;
temp.Image = grass;
}
if (sender.Equals(boxes[x]))
{
PictureBox pb = (PictureBox)sender;
if (pb.Tag == "skeleton.png")
initialscore++;
}
}
label1.Text = " Score: " +initialscore.ToString();
}
public void timer1_Tick(object sender, EventArgs e)
{
boxes[randPos].Image = Image.FromFile("swamp.png");
boxes[randPos].Tag = "swamp.png";
Random r = new Random();
randPos=r.Next(0, 27);
boxes[randPos].Image = Image.FromFile("skeleton.png");
boxes[randPos].Tag = "skeleton.png";
}
private void Form1_Load(object sender, EventArgs e)
{
boxes = new PictureBox[27];
int top = 100;
int left = 100;
for (int x = 0; x < 27; x++)
{
boxes[x] = new PictureBox();
boxes[x].Image = Image.FromFile("swamp.png");
boxes[x].Height = 100;
boxes[x].Width = 100;
if (x % 9 == 0)
{
top += 120;
left = 120;
}
else
left += 120;
boxes[x].Top = top;
boxes[x].Left = (50 + left);
Controls.Add(boxes[x]);
this.boxes[x].MouseClick += new
System.Windows.Forms.MouseEventHandler(this.boxes_MouseClick);
label1.Text = " Score: " + initialscore.ToString();
label2.Text = " Time: " + time.ToString();
}
}
}
namespace WindowsFormsApplication1
{
class Monster
{
protected int score;
public Monster()
{
score = 10;
}
}
}
namespace WindowsFormsApplication1
{
class Player:Monster
{
}
}
Nothing has been added in the player class yet.
What do I need to add or change to be able to get the initial score to change by the value of the score in the monster class when clicking on the moving image?
To unify the updating/incrementing and visualization of the score you should extract that to a method:
public void incrementScore(int increment)
{
initialscore += increment;
label1.Text = " Score: " + initialscore.ToString();
}
in the Form1_Load you call this like:
incrementScore(0);
for the click on the monster you have different possibilities:
if all the monsters have the same points you can make it a static variable in the Monster class.
protected static int Score = 10;
which allows you to use it in the boxes_MouseClick event handler:
incrementScore(Monster.Score);
in case all monsters have another value you have to hold the score variable as an instance variable, identify somehow the instance of the monster class you clicked on and increment with this value
I need some help changing the position of an item on another form dynamically.
I am trying to make a skin design tool for an app I'm making and need to know how to process an event from one form to another.
What I would like to do is set some initial variables in some text boxes and hit a preview button this will open a new form and display the skin.
Then I would like to be able to fine tune the positions of the items by clicking buttons on the 1st form.
I am ok with getting the initial positions on form2 from form1 I do it like this.
Form1 form1 = (Form1)Application.OpenForms["Form1"];
int xPos = 0;
int yPos = 0;
if (int.TryParse(form1.textBox1.Text, out xPos))
if (int.TryParse(form1.textBox2.Text, out yPos))
button1.Location = new Point(xPos,yPos);
And my button code in form1 to increase the position is this.
Form2 PreviewWindow = new Form2();
int newText;
int xPos = 0;
int yPos = 0;
if (int.TryParse(textBox1.Text, out xPos))
if (int.TryParse(textBox2.Text, out yPos))
PreviewWindow.button1.Location = new Point(xPos + 1 , yPos);
newText = xPos + 1;
textBox1.Text = newText.ToString();
But now I'm stuck on updating the event to the 2nd form.Would any of you mind giving me some pointers?
The second code doesn't work because you're creating a new instance of Form2. Try this instead
Form2 PreviewWindow = (Form2)Application.OpenForms["Form2"];
int newText;
int xPos = 0;
int yPos = 0;
if (int.TryParse(textBox1.Text, out xPos))
if (int.TryParse(textBox2.Text, out yPos))
PreviewWindow.button1.Location = new Point(xPos + 1 , yPos);
newText = xPos + 1;
textBox1.Text = newText.ToString();
Your best bet here will be to expose properties and/or methods in the form you wish to control. For a TextBox position, for instance:
//Property option:
public Int32 TextBox1XPos
{
get
{
return textBox1.Location.X;
}
set
{
textBox1.Location.X = value;
}
}
public Int32 TextBox1YPos
{
get
{
return textBox1.Location.Y;
}
set
{
textBox1.Location.Y = value;
}
}
//Method option
public void MoveTextBox1(Int32 XPos, Int32 YPos)
{
textBox1.Location = new Point(XPos, YPos);
}
You can implement these for any property on the form. This gives you an indirect way of communicating with the form and doesn't require setting all controls to Public exposure.