I search a easy way to access different controls on different forms without any workarounds like I would do this e. g. in Visual Basic 6.
Example:
Form3.pictureBox1.Image = MyImage;
But somehow C# doesn't allow accessing another controls on another forms not even from my own classes. I already changed the "pictureBox1" in Form3 to public and still C# doesn't know this control if I type "Form3.".
What I have to do, to access my controls? I already run Visual Studio with elevated privileges (Microsoft answered me on my question in their support area, that elevated privileges are important for accessing the other forms and the controls on it) but nothing helped me sofar. So I stay now with the one form always in C# and this is not suitable to develop any application. Most applications need multiple forms and therefor should be a easy way to access controls from any context in a class or another form. I don't want to use any "set...or get properties" - I do not know even how! Somewhere I found this specific workaround but I usually have so many controls and labels to access in my application, that this would generate a lot of useless overhead, if each control property needs a get- and set-statement or whatever to write to it.
Maybe someone of you knows a more elegant method to do this in a more simple way even if elevation needed.
In VB6 you could access the default instance of your form by using the Class name, in VB.Net they have continued that behavior. C# doesn't have that behavior, therefore you have to create your own instance of your Form. Otherwise you are trying to use it like a static Class. Even though you do not want to, the best way to do want you want is to expose them through properties it keeps everything encapsulated.
Form3 frm3 = new Form3();
frm3.pictureBox1.Image = Image.FromFile("ImageName");
frm3.Show();
I think I know what is wrong. Form1 and Form3 are in fact classes, so typing Form1.something means that something must be a static member. In order to be able to access the picture, you need an instance of the class.
To explain this better, here is an example:
string a;
string is the class type, and a is an instance of that class.
A method to do this would be to modify the startup code (in windows forms that would be in the Program.cs source file), and save the form in a static class, and access it from there.
This is what Program.cs probably looks like:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
You can see that a new instance of Form1 is being created, that is what the new keyword does. You could also do the following:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f = new Form1();
Application.Run(f);
}
The variable f contains the form being displayed.
I don't really know how your program works, but anyway... to be able to access members of Form3, you need to find the instance. Maybe you have new Form3().Show() somewhere in your code, I don't know exactly... but you need to save that to a variable, and that's how you can access it.
You need to change the modifier property of the objects to public, than you make a instance of the form and call the object you want
Form2 frm2 = new Form2();
frm2.show();
frm2.pictureBox1.Image = "MyImage";
Form3 may refer to the class. You need to use an object to access picturebox1 (or make the field static)
Call me crazy, but I'm the type of guy that likes constructors with parameters (if needed), as opposed to a constructor with no parameters followed by setting properties. My thought process: if the properties are required to actually construct the object, they should go in the constructor. I get two advantages:
I know that when an object is constructed (without error/exception), my object is good.
It helps avoid forgetting to set a certain property.
This mindset is starting to hurt me in regards to form/usercontrol development. Imagine this UserControl:
public partial class MyUserControl : UserControl
{
public MyUserControl(int parm1, string parm2)
{
// We'll do something with the parms, I promise
InitializeComponent();
}
}
At designtime, if I drop this UserControl on a form, I get an Exception:
Failed to create component 'MyUserControl' ...
System.MissingMethodException - No parameterless constructor defined for this object.
It seems like, to me, the only way around that was to add the default constructor (unless someone else knows a way).
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public MyUserControl(int parm1, string parm2)
{
// We'll do something with the parms, I promise
InitializeComponent();
}
}
The whole point of not including the parameterless constructor was to avoid using it. And I can't even use the DesignMode property to do something like:
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
if (this.DesignMode)
{
InitializeComponent();
return;
}
throw new Exception("Use constructor with parameters");
}
}
This doesn't work either:
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
Fine, moving along ...
I have my parameterless constructor, I can drop it on the form, and the form's InitializeComponent will look like this:
private void InitializeComponent()
{
this.myControl1 = new MyControl();
// blah, blah
}
And trust me, because I did it (yes, ignoring the comments Visual Studio generated), I tried messing around and I passed parameters to InitializeComponent so that I could pass them to the constructor of MyControl.
Which leads me to this:
public MyForm()
{
InitializeComponent(); // Constructed once with no parameters
// Constructed a second time, what I really want
this.myControl1 = new MyControl(anInt, aString);
}
For me to use a UserControl with parameters to the constructor, I have to add a second constructor that I don't need? And instantiate the control twice?
I feel like I must be doing something wrong. Thoughts? Opinions? Assurance (hopefully)?
Design decisions made regarding the way Windows Forms works more or less preclude parameterized .ctors for windows forms components. You can use them, but when you do you're stepping outside the generally approved mechanisms. Rather, Windows Forms prefers initialization of values via properties. This is a valid design technique, if not widely used.
This has some benefits, though.
Ease of use for clients. Client code doesn't need to track down a bunch of data, it can immediately create something and just see it with sensible (if uninteresting) results.
Ease of use for the designer. Designer code is clearer and easier to parse in general.
Discourages unusual data dependencies within a single component. (Though even microsoft blew this one with the SplitContainer)
There's a lot of support in forms for working properly with the designer in this technique also. Things like DefaultValueAttribute, DesignerSerializationVisibilityAttribute, and BrowsableAttribute give you the opportunity to provide a rich client experience with minimal effort.
(This isn't the only compromise that was made for client experience in windows forms. Abstract base class components can get hairy too.)
I'd suggest sticking with a parameterless constructor and working within the windows forms design principles. If there are real preconditions that your UserControl must enforce, encapsulate them in another class and then assign an instance of that class to your control via a property. This will give a bit better separation of concern as well.
There are two competing paradigms for designing classes:
Use parameterless constructors and set a bunch of properties afterwards
Use parameterized constructors to set properties in the constructor
The Visual Studio Windows Forms Designer forces you to provide a parameterless constuctor on controls in order to work properly. Actually, it only requires a parameterless constructor in order to instantiate controls, but not to design them (the designer will actually parse the InitializeComponent method while designing a control). This means that you can use the designer to design a form or user control without a parameterless constructor, but you cannot design another control to use that control because the designer will fail to instantiate it.
If you don't intend to programmatically instantiate your controls (i.e. build your UI "by hand"), then don't worry about creating parameterized constructors, since they won't be used. Even if you are going to programmatically instantiate your controls, you may want to provide a parameterless constructor so they can still be used in the designer if need be.
Regardless of which paradigm you use, it is also generally a good idea to put lengthy initialization code in the OnLoad() method, especially since the DesignMode property will work at load time, but not work in the constructor.
I would recommend
public partial class MyUserControl : UserControl
{
private int _parm1;
private string _parm2;
private MyUserControl()
{
InitializeComponent();
}
public MyUserControl(int parm1, string parm2) : this()
{
_parm1 = parm1;
_parm2 = parm2;
}
}
As this way the base constructor is always called first and any references to components are valid.
You could then overload the public ctor if need be, ensuring the control is always instantiated with the correct values.
Either way, you ensure that the parameterless ctor is never called.
I haven't tested this so if it falls over I apologise!
This is unfortunately a design issue that will occur frequently, not just in the control space.
There are often situations where you need to have a parameterless constructor, even though a parameterless constructor is not ideal. For example, many value types, IMO, would be better off without parameterless constructors, but it's impossible to create one that works that way.
In these situations, you have to just design the control/component in the best manner possible. Using reasonable (and preferably the most common) default parameters can help dramatically, since you can at least (hopefully) initialize the component with a good value.
Also, try to design the component in a way that you can change these properties after the component is generated. With Windows Forms components, this is typically fine, since you can pretty much do anything until load time safely.
Again, I agree - this isn't ideal, but it's just something we have to live with and work around.
Well, in short, the designer is the kind of guy that likes parameter-less constructors. So, to the best of my knowledge, if you really want to use parameter based constructors you are probably stuck with working around it one way or the other.
Just do this:
public partial class MyUserControl : UserControl
{
public MyUserControl() : this(-1, string.Empty)
{
}
public MyUserControl(int parm1, string parm2)
{
// We'll do something with the parms, I promise
if (parm1 == -1) { ... }
InitializeComponent();
}
}
Then the 'real' constructor can act accordingly.
Provide a parameterless constructor for the designer and make it private - if you really must do it this way... :-)
EDIT: Well of course this won't work for UserControls. I obviously wasn't thinking clearly. The designer need to execute the code in InitializeComponent() and it's can't work if the constructor is private. Sorry about that. It does work for forms, however.
It's quite a while since the question was asked, but maybe my approach is helpful to somebody.
I personally also prefer to use parameterized Constructors to avoid forgetting to set a certain property.
So instead of using the actual Constructor I simply define a public void PostConstructor where all things are put you would normally put in the Constructor. So the Actual Constructor of the UserControl always contains only InitializeComponent().
This way you don't have to adjust your favourite programming paradigm to VisualStudios needs to run the Designer properly. For this programming schema to work it has to be followed from the very bottom.
In practice this PostConstructionalizm would look somewhat like this:
Let's start with a Control at the bottom of your UserControl call hierarchy.
public partial class ChildControl : UserControl
{
public ChildControl()
{
InitializeComponent();
}
public void PostConstructor(YourParameters[])
{
//setting parameters/fillingdata into form
}
}
So a UserControl containing the ChildControl would look something like that:
public partial class FatherControl : UserControl
{
public FatherControl()
{
InitializeComponent();
}
public void PostConstructor(YourParameters[])
{
ChildControl.PostConstructor(YourParameters[])
//setting parameters/fillingdata into form
}
}
And finally a Form calling one of the User Control simply puts the PostConstructor after InitializeComponent.
public partial class UI : Form
{
public UI(yourParameters[])
{
InitializeComponent();
FatherControl.PostConstructor(yourParameters[]);
}
}
I have a way to work around it.
Create a control A on the form with the parameterless constructor.
Create a control B with parameterized constructor in the form contstructor.
Copy position and size from A to B.
Make A invisible.
Add B to A's parent.
Hope this will help. I just encountered the same question and tried and tested this method.
Code for demonstrate:
public Form1()
{
InitializeComponent();
var holder = PositionHolderAlgorithmComboBox;
holder.Visible = false;
fixedKAlgorithmComboBox = new MiCluster.UI.Controls.AlgorithmComboBox(c => c.CanFixK);
fixedKAlgorithmComboBox.Name = "fixedKAlgorithmComboBox";
fixedKAlgorithmComboBox.Location = holder.Location;
fixedKAlgorithmComboBox.Size = new System.Drawing.Size(holder.Width, holder.Height);
holder.Parent.Controls.Add(fixedKAlgorithmComboBox);
}
holder is Control A, fixedKAlgorithmComboBox is Control B.
An even better and complete solution would be to use reflect to copy the properties one by one from A to B. For the time being, I am busy and I am not doing this. Maybe in the future I will come back with the code. But it is not that hard and I believe you can do it yourself.
I had a similar problem trying to pass an object created in the main Windows Form to a custom UserControl form. What worked for me was adding a property with a default value to the UserControl.Designer.cs and updating it after the InitializeComponent() call in the main form. Having a default value prevents WinForms designer from throwing an "Object reference not set to an instance of an object" error.
Example:
// MainForm.cs
public partial class MainForm : Form
public MainForm()
{
/* code for parsing configuration parameters which producs in <myObj> myConfig */
InitializeComponent();
myUserControl1.config = myConfig; // set the config property to myConfig object
}
//myUserControl.Designer.cs
partial class myUserControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
// define the public property to hold the config and give it a default value
private myObj _config = new myObj(param1, param2, ...);
public myObj config
{
get
{
return _config ;
}
set
{
_config = value;
}
}
#region Component Designer generated code
...
}
Hope this helps!
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.)
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.
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?
The first is not working of course. The controls on a form are private, visible only for that form by design.
To make it all public is also not the best way.
If I would like to expose something to the outer world (which also can mean an another form), I make a public property for it.
public Boolean nameOfControlVisible
{
get { return this.nameOfControl.Visible; }
set { this.nameOfControl.Visible = value; }
}
You can use this public property to hide or show the control or to ask the control current visibility property:
otherForm.nameOfControlVisible = true;
You can also expose full controls, but I think it is too much, you should make visible only the properties you really want to use from outside the current form.
public ControlType nameOfControlP
{
get { return this.nameOfControl; }
set { this.nameOfControl = value; }
}
After reading the additional details, I agree with robcthegeek: raise an event. Create a custom EventArgs and pass the neccessary parameters through it.
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();
I would handle this in the parent form. You can notify the other form that it needs to modify itself through an event.
Use an event handler to notify other the form to handle it.
Create a public property on the child form and access it from parent form (with a valid cast).
Create another constructor on the child form for setting form's initialization parameters
Create custom events and/or use (static) classes.
The best practice would be #4 if you are using non-modal forms.
You can
Create a public method with needed parameter on child form and call it from parent form (with valid cast)
Create a public property on child form and access it from parent form (with valid cast)
Create another constructor on child form for setting form's initialization parameters
Create custom events and/or use (static) classes
Best practice would be #4 if you are using non-modal forms.
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; } }
}
}
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;
}
#Lars, good call on the passing around of Form references, seen it as well myself. Nasty. Never seen them passed them down to the BLL layer though! That doesn't even make sense! That could have seriously impacted performance right? If somewhere in the BLL the reference was kept, the form would stay in memory right?
You have my sympathy! ;)
#Ed, RE your comment about making the Forms UserControls. Dylan has already pointed out that the root form instantiates many child forms, giving the impression of an MDI application (where I am assuming users may want to close various Forms). If I am correct in this assumption, I would think they would be best kept as forms. Certainly open to correction though :)
Do your child forms really need to be Forms? Could they be user controls instead? This way, they could easily raise events for the main form to handle and you could better encapsulate their logic into a single class (at least, logically, they are after all classes already).
#Lars: You are right here. This was something I did in my very beginning days and have not had to do it since, that is why I first suggested raising an event, but my other method would really break any semblance of encapsulation.
#Rob: Yup, sounds about right :). 0/2 on this one...
You should only ever access one view's contents from another if you're creating more complex controls/modules/components. Otherwise, you should do this through the standard Model-View-Controller architecture: You should connect the enabled state of the controls you care about to some model-level predicate that supplies the right information.
For example, if I wanted to enable a Save button only when all required information was entered, I'd have a predicate method that tells when the model objects representing that form are in a state that can be saved. Then in the context where I'm choosing whether to enable the button, I'd just use the result of that method.
This results in a much cleaner separation of business logic from presentation logic, allowing both of them to evolve more independently — letting you create one front-end with multiple back-ends, or multiple front-ends with a single back-end with ease.
It will also be much, much easier to write unit and acceptance tests for, because you can follow a "Trust But Verify" pattern in doing so:
You can write one set of tests that set up your model objects in various ways and check that the "is savable" predicate returns an appropriate result.
You can write a separate set of that check whether your Save button is connected in an appropriate fashion to the "is savable" predicate (whatever that is for your framework, in Cocoa on Mac OS X this would often be through a binding).
As long as both sets of tests are passing, you can be confident that your user interface will work the way you want it to.
This looks like a prime candidate for separating the presentation from the data model. In this case, your preferences should be stored in a separate class that fires event updates whenever a particular property changes (look into INotifyPropertyChanged if your properties are a discrete set, or into a single event if they are more free-form text-based keys).
In your tree view, you'll make the changes to your preferences model, it will then fire an event. In your other forms, you'll subscribe to the changes that you're interested in. In the event handler you use to subscribe to the property changes, you use this.InvokeRequired to see if you are on the right thread to make the UI call, if not, then use this.BeginInvoke to call the desired method to update the form.
Step 1:
string regno, exm, brd, cleg, strm, mrks, inyear;
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
string url;
regno = GridView1.Rows[e.NewEditIndex].Cells[1].Text;
exm = GridView1.Rows[e.NewEditIndex].Cells[2].Text;
brd = GridView1.Rows[e.NewEditIndex].Cells[3].Text;
cleg = GridView1.Rows[e.NewEditIndex].Cells[4].Text;
strm = GridView1.Rows[e.NewEditIndex].Cells[5].Text;
mrks = GridView1.Rows[e.NewEditIndex].Cells[6].Text;
inyear = GridView1.Rows[e.NewEditIndex].Cells[7].Text;
url = "academicinfo.aspx?regno=" + regno + ", " + exm + ", " + brd + ", " +
cleg + ", " + strm + ", " + mrks + ", " + inyear;
Response.Redirect(url);
}
Step 2:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string prm_string = Convert.ToString(Request.QueryString["regno"]);
if (prm_string != null)
{
string[] words = prm_string.Split(',');
txt_regno.Text = words[0];
txt_board.Text = words[2];
txt_college.Text = words[3];
}
}
}
public void Enable_Usercontrol1()
{
UserControl1 usercontrol1 = new UserControl1();
usercontrol1.Enabled = true;
}
/*
Put this Anywhere in your Form and Call it by Enable_Usercontrol1();
Also, Make sure the Usercontrol1 Modifiers is Set to Protected Internal
*/
Change modifier from public to internal. .Net deliberately uses private modifier instead of the public, due to preventing any illegal access to your methods/properties/controls out of your project. In fact, public modifier can accessible wherever, so They are really dangerous. Any body out of your project can access to your methods/properties. But In internal modifier no body (other of your current project) can access to your methods/properties.
Suppose you are creating a project, which has some secret fields. So If these fields being accessible out of your project, it can be dangerous, and against to your initial ideas. As one good recommendation, I can say always use internal modifier instead of public modifier.
But some strange!
I must tell also in VB.Net while our methods/properties are still private, it can be accessible from other forms/class by calling form as a variable with no any problem else.
I don't know why in this programming language behavior is different from C#. As we know both are using same Platform and they claim they are almost same Back end Platform, but as you see, they still behave differently.
But I've solved this problem with two approaches. Either; by using Interface (Which is not a recommend, as you know, Interfaces usually need public modifier, and using a public modifier is not recommend (As I told you above)),
Or
Declare your whole Form in somewhere static class and static variable and there is still internal modifier. Then when you suppose to use that form for showing to users, so pass new Form() construction to that static class/variable. Now It can be Accessible every where as you wish. But you still need some thing more.
You declare your element internal modifier too in Designer File of Form. While your Form is open, it can be accessible everywhere. It can work for you very well.
Consider This Example.
Suppose you want to access to a Form's TextBox.
So the first job is declaration of a static variable in a static class (The reason of static is ease of access without any using new keywork at future).
Second go to designer class of that Form which supposes to be accessed by other Forms. Change its TextBox modifier declaration from private to internal. Don't worry; .Net never change it again to private modifier after your changing.
Third when you want to call that form to open, so pass the new Form Construction to that static variable-->>static class.
Fourth; from any other Forms (wherever in your project) you can access to that form/control while From is open.
Look at code below (We have three object.
1- a static class (in our example we name it A)
2 - Any Form else which wants to open the final Form (has TextBox, in our example FormB).
3 - The real Form which we need to be opened, and we suppose to access to its internal TextBox1 (in our example FormC).
Look at codes below:
internal static class A
{
internal static FormC FrmC;
}
FormB ...
{
'(...)
A.FrmC = new FormC();
'(...)
}
FormC (Designer File) . . .
{
internal System.Windows.Forms.TextBox TextBox1;
}
You can access to that static Variable (here FormC) and its internal control (here Textbox1) wherever and whenever as you wish, while FormC is open.
Any Comment/idea let me know. I glad to hear from you or any body else about this topic more. Honestly I have had some problems regard to this mentioned problem in past. The best way was the second solution that I hope it can work for you. Let me know any new idea/suggestion.