简体   繁体   中英

How do I update a child form from another child form

I have an app that displays a parent (Form 1) and child form (Form 2). On the parent I click a button that calls a second child form (Form 3) as a modal dialog. When I click a button on the dialog form, it updates a tableLayoutPanel on the parent form with text from the dialog form . I need it to also update a tableLayoutPanel on the first child form with the same information.

For the parent and dialog form I use the solution provided here. get value from child from to parent form

First, to answer your question directly , you can access any form with:

Form frmIWantThisForm = System.Windows.Forms.Application.OpenForms.OfType<Form1>().First();

In this example, Form1 is the class name of the form you want. OpenForms is a collection of forms owned by your application. At this point you can access frmIWantThisForm.somePropertyOfTheForm;

For example (after the code above which sets the form I want), I want to populate a string with the background color name of a listbox (for some reason I guess I'm just partial to the background color of that listbox):

    //the 'true' causes a search of children as well:
    Control theControl = frmIWantThisForm.Controls.Find("listBox1",true).First();

    string bgColor = ((ListBox)theControl).BackColor.Name;

Other things you could do are (still simple, but not great options because complexity grows as increasing numbers of forms are talking to each other):

  1. Assign the form to the Tag property of another form so that it has access to the calling form (not very clear). The tag property stores itself as an object, so you'll need to use casting again (like in my example above when I cast the control to a ListBox).
  2. Change the constructor or the dialogs you're calling so that you can pass in another form. This option isn't too bad because it's at least easy to see where the data is going, but complexity still increases as you gain more forms.

Complicated (but better) Answer

However, you're running into an anti-pattern ( scary coding, see Wiki definition ) style that will potentially work in a simple application, but the complexity will grow exponentially. Every form will be referencing every other form and updates to the code will get more and more complex. Imagine making an update and suddenly you break several other pieces of code.

Instead, I recommend you separate the data model from your view / controller code. When you start the application, load data into the controller. When you exit, save back. Perhaps eventually you'll do that more often. Then, when you call a modal dialog, if it's for a piece of the model, pass in that part and have the dialog edit the model based on that data. This way instead of updating controls all across your code, the next dialog you open simply opens and updates it's "view" based upon your model.

internal class MortgageAccounts
{
    internal List<Mortgage> Mortgages = new List<Mortgage>();

    internal decimal ComputeAverageAmount()
    {
        decimal amount = 0;
        //code to compute
        return amount;
    }

    internal void Load()
    {
        //Here you load your data from a save file, 
        //database, or some other method of deserializing.
    }

    internal void Save()
    {
        //Here you save your data (serialize in some way)
    }
}

internal class Mortgage
{
    internal int Id;
    internal decimal Amount;
}

There is additional work you can do to separate your code into conceptual segments, and while this goes far beyond the scope of the question, consider looking into MVC (Model View Controller) tutorials for this application. Code Project has a tutorial to get you started .

From this article, we have the following description of these concepts:

  • The Model - This should take care of all the operations which deal with the data required (in other words the business logic) for the application, which is implementing the MVC model from now onwards will be referred to as by the MVC application. The operations can mean reading, writing data into the database, getting information from remote machines via network, time consuming operations etc. The model should also inform the view about any changes to the data happening in the background.
  • The View - This component takes care of presenting the data to the user. With respect to the context of this article, ie, WinForms, the view class will be tied around with the Form which will be shown to the user.
  • The Controller - This is the center and important component of the MVC pattern as it ties the Model and View together. The Model which manipulates the data and the View which presents the data to the user does not know the existence of each other or they interact directly with each other. It is the controller which acts as an intermediary and ties them together. For example, the controller takes the input from the user such as a button click and informs the model to take appropriate action, if there should be an action that needs to be initiated to manipulate the project data.

Here's some additional reading on tight vs loose coupling. Tight coupling is when objects need to know a lot about each other, and loose coupling is when they do not need to know a lot. The former is hard to maintain and update while the latter is generally preferred.

I am not claiming that what follows is for large scale applications, but for small applications following approach works fine :

RitVerplaatsenForm dlg = new RitVerplaatsenForm(focusCell.Date.AddDays(rit<7?rit-1:0));
dlg.Text += string.Format("({0} records)",rows.Length);
if (dlg.ShowDialog() == DialogResult.OK)
{
     DateTime date = dlg.Date;
     //do stuff with the obtained date from the dialog
}

the Date property of the dialog class is simple and straight forward :

public DateTime Date
{
    get
    {
        return this.monthCalendar1.SelectionStart;
    }
    set
    {
        monthCalendar1.SelectionStart = value;
    }
}

For not too complex GUI's and not too complex applications this works fine. Of course some applications start simple and grow and grow and grow. But in my opinion you don't have to start with the big guns right from the start.

The code in question is a copy paste and then deleted some overhead from a real application so you can see some more stuff going on. This app creates some crystal reports in .NET and the emphasis is really on the reports and not as such on the dialogs I use to drive the user towards the reports.

  • On line 1 I am instantiating the form and passing information via the constructor of the form. The fact that this is a focusCell.... you have to make abstraction from that, you can pass anything that way to your dialog if you need to.
  • The second line, I am updating the title of the dialog. It's pragmatic, it could also have been done in the constructor of the dialog. In Sw there are a millions ways to achieve something.
  • line 3 show the dialog
  • line 5 take results from the dialog.

The get, set makes a property of the monthCalender, public via a different name to the user of the dialog. You can also make the monthCalendar public, but that is a more pragmatic approach. The point is that i want to obtain a date. Where the date actually comes from is of no concern of the user of the dialog nor that there is a monthcalender on the dialog.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM