开发者

Using The Controls Of One Form Into Another

I have a application that in one form(Form1) I have many checkBoxes and textBoxes and in Form2 I have only a textBox, but I want to put some contents from the Form开发者_开发问答1 textBoxes and put in the Form2 textBox, like this, but between forms:

textBox1.Text = "Test: " + textBox1 + "\n" + textBox3;

As textBox1 in Form2 and the second textBox1 and textBox3 in Form1, but how I can do this? Thanks.


Depending on how you launch the second form you can either assign a member object in Form2 that references Form1 or if you are using an MDI interface there is a forms collection from which you can retrieve a reference to your Form1.

For example, you could have the following code in your Form2 class:

public partial class Form2 : Form
{
    public Form1 LaunchOrigin { get; set; }
    // and so on

Now you can assign the LaunchOrigin member when you launch Form2. Here is an example:

Form2 newForm = new Form2();
newForm.LaunchOrigin = this;
newForm.Show();

You now have access to Form1 and all its members. Here is a simple example of that:

    private void Form2_Load(object sender, EventArgs e)
    {
        this.Text = LaunchOrigin.Text;
    }

You must remember that controls are declared as private so you won't have direct access to them. You could write a property on Form1 that referenced that control but this is most often a bad idea. For the sake of completeness, however, here is some code that you could use to expose a button on Form1:

public partial class Form1 : Form
{
    public Button theButton;
    public Form1()
    {
        InitializeComponent();
        theButton = button1; // where button1 is what I dragged on
    }
    // and so on

Although what you're asking is relatively easy to accomplish, it puts you on the road to some brittle application structure. Think hard about what it is you're trying to expose between forms, perhaps it deserves to be a distinct type that you can bind to both forms so that once you change the underlying type, you change the representation on both.


There are decent ways to do this and ugly ways to do this... starting with the UGLY:

  1. One of the ugliest would be to pass a reference to Form1 into Form2's constructor and then store that reference as a field for later. It's nasty because it creates a very tight coupling between the two. Changing Form1's interface or behavior affects Form2.

  2. A less ugly, but still hackish, way to do this would be pass the string values from Form1 into Form2's constructor - or some public/internal method on Form2. You still have the dependency around those strings, but at least it's not a complete coupling of Form1 and Form2. It's just an expectation that Form2 will always have a Form1 to feed it these strings.

... fill in some more nasty variations here.

I suggest you look into an app-wide solution that solves this problem and doesn't create the inter-objec dependencies.

Create a messaging interface that works on a lightweight "pub/sub" -- or publish/subscribe -- model. The idea is that you have some components in your app that publish messages (your string values - or something more complex) and other components in your app that subscribe to messages.

When Form 1 starts up, it'd register with the messaging interface "Hey, I'm gonna publish messages of this type" (where the type is some indicator your provide). When Form 2 starts up, it registers with the messaging interface saying "Yo, when someone publishes a message of this type, pass it to me".

Both the publisher and subscriber implement some known interface so that your message handler can talk to them (IPublisher, ISubscriber) -- and receive/send the messages. There's no reason one component can be both a publisher and subscriber, if warranted (essentially treating the objects in a system as "peers" or "colleagues") A few MessageReceived events and some code to manage a collection of publishers/subscribers and you're good to go.

For more detail, check out the Mediator pattern which describes this type of solution in more detail.


I think the answers from David in Dakota, and Jeff Donnici, above, give you all you need, but I'll "flesh out" a trivial example of the broader approach wisely suggested by Jeff that I hope will get you started.

One slight area of disagreement I may have with Jeff's answer is that I believe that any solution to this problem is a variation of "dependency injection" or "dependency management" : even if you go the "most abstract" route and have "publishers" "broadcast" events to "unknown subscribers," but that's just my personal opinion.

Here's a simple example of the type that was helpful for me to understand in the past.

Create a single public static class into which you insert static references to the TextBoxes on all Forms you want to possibly modify (or store the Forms themselves, or whatever) : define public static methods to move data from one form's textbox to the other(s) : a very quick outline : (use of extra long variable names is deliberate, and is for expository purposes only)

using System;
using System.Collections.Generic;
using System.Windows.Forms;

// note : compiles against FrameWork 2.0 and 4.0
// wanted this to work w/o Linq, automatic properties, etc.

namespace MessageHandler
{
    public static class TextBoxMessenger
    {
        // internal List of TextBoxes of interest on all Forms
        internal static List<TextBox> _messageEnabledTBxes = new List<TextBox>();

        // public Property to get/set the collection of TextBoxes of interest
        public static List<TextBox>MessageEnabledTextBoxes
        {
            get { return _messageEnabledTBxes; }

            set { _messageEnabledTBxes = value; }
        }

        // in case you want to register one TextBox at a time
        public static void RegisterTextBoxForMessaging(TextBox theTBx)
        {
            _messageEnabledTBxes.Add(theTBx);
        }

       // send from one specific TBx to another
        public static void setText(TextBox originTBx, TextBox destinationTBx)
       {
           destinationTBx.Text = originTBx.Text;
       }

       // send to a specified list of TextBoxes
        public static void setText(TextBox originTBx, List<TextBox> destinationTBxs)
       {
           foreach (TextBox theTBx in destinationTBxs)
           {
               theTBx.Text = originTBx.Text;
           }
       }

        // set text in all other TextBoxes in MessageEnabledTextBoxes list
        public static void setText(TextBox originTBx)
       {
           foreach (TextBox theTBx in _messageEnabledTBxes)
           {
               // a needless check, since assigning the text of the
               // original TextBox to itself wouldn't "hurt" anything
               // but, imho, much better "practice" to always test
               if (theTBx != originTBx) theTBx.Text = originTBx.Text;
           }
       }
    }
}

So in action how does this work : let's use an example where your Form1 Load event looks like this :

// assume Form2 has a single TextBox on it named 'textBox1'
public Form2 myForm2;

private void Form1_Load(object sender, EventArgs e)
{
    myForm2 = new Form2();
    myForm2.Show();

    // register all the TextBoxes

    // note the redundant use of 'this here : it's a deliberate choice to make
    // the code communicate to a future user/reader/maintainter
    TextBoxMessenger.RegisterTextBoxForMessaging(this.textBox1);
    TextBoxMessenger.RegisterTextBoxForMessaging(this.textBox2);
    TextBoxMessenger.RegisterTextBoxForMessaging((TextBox)myForm2.Controls["textBox1"]);

    // or ...
    //TextBoxMessenger.MessageEnabledTextBoxes = new List<TextBox> 
    //{
    //    this.textBox1, this.textBox2, (TextBox)myForm2.Controls["textBox1"]
    //};
}

And you might test the above like this by putting a button on Form1 :

private void button1_Click(object sender, EventArgs e)
{
    // tests

    // one to all ...
    //TextBoxMessenger.setText(this.textBox1);

    // one to a specific TextBox on another Form
    //TextBoxMessenger.setText(this.textBox1, (TextBox) myForm2.Controls["textBox1"]);

    // one to a List<TextBox>
    TextBoxMessenger.setText(this.textBox1, new List<TextBox> { this.textBox2, (TextBox)myForm2.Controls["textBox1"]});
}

But, note the "ugliness," the "bad code smell," of things like :

(TextBox) myForm2.Controls["textBox1"] // casting is evil ! set a bloody reference !

That's the kind of thing you want to get rid of by moving beyond an example like this into the "arena" that Jeff is, I believe, pointing you to.

Hope this is helpful. In the "long run" the abstraction of message passing into a higher-level, which I believe Jeff prescribes, is, imho, the "royal road" to making code examples much more powerful and more "generalizable" than this example. best,


This question, or variations of it, as been asked many times on StackOverflow. I think it is caused by a misunderstanding about Forms and the Visual Studio designer.

  • how-to-transferring-objects-between-windows-forms-in-c
  • how-to-call-a-form-when-there-are-3-forms-in-a-project-and-data-transfer-between
  • windows-application
  • passing-variables-from-main-form-to-input-form
  • how-to-pass-values-from-one-form-to-another
  • using-the-controls-of-one-form-into-another

A Form is just a standard class that happens to represent a visual window. It is completely reasonable to add your own private fields and public properties to a Form.

So, when you need to pass data between forms or even other parts of your application, simply create a new class (not a Form) that will contain this data and call it something like "ApplicationData". It is entirely up to you what properties and fields this class contains.

Then, for each Form that needs to access the data, add a public get/set property of type ApplicationData. Finally set this property to the ApplicationData object just before Showing each form.

The form can then get data from and update this object in any way it needs to. Because it is a reference type (ie class) all changes to the object are visible to any other form that uses the same object.

Here's rough example. Note, this code is indicative only:

class ApplicationData{
    private string _firstName;
    public string FirstName;
    {
       get { return _firstName;; }
       set { __firstName;=value; }
    }

    private string _lastName;
    public string LastName;
    {
       get { return _lastName; }
       set { __lastName=value; }
    }
}

class ChildForm : Form
{
   private ApplicationData _applicationData=null;

   public ApplicationData AppData
   {
       get { return _applicationData; }
       set { _applicationData=value; }
   }

   void Load_Form(object sender, EventArgs args)
   {
         txtFirstName.Text=AppData.FirstName;
         txtLastName.Text=AppData.LastName;
    }

   void Form_Closing(object sender, EventArgs args)
   {
         AppData.FirstName=txtFirstName.Text;
         AppData.LastName=txtLastName.Text;
    }

}

class MainForm : Form
{
    private ApplicationData _applicationData=new ApplicationData();

    void Button_Click(object sender, EventArgs args)
    {
        ChildForm childForm=new ChildForm ();

        ChildForm.AppData=_applicatonData;

        ChildForm.ShowDialog();

        string fullName=_applicatonData.LastName + " " + _applicatonData.FirstName
    }
}

Some of the answers in other questions such as a publisher / subscriber design are really complete overkill for anything but very complex applications. Keeping it simple is a very important guideline to follow.

Of course it doesn't help that the Visual Studio designer makes it appear that all classes must be visually oriented and created from the toolbox or New Form option. This is simply incorrect.

The design pattern of creating and using an "ApplicationData" class is the first step towards separating your presentation from your content. It's a shame Visual Studio doesn't provide more guidance in this area.


You can even do it by writing a parametrized constructor.

e.g.

namespace SomeNamespace
{
    public partial class Form2 : Form
    {
       string someStr = string.Empty;

        public Form2()
        {
            InitializeComponent();
        }

        public Form2(string params) // Parametrized Constructor
        {
            InitializeComponent();

            someStr  = params
        }

        private void Form2_Load(object sender, EventArgs e)
        {
          Form2TextBox.Text = someStr  ;
        }
    }
}

Now from Form1 call Form2 in this way

Form2 objF2 = new Form2(Form1TextBox1.Text);
objF2.Showdialog();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜