views:

127

answers:

1

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?

+8  A: 

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;
}
Rex M
I'm new to C# can you give a brief example or a link to one. ;-)
Bob Dylan
Thanks for the update. It really helped me understand what you were saying.
Bob Dylan
You can also just use `EventHandler<BooleanValueChangedEventArgs>` instead of making your own delegate type. This also marks it logically as an event handler delegate.
Matthew Scharley