views:

2272

answers:

3

I have a Parent Form that holds a "HUD" with First Name, Last Name, etc. One of the child forms is a Search Form. When the user selects a member from the results that are displayed in a DataGrid I want the pertinent information to fill in the HUD. I created a HUD class with variables for each value and a method called UpdateHUD(). I am unsure how to get this working. I have a reference to the Search Form of the Parent form containing the HUD, like so:

public frmWWCModuleHost _frmWWCModuleHost;

This is the code I use to embed forms. I am not using MDI.

 public static void ShowFormInContainerControl(Control ctl, Form frm)
    {
        frm.TopLevel = false;
        frm.FormBorderStyle = FormBorderStyle.None;
        frm.Dock = DockStyle.Fill;
        frm.Visible = true;
        ctl.Controls.Add(frm);
    }

Here is the code I am running on Cell Click on the Search Form. This is from before I tried implementing the HUD class.

private void dgvSearchResults_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        _frmWWCModuleHost = new frmWWCModuleHost();
        _frmWWCModuleHost.tbxHUD_LastName.Text = dgvSearchResults.CurrentRow.Cells[1].FormattedValue.ToString();
        _frmWWCModuleHost.tbxHUD_LastName.Invalidate();
        _frmWWCModuleHost.FormPaint();
    }

Thanks in advance!

~ Patrick


EDIT


dgvSearchResults_CellContentClick is now current. When I step through this code it is getting the correct Value here but it is never updating the actual HUD.


EDIT 2


Is my problem that I am declaring a NEW frmWWCModuleHost instead of passing a ref to the existing? I am still pretty weak in my understanding of this.


EDIT 3


I have "solved" this by doing the following: On the Parent Form where I declare the Child Form I pass this as a param. Then in the constructor of the child form I added _frmWWCModuleHost = m_parent; I have a UpdateHUD() method on my Parent form and I call it from the _CellClick event on the child.

Now to rephrase my question; Is there anything glaringly wrong with doing it this way?

+3  A: 

When the child form search completes, raise a "SearchCompleted" event. Then anything (including the parent form) can subscribe to that event and retrieve the details.

See the following NotepadCode for an example:

class ParentForm
{
    private readonly ChildForm childForm;

    public ParentForm()
    {
        InitializeComponent();

        childForm = new ChildForm();

        childForm.SearchCompleted += childForm_SearchCompleted;
    }

    private void childForm_SearchCompleted(object sender, SearchCompletedEventArgs e)
    {
        // Update the display
        lblName.Text = e.DataToDisplay;
    }
}

class ChildForm
{
    public event EventHandler<SearchCompletedEventArgs> SearchCompleted;

    private void Search(string query)
    {
        // Do the searching

        OnSearchCompleted(new SearchCompletedEventArgs([arg values]));
    }

    public void OnSearchCompleted(SearchCompletedEventArgs args)
    {
        if (SearchCompleted != null)
        {
            SearchCompleted(this, args);
        }
    }
}
Neil Barnwell
I must be dense but how would I do this on cell or row click? I can't do it on SearchComplete because there will be more then one returned.
Refracted Paladin
You call OnSearchCompleted from the cell/row click, having taken the data out of the currently selected row/cell.
Neil Barnwell
Douh! I will give this a try.
Refracted Paladin
I, obviously, am not up to this yet. I am getting errors with this approach. Maybe I am taking your code to literal. I assume where it states arg values I should put the values to pass.
Refracted Paladin
Yes. Maybe you'd just pass the DataRow or Domain Model object that is linked to the selected row in the grid. That way, the thing observing the event can do what they like with it.
Neil Barnwell
+2  A: 

In .NET, Forms are objects like everything else, so you should think of the problem in those terms.

With that, the child form will need access to the parent form. You can provide that by passing the parent form reference to the child form through the constructor, a method, or a field/property (although the constructor makes the most sense).

Then, you can change the values in parent form from the child.

HOWEVER I would say this isn't the best idea. Rather, the child should expose an event indicating that the data changed (as well as the mechanism to get that data) and then the parent should subscribe to that event and update itself with the data when it is fired.

casperOne
I thought I was doing this in the above example or am I mistaken?
Refracted Paladin
Okay, I think this is NOW what I am doing. In the Constructor. Could you elaborate as to why I shouldn't do it this way? Thanks!
Refracted Paladin
@Mr_Mom: Well, it's about separation of concerns. With your approach, the child form has intimate knowledge of the parent, and that's the only relationship supported. With an event, the child doesn't care who is responding to the data, and that makes the class more reusable.
casperOne
+1  A: 

Sometimes in situations like this I'll create a delegate that matches the signature of the method I want to call in the parent class (I think that would be UpdateHUD in your case), and then pass an instance of that delegate (i.e. a reference to UpdateHUD) to the child form (the search form in this case). When the child form is finished accepting input, it invokes the delegate using the data collected on the form.

So, say UpdateHUD is a method in the parent form that looks something like this.

private void UpdateHUD(string firstName, string lastName) {
    //...
}

You would create a delegate with the same signature, like this.

public delegate void HUDUpdateHandler(string firstName, string lastName);

Then you would add a HUDUpdateHandler parameter to the constructor of the child form and store it in a private field (for example, this.handler = handler). When your child form is ready to send its data back, you would invoke the child form's private field (this.handler.Invoke(firstNameTextBox.Text, lastNameTextBox.Text), for example). That will invoke UpdateHUD in your parent class using the values from the child class, and you won't have to expose anything.

I find this approach simpler to implement than raising and catching events, and it allows you to keep the internals of your parent class internal.

John M Gant
Do I create the Delegate in the Parent or Child Form? Thanks!
Refracted Paladin
You can create it anywhere as long as it's in scope for both parent and child. I usually create it in the same code file as the parent, but I don't nest it within the parent class itself. It really doesn't matter, though, as long as it's in scope.
John M Gant