Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to change properties in a parent form from a child form?

I was just wondering if I'm doing this the correct way. I have 2 forms a parent form and a child form (options dialog). To change a property in my parent form from my child form I use code like this:

// Create an array of all rich textboxes on the parent form.
var controls = this.Owner.Controls.OfType<RichTextBox>();

foreach (var item in controls) {
    if (chkDetectUrls.Checked)
        ((RichTextBox)item).DetectUrls = true;
    else
        ((RichTextBox)item).DetectUrls = false;
}

I only have one RichTextBox on my form. It seems silly to have to loop through a array of 1 control. Is this the correct way to do it or is there an easier way?

like image 710
Bob Dylan Avatar asked Aug 15 '09 23:08

Bob Dylan


1 Answers

It's not appropriate to change properties in a parent form at all. Instead, your child form should raise an event which the parent form listens for, and changes its own value accordingly.

Manipulating the parent form from the child creates a two-way coupling - the parent form owns the child, but the child also has intimate knowledge and dependency on the parent form. Bubbling is the established solution to this, as it allows information to flow upwards ('bubbling') while avoiding any strict coupling.

Here is the most basic example of eventing. It does not include passing specific information in the event (which is what you may need) but covers the concept.

In your child form:

//the event
public event EventHandler SomethingHappened;

protected virtual void OnSomethingHappened(EventArgs e)
{
    //make sure we have someone subscribed to our event before we try to raise it
    if(this.SomethingHappened != null)
    {
        this.SomethingHappened(this, e);
    }
}

private void SomeMethod()
{
    //call our method when we want to raise the event
    OnSomethingHappened(EventArgs.Empty);
}

And in your parent form:

void OnInit(EventArgs e)
{
    //attach a handler to the event
    myChildControl.SomethingHappened += new EventHandler(HandleSomethingHappened);
}

//gets called when the control raises its event
private void HandleSomethingHappened(object sender, EventArgs e)
{
    //set the properties here
}

As I said above, you probably need to pass some specific information in your event. There's a few ways we can do this, but the simplest one is to create your own EventArgs class and your own delegate. It looks like you need to specify whether some value is set to true or false, so let's use that:

public class BooleanValueChangedEventArgs : EventArgs
{
    public bool NewValue;

    public BooleanValueChangedEventArgs(bool value)
        : base()
    {
        this.NewValue = value;
    }
}

public delegate void HandleBooleanValueChange(object sender, BooleanValueChangedEventArgs e);

We can change our event to use these new signatures:

public event HandleBooleanValueChange SomethingHappened;

And we pass our custom EventArgs object:

bool checked = //get value
OnSomethingHappened(new BooleanValueChangedEventArgs(checked));

And we change our event handling in the parent accordingly:

void OnInit(EventArgs e)
{
    //attach a handler to the event
    myChildControl.SomethingHappened += new HandleBooleanValueChange(HandleSomethingHappened);
}

//gets called when the control raises its event
private void HandleSomethingHappened(object sender, BooleanValueChangedEventArgs e)
{
    //set the properties here
    bool value = e.NewValue;
}
like image 70
Rex M Avatar answered Sep 24 '22 21:09

Rex M