Why does my attempt at this fail?
I made this public on Form1.Designer.cs
public System.Windows.Forms.ProgressBar progressBar1;
and I can check it shares Form
public partial class Form3 : Form
and then tried this to update increment on another form "form3"
Form1.progressBar1.Increment(10);
I made this somewhat weird try because I saw simple "classname.variablename" for using data from another form working...
PS. If I am lucky enough to understand your generous answers... I think I will be able to bite off more of your further suggestions like "how about try inheritance" or "make instance for this"... :)
The problem with your attempt is that you are trying to access an instance member through the class name, rather than an actual instance reference.
When you create the Form3 instance, you need to pass it the reference to the Form1 instance, preferably via the constructor. E.g.:
partial class Form3 : Form
{
private readonly Form1 _form1;
public Form3(Form1 form1)
{
_form1 = form1;
}
}
Then you can access the ProgressBar instance like this:
_form1.progressBar1.Increment(10);
Note, however, that making the progressBar1 field public really isn't the right thing to do. It gives callers more access than they need, when your classes should be designed to give only the minimum access required.
It would be better to keep the field private and do something like this:
partial class Form1 : Form
{
public void IncrementProgress(int i)
{
progressBar1.Increment(i);
}
}
Then you'd access it like this :
_form1.IncrementProgress(10);
(still passing the Form1 instance to the constructor of Form3, of course).
Edit:
It's worth mentioning that I agree with the general sentiment expressed in the question comments that a better approach is for Form3 to expose some kind of progress event, and for Form1 to subscribe to that, rather than requiring Form3 to specifically know about the Form1 class at all.
The above code examples address the specific question, but if you are interested in a better design, it would look something like this:
partial class Form3 : Form
{
public event EventHandler IncrementProgress;
void SomeMethodWhereProgressHappens()
{
// ... make some progress
// Then raise the progress event
EventHandler handler = IncrementProgress;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
// ... then make some more progress, etc.
}
}
and in your Form1 class:
partial class Form1 : Form
{
void SomeMethodThatShowsForm3()
{
Form3 form3 = new Form3();
form3.IncrementProgress += (sender, e) => progressBar1.Increment(10);
form3.Show();
}
}
Note that in this approach, the Form3 class doesn't have any code at all that depends on the Form3 class specifically, and Form1 does not need to expose the ProgressBar instance in any way, not even via some proxy method.
Finally note that the reason an event is appropriate in this scenario is because of the callback nature of the operation. There are other scenarios where some caller, e.g. the code instantiating the class object itself, simply wants to set certain properties that map to control properties. In this case, the delegation/proxy approach I showed as the initial solution is still appropriate. It's a good technique to learn and use when it applies.
You need to create a public property on Form1:
public ProgressBar MyProgressBar
{
get
{
return progressBar1;
}
}
Then you can access it from Form3:
form1.MyProgressBar.Increment(10);
You'll probably need to create a property in Form3 also:
public Form MainForm
{
get; set;
}
So when you open Form3, you'll do this:
Form3 form3 = new Form3();
form3.Show();
form3.MainForm = this;
Related
I am trying to pass a value from textbox1 of my form3 to the ListBox of my form1.
Here is the code for form3 :
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1(textBox1.Text);
f1.Show();
}
And here it is what is wrote in form1 :
public partial class Form1 : Form
{
public Form1(string something)
{
InitializeComponent();
listBox1.Items.Add(something);
}
The error is:
Form1' does not contain a constructor that takes 0 arguments.
Thank you for your help in advance!
You should take a look at the line where this error comes from (). I would wildly guess that there is a line in your code that uses a parameterless constructor like :
Form1 foo = new Form1();
or even if it is the starting form:
Application.Run(new Form1());
You should overload the constructor and not simply change it, since it is auto-generated it might highly probably be that it is already used in this form somewhere. Just add a second constructor:
public partial class Form1 : Form
{
public Form()
{
InitializeComponent();
}
public Form(string something)
{
InitializeComponent();
listBox.Items.Add(something);
}
}
Edit:
trying to pass a value from textbox1 of my form3 to the listbox of my form1
This is a slightly different problem then your error suggested in the first place. A different approach would be advisable. The constructor is useless, because it will create a different instance/object which is not the same that you see on the screen! In other words, all Elements will loose their values!
One of many solutions can be to create a method which would add items to the ListBox in the class Form1:
public void AddItemToListBox(string s)
{
listBox.Items.Add(something);
}
and pass the instance of the current window Form1 via Form2 to Form3. Have a variable in each class(Form2 and Form3) of type Form1
public Form1 temp_form1;
and pass the instance of the starting window Form1 to the variable temp_form1 when you call Form2 in the class Form1:
Form2 form2 = new Form2();
form2.temp_form1 = this; // "this" stands for the instance of the current object
and the same hold for Form3 when you call it in the class Form2:
Form3 form3 = new Form3();
form3.temp_form1 = this.temp_form1;
At the end just call the method to update the listbox in the class Form3:
temp_form1.AddItemToListBox("yourstring");
Do not delete the default constructor of your form, leave it there and add another one with your custom parameters under it instead.
public Form1()
{
//Default constructor
InitializeComponent();
}
public Form1(string something)
{
//Your custom constructor
InitializeComponent();
listBox1.Items.Add(something);
}
I have a class for global variables, like this:
internal static class GlobalVariables
{
public static PortBrowserForm open;
}
The PortBrowserForm class is a Windows Form class that has a timer and want to use its properties, like this (in another form):
// In that other form...
GlobalVariables.open.timer1.Enabled = true;
But I cannot call it. I can only call a function from GlobalVariables.open variable (which is a form already). Please help.
GlobalVariables.open.timer1.Enabled = true;
To make the above code work you need to make the timer1's modifier public or atleast internal. But... Don't do that, never expose fields public because you don't get control over who is doing what.
Instead create a method which does the job for you.
class PortBrowserForm : Form
{
public void SetTimerEnabled(bool enabled)
{
timer1.Enabled = enabled;
}
}
Then use
GlobalVariables.open.SetTimerEnabled(true);
Quick and Dirty
Check PortBrowserForm .designer.cs/vb file there you can find the declaration of all controls of the form. Change its access level to public from there and you can access that from any form just by creating forms instance.
Update:
To access one forms control in another you need to pass the first form in the constructor of another. Suppose we have two forms
Form1.cs
Form2.cs
In some event of form1 , call form2.
frm1Btn_Click()
{
form2 f2 = new form2(this);
f2.Show();
}
Create a overloaded constructor in form2 with Form1 as parameter and pickup form1 and its all controls.
I am making an app for a friend, and need the user to "input" a value, and return it to the MySQL code I have. this way, what displays will change.
My problem is this: When I do "Form1 newForm = new Form1();" (this is called in DB_Application)
I get a stackoverflow error.
public partial class Form1
{
private DBApplication DB_App = new DBApplication();
private void InitializeComponent()
{
this.orderID.Text = "";
this.orderID.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.EnterKey);
.....
this.phoneNumber.Text = DB_App.phone_number;
.....
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void EnterKey(object o, KeyPressEventArgs e)
{
if(e.KeyChar == (char)Keys.Enter)
{
//converts the "orderID.Text" to an integer value.
if (!int.TryParse(orderID.Text, out newCurrentID))
MessageBox.Show("not a number");
e.Handled = true;
}
}
}
public class DBApplication : DBInfo
{
Form1 newForm = new Form1(); // infinite loop
public DBApplication()
{
OrderID();
}
private string OrderID ()
{
.... //reads the MySQL info, and outputs the value from the database.
}
}
After the User presses "enter" I need the value to go back into "DB_Application" so the MySQL command may receive it, and output a new value.
As mentioned in your comments and by others, the stack overflow is coming from your DBApplication instantiating a Form1, which in turn instantiates a DBApplication, which in turn instantiates a Form1 and so on.
Rewrite your DBApplication to take a Form1 as part of its constructor rather than instantiating its own, this will avoid the infinite recursion and likely this is want you want since the DBApplication will properly reference the open form:
public class DBApplication
{
private Form1 Form;
public DBApplication(Form1 form)
{
this.Form = form;
}
...
}
public partial class Form1 : Form
{
private DBApplication DB_App;
public Form1()
{
DB_App = new DBApplication(this);
InitializeComponent();
}
...
}
Depending on the rest of your application, you may want to instantiate DB_App after the call to InitializeComponent(). (On second look at your code, it's pretty obvious that the DB_App needs to be assigned before calling InitializeComponent().)
Also, since we don't know the full design/usage of DBApplication, perhaps you need to flip it around where the DBApplication instantiates a Form1, and the Form1 has the existing DBApplication passed in instead.
There are generally better ways of doing this (say via dependency injection), but this should be a simple way without completely breaking the architecture you have now.
If you indeed call new Form1() from DBApplication the StackOverflow comes from new DBApplication() in Form1 (it's an instance variable). How to solve the problem depends on your application logic.
I am building a small windows form application in C#. Within the form code I define a public struct with a ToString method that must build part of its output from items in comboBoxes on the same form. This doesn't sound like it should be difficult
public partial class Form1 : Form
{
public struct OrderLineItem
{
string someString;
int index;
string ToString()
{return someString + ActiveForm.sizeComboBox.Items[index].ToString();}
}
}
It complains that it cannot find a definition for sizeComboBox. If I explicitly use the name of the form, it says an object reference is required for the static field...
I'm not quite sure what it means by that. Using this.sizeComboBox refers to the struct, not the form. Using just sizeComboBox, again, an object reference is required.
The struct knows about its containing class type, but it doesn't know about any particular instance of that type, unless you tell it. For example, you can create a constructor that takes a Form1 object, and it can save a reference to that form in a member variable.
public partial class Form1 : Form
{
public struct OrderLineItem
{
string someString;
int index;
Form1 parentForm;
internal OrderLineItem(Form1 parentForm)
{
this = new OrderLineItem();
this.parentForm = parentForm;
}
string ToString()
{
if (parentForm == null)
return string.Empty;
else
return someString + parentForm.sizeComboBox.Items[index].ToString();
}
}
}
That said, this is a seriously questionable design.
The tiered structure of this application appears to be upside-down. The order-line-item objects should exist at a lower level than the user interface layer. The UI can sometimes see the business objects (order, order-line-item, etc.), but the business objects should not know anything about the UI.
If you can invert this structure, it will make the code much cleaner.
Suppose the other form is Form2 you can cast ActiveForm to Form2:
var form2 = ActiveForm as Form2;
if (form2 != null) // form2 == null if ActiveForm is not of type Form2.
{
form2.sizeComboBox...
}
Edit:
Two notes.
Instead of getting ActiveForm it is better store form2 in a member variable in form1 when form2 is created.
You should encapsulate the getting of combobox values behind a property in Form2, like SelectedFooValue.
public partial class Form1 : Form
{
internal static Form1 ActiveForm { get; set; }
public Form1()
{
InitializeComponent();
ActiveForm = this;
}
public struct OrderLineItem
{
public override string ToString()
{
return ActiveForm.sizeComboBox.Items[index].ToString();
}
}
However note that this is not the correct approach. Maybe you can post what you are trying to accomplish and we can help?
You need to cast ActiveForm to Form1.
Something like this I think (don't have VS open now to check):
return someString + ((Form1)ActiveForm).sizeComboBox.Items[index].ToString();
However, this is generally not a good way of going about things, you shouldn't make your methods in your classes and structs refer directory to controls since then you tie them together to closely. Try to send the data in to the struct instead or create a method on the form to return the data in some way.
I need to call "panel.invalidate" outside my form (WINform) class also I need to change some other controls as well, I read similar question here, and tried what they said, but it didn't work and I wasn't convinced at all.
The answer I read was about exposing a public method like this:
public void EnableButton(bool enable)
{
this.myButton.Enabled = enable;
}
Also I made a static instance in the other file
static Form1 myForm = new Form1();
Any useful suggestions??
The problem is the "myForm" reference. It is a reference to an instance of Form1 that isn't visible and doesn't match the one that the user is looking at. It can't be a match, you created a new one.
Whatever class needs to update the form must have a constructor that takes a Form1 reference. You can create the class object in your Form1 constructor or Load event, pass "this". Using Application.OpenForms[0] is another way to get the reference, one you should not use.
Are you updating from the same thread? Otherwise you might need to use Invoke.
Here's a nice short article about how to do that:
http://blogs.msdn.com/csharpfaq/archive/2004/03/17/91685.aspx
Control.Invalidate() is a public method, but the control itself is most likely not public. You will have to expose the call to Control.Invalidate() through a public facing method in your form or by marking the control in question as public.
public class MyForm : Form {
private TextBox tbxName = new TextBox();
public InvalidateTextBox() {
tbxName.Invalidate();
}
}
OR
public class MyForm : Form {
public TextBox tbxName = new TextBox();
}
public class SomeOtherClass {
public void InvalidateTextBox(MyForm form) {
form.tbxName.Invalidate();
}
}