0

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

Community
  • 1
  • 1
  • Pass form 2 to form 3. – deathismyfriend Jul 02 '15 at 17:32
  • possible duplicate of [Send values from one form to another form](http://stackoverflow.com/questions/1559770/send-values-from-one-form-to-another-form) and [Passing a value from one form to another form](http://stackoverflow.com/questions/7886544/passing-a-value-from-one-form-to-another-form) – C-Pound Guru Jul 02 '15 at 18:40
  • Since Form1 is the parent of both Form2 and Form3 it should have the references of both Forms, create a property on Form2 that Form1 can pass the data the Form3 has passed to it already. – Mark Hall Jul 02 '15 at 19:03

2 Answers2

3

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, i.e., 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.

Palu Macil
  • 1,708
  • 1
  • 24
  • 34
  • 1
    Thanks! The app I'm working on is stupidly simple (and I'm not a seasoned coder, just had an idea for a friend and wanted to code it out for him.) But giving me both the simple way to do it, and the right way is a huge help. – slingeronline Jul 02 '15 at 18:22
  • @slingeronline Great! And welcome to Stack Overflow! If you want, you can mark my answer as the accepted answer and I get a reputation bonus. Once you have 15 reputation, you can also upvote any question you find helpful. This is a great place to find help, and you can choose to only read or you can choose to get involved to increasing degrees as you gain reputation. – Palu Macil Jul 02 '15 at 18:28
  • Already did mark yours as an answer. Although I'm having an issue trying to access the tableLayoutPanel on that form. (Apparently I'm missing something...) – slingeronline Jul 02 '15 at 18:36
  • Actually none of the 2 proposed answers are what the op is looking for. The first is extremely bad, and the second is only ok for large applications and even then subject to different opinions. The answer is actually in the first comment of the post. pass references to the original forms, or, handle the dialogresult of the modal dialog and then access the information from the dialog while it is no longer visible by accessing the different form elements. This is perfectly fine for small applications that don't need complex architecting. – Philip Stuyck Jul 02 '15 at 18:42
  • Philip, how would I pass the reference? I already use this to get the parent form from the dialog window. ` public partial class AddDialog : Form { LaneManager m_parent; public AddDialog(LaneManager frm1) { InitializeComponent(); m_parent = frm1; } } ` – slingeronline Jul 02 '15 at 18:50
  • @slingeronline I added some information on passing references (using tag property or in the constructor of the new form) and I added an example showing you how to find a control in the controls collection now that you have located a form. – Palu Macil Jul 02 '15 at 18:52
  • @PhilipStuyck I actually answered the question directly first and talked about MVC (in a simplified way) second. I just changed some formatting to make it more obvious, so that will help, I think. Please review and let me know if I should modify the formatting further to clarify this better. – Palu Macil Jul 02 '15 at 18:53
  • @PaluMacil nothing what you say is wrong. But it is simply not applicable for this user he is not a professional like you are. Using openforms to get to the open dialogs is not the best advice. Neither is using the tag property, but you explain that yourself too. My only remark is that you need to put yourself a bit in the shoes of the op and not your own or your coworkers who might come to your for advice. My answer would be different depending on the skill of the one who asks. – Philip Stuyck Jul 02 '15 at 19:00
  • Assume I have the requisite coding skill of an absolute beginner. @PaluMacil I have tried to do what you said using Control displayTable = displayForm.Controls.Find("tableLayoutPanel2", true).First(); but when I try to update the control like this displayTable.RowCount = displayTable.RowCount + 1; it gives me an error on the "Row Count" property. Is there a way to pass what type of control it should be so that it accepts properties for a tableLayoutPanel? – slingeronline Jul 02 '15 at 19:27
  • @slingeronline I think you're looking for casting. That's how I turned a Control into a ListBox with ((ListBox)theControl). To cast, you need to put the type in parentheses before the original variable. Use this method when you're sure it'll succeed. You'll use ((TableLayoutPanel)displayTable). The outermost parens are necessary if you're chaining other methods afterwards. If you need more information on adding rows, http://www.codeproject.com/Questions/410746/how-to-add-new-row-in-tablelayoutpanel-at-runtime is a nice tutorial, but I think all you needed was the casting. – Palu Macil Jul 02 '15 at 19:54
  • @PaluMacil, perfect! Thanks! Casting is exactly what I was looking for. – slingeronline Jul 03 '15 at 22:25
2

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.

Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
  • This is actually a pretty decent middle ground approach. While I answered directly / verbatim what was asked and then explained something more complex, this is a decent way to do it simply. I'd recommend showing more code around the property to make it clear that it's a property of RitVerplaatsenForm, and explaining the get/set as well as focusCell wouldn't hurt for helping the OP use this suggestion. – Palu Macil Jul 02 '15 at 19:10
  • @PaluMacil point taken and updated the answer with your comments. – Philip Stuyck Jul 02 '15 at 19:20
  • +1 for the edit and overall answer. I just realized I actually have the same type of example handy at the moment, but I wrote it in VB.net, so I won't confuse things by adding that. – Palu Macil Jul 02 '15 at 19:26