Wednesday, April 2, 2008

... to change the properties of controls on another form.

You have two options for exposing properties of hosted controls from a form. The intuitive option is simply to make the control field public:

class Form1 : Form {

public Label labelInForm1; // Don't!
...

}

Now, when Form2 needs access to the control in Form1, it can access it directly, like so:

class Form2 : Form {

Form1 form1; // Needs to be set from somewhere
void setLabelInForm1_Click(object sender, EventArgs e){
// Set a control's property on Form1
form1.labelInForm1.Text = textForLabelInForm1.Text;

}
...
}


For this to work, the Form2 object needs to have access to the Form1 object. Form2 would normally get access to an object by exposing a property so that whoever has access to Form1 can share that access with Form2:

class Form2 : Form {
...
Form1 form1; // Set by the property
public Form1 Form1 {
get { return form1; }
set { form1 = value; }
}
}

For example, maybe Form1 creates Form2 and sets the Form1 property as it does so:

void Form1_Load(object sender, EventArgs e) {
Form2 form2 = new Form2();
form2.Form1 = this; // Allow Form2 to access Form1 public members
form2.Show();
}

Now, Form2 has access to all public members of Form1, including any controls exposed as public fields. However, there’s a problem. The problem is that if Form1 decides to make the Label control editable, it may well need to change the Label to a TextBox. Now, because the field has been exposed to the world, whenever Form1’s implementation needs to change, it has to update the client code as well, or the compiler will complain. Instead of exposing fields directly, it’s almost always better to expose public properties whose implementation can change, but whose signature remains the same:


class Form1 : Form {
...
private Label labelInForm1; // Fields should be private
public string LabelText {
get { return labelInForm1.Text; }
set { labelInForm1.Text = value; }
}
}

Once you use a property, the access code is actually simpler, since Form2 is accessing Form1 and not worrying about the internal implementation details:

void setLabelInForm1_Click(object sender, EventArgs e) {
// Set a property on Form1 (w/o worrying about the implementation)
form1.LabelText = textForLabelInForm1.Text;
}

Now, when Form1 needs to change its implementation from a Label control to a TextBox control, it can do so:

class Form1 : Form {
...
private TextBox textboxInForm1; // Not exposed to client
public string LabelText { // Client need not change
get { return textboxInForm1.Text; }
set { textboxInForm1.Text = value; }
}
}

By keeping fields private, internal implementation details can change w/o affecting clients. This is encapsulation and abstraction, both core principles of object-orientation.

All the bests...

0 comments: