Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to access a control on another form in Windows Forms?

First off, this is a question about a desktop application using Windows Forms, not an ASP.NET question.

I need to interact with controls on other forms. I am trying to access the controls by using, for example, the following...

otherForm.Controls["nameOfControl"].Visible = false;

It doesn't work the way I would expect. I end up with an exception thrown from Main. However, if I make the controls public instead of private, I can then access them directly, as so...

otherForm.nameOfControl.Visible = false;

But is that the best way to do it? Is making the controls public on the other form considered "best practice"? Is there a "better" way to access controls on another form?

Further Explanation:

This is actually a sort of follow-up to another question I asked, Best method for creating a “tree-view preferences dialog” type of interface in C#?. The answer I got was great and solved many, many organizational problems I was having in terms of keeping the UI straight and easy to work with both in run-time and design-time. However, it did bring up this one niggling issue of easily controlling other aspects of the interface.

Basically, I have a root form that instantiates a lot of other forms that sit in a panel on the root form. So, for instance, a radio button on one of those sub-forms might need to alter the state of a status strip icon on the main, root form. In that case, I need the sub-form to talk to the control in the status strip of the parent (root) form. (I hope that makes sense, not in a "who's on first" kind of way.)

like image 422
Dylan Bennett Avatar asked Aug 12 '08 07:08

Dylan Bennett


People also ask

How do you access a form control from another form?

Control c = TheForm("Form1"); Once we have this, we can gain access to ALL the child controls including the children in other container controls on the form. The next method to declare is the one that locates the control to access on the form returned by the TheForm method.


9 Answers

Instead of making the control public, you can create a property that controls its visibility:

public bool ControlIsVisible
{
     get { return control.Visible; }
     set { control.Visible = value; }
}

This creates a proper accessor to that control that won't expose the control's whole set of properties.

like image 185
Jon Limjap Avatar answered Oct 10 '22 16:10

Jon Limjap


I personally would recommend NOT doing it... If it's responding to some sort of action and it needs to change its appearance, I would prefer raising an event and letting it sort itself out...

This kind of coupling between forms always makes me nervous. I always try to keep the UI as light and independent as possible..

I hope this helps. Perhaps you could expand on the scenario if not?

like image 38
Rob Cooper Avatar answered Oct 10 '22 14:10

Rob Cooper


After reading the additional details, I agree with robcthegeek: raise an event. Create a custom EventArgs and pass the neccessary parameters through it.

like image 39
Biri Avatar answered Oct 10 '22 14:10

Biri


Suppose you have two forms, and you want to hide the property of one form via another:

form1 ob = new form1();
ob.Show(this);
this.Enabled= false;

and when you want to get focus back of form1 via form2 button then:

Form1 ob = new Form1();
ob.Visible = true;
this.Close();
like image 38
KARAN Avatar answered Oct 10 '22 15:10

KARAN


I would handle this in the parent form. You can notify the other form that it needs to modify itself through an event.

like image 40
Ed S. Avatar answered Oct 10 '22 16:10

Ed S.


  1. Use an event handler to notify other the form to handle it.
  2. Create a public property on the child form and access it from parent form (with a valid cast).
  3. Create another constructor on the child form for setting form's initialization parameters
  4. Create custom events and/or use (static) classes.

The best practice would be #4 if you are using non-modal forms.

like image 33
user811204 Avatar answered Oct 10 '22 16:10

user811204


You can

  1. Create a public method with needed parameter on child form and call it from parent form (with valid cast)
  2. Create a public property on child form and access it from parent form (with valid cast)
  3. Create another constructor on child form for setting form's initialization parameters
  4. Create custom events and/or use (static) classes

Best practice would be #4 if you are using non-modal forms.

like image 24
Davorin Avatar answered Oct 10 '22 14:10

Davorin


With the property (highlighted) I can get the instance of the MainForm class. But this is a good practice? What do you recommend?

For this I use the property MainFormInstance that runs on the OnLoad method.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LightInfocon.Data.LightBaseProvider;
using System.Configuration;

namespace SINJRectifier
{

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            UserInterface userInterfaceObj = new UserInterface();
            this.chklbBasesList.Items.AddRange(userInterfaceObj.ExtentsList(this.chklbBasesList));
            MainFormInstance.MainFormInstanceSet = this; //Here I get the instance
        }

        private void btnBegin_Click(object sender, EventArgs e)
        {
            Maestro.ConductSymphony();
            ErrorHandling.SetExcecutionIsAllow();
        }
    }

    static class MainFormInstance  //Here I get the instance
    {
        private static MainForm mainFormInstance;

        public static MainForm MainFormInstanceSet { set { mainFormInstance = value; } }

        public static MainForm MainFormInstanceGet { get { return mainFormInstance; } }
    }
}
like image 43
eduardolucioac Avatar answered Oct 10 '22 16:10

eduardolucioac


I agree with using events for this. Since I suspect that you're building an MDI-application (since you create many child forms) and creates windows dynamically and might not know when to unsubscribe from events, I would recommend that you take a look at Weak Event Patterns. Alas, this is only available for framework 3.0 and 3.5 but something similar can be implemented fairly easy with weak references.

However, if you want to find a control in a form based on the form's reference, it's not enough to simply look at the form's control collection. Since every control have it's own control collection, you will have to recurse through them all to find a specific control. You can do this with these two methods (which can be improved).

public static Control FindControl(Form form, string name)
{
    foreach (Control control in form.Controls)
    {
        Control result = FindControl(form, control, name);

        if (result != null)
            return result;
    }

    return null;
}

private static Control FindControl(Form form, Control control, string name)
{
    if (control.Name == name) {
        return control;
    }

    foreach (Control subControl in control.Controls)
    {
        Control result = FindControl(form, subControl, name);

        if (result != null)
            return result;
    }

    return null;
}
like image 24
Patrik Svensson Avatar answered Oct 10 '22 15:10

Patrik Svensson