Access/Set controls on another form - c#

I'm not good at C# at all, I just don't get the logics. But VB I seem to understand alot better since it seems much more logical. Atleast to me.
So I'm run into something which isn't a problem at all in VB, accessing controls on a different form then the one you're currently in.
In VB, if I want to set the state of a button say, in Form2. I just type the following:
Form2.Button1.Text = "Text"
In C# I cannot seem to do this. Why? There must be a pretty good reason for this right?
Edit: So if I have this code, what would it look like to be able to access controls on the other form?
if (!AsioOut.isSupported())
{
SoundProperties.radioButtonAsio.Enabled = false;
SoundProperties.buttonControlPanel.Enabled = false;
SoundProperties.comboBoxAsioDriver.Enabled = false;
}
else
{
// Just fill the comboBox AsioDriver with available driver names
String[] asioDriverNames = AsioOut.GetDriverNames();
foreach (string driverName in asioDriverNames)
{
SoundProperties.comboBoxAsioDriver.Items.Add(driverName);
}
SoundProperties.comboBoxAsioDriver.SelectedIndex = 0;
}
Just tried to add this "SoundProperties SoundProperties = new SoundProperties();
And I do get access to the controls. But do I need to add this bit of code in both parts of this IF-statement? Seems like I do, but still, adding that line to the last part of this code doesn't do anything ang gives me the error message:
"A local variable named 'SoundProperties' cannot be declared in this scope because it would give a different meaning to 'SoundProperties', which is already used in a 'child' scope to denote something else"
Removing the line gives me the following error:
"An object reference is required for the non-static field, method, or property 'NAudio.SoundProperties.comboBoxAsioDriver'"
Here's the code after adding these lines in two places:
if (!AsioOut.isSupported())
{
SoundProperties SoundProperties = new SoundProperties();
SoundProperties.radioButtonAsio.Enabled = false;
SoundProperties.buttonControlPanel.Enabled = false;
SoundProperties.comboBoxAsioDriver.Enabled = false;
}
else
{
// Just fill the comboBox AsioDriver with available driver names
String[] asioDriverNames = AsioOut.GetDriverNames();
foreach (string driverName in asioDriverNames)
{
SoundProperties SoundProperties = new SoundProperties();
SoundProperties.comboBoxAsioDriver.Items.Add(driverName);
}
SoundProperties SoundProperties = new SoundProperties();
SoundProperties.comboBoxAsioDriver.SelectedIndex = 0;
}

Please don't hate me for saying this - but I think this is an issue that I've seen a lot of VB coders run into.
VB allows you to not deal with classes if you don't want to. When in C# you are adding a form to your project - visual studio is just making a class file for you that inherits from "Form".
In C# you have to actually instantiate this into an object and then work with that object. VB allows you to just access the class as if it was already instantiated - but it is actually just making a new "Form2" for you.
In vb if you want to have more than 1 actual "Form2" you would say something like this...
Dim window1 as new Form2()
Dim window2 as new Form2()
window1.Show()
window2.Show()
Now you will have two copies of "Form2" on your screen when you run this.
The difference between VB and C# is you also need to actually make(instantiate) your first copy of Form2 - C# will not do it for you.
Now to answer your question:
Once you have an actual object that has been instantiated - you need to actually make "Button1" public instead of private.
To do this - on Form2 - select Button1 and look at the properties...
Find the "Modifiers" property and set this to public.
You will now be able to see "Button1" on both window1 and window2.
Hope that helped.

You can access another form in c# too.
But you need a reference to the Form instance you want to interact with.
So you have to hold the variable of the 2nd Form instance and access it via this.
E.g.:
From the code of the first form call:
Form2 my2ndForm = new Form2();
my2ndForm.Button1.Text = "Text";
Be sure to set the access modifier of the Button1 to public or internal.

Related

How to use common cs files to transfer variables between forms

I am currently learning basics of c# window forms in visual studios and wondered how I use common cs files. I want to transfer variables from one file to another and I believe an easy way to do this is with a common cs file that just stores the variable and then i just reference it from each of the forms. So my questions are. How do i lay out the code for this common cs file ? if i reference the value in one form and then reference it in the next will it display the value recorded in the previous form or restart from 0. Thanks for any help!
A couple of things. I would remove the basic tag from this post, as that is a different language altogether and might elicit some weird responses.
Your question seems to confuse the cs file with objects and references. So first up, there is nothing magical about a .cs file. It is just a file where c# code is. Often there is a 1-class-per-file convention, but this is just a developer aid, not a requirement. Your data itself will be in an object instance, and that object instance is defined by a class (that happens to be in a cs file).
A simple class definition might look like this
public class Person
{
public int Id
{
get;
set;
}
public string Name
{
get;
set;
}
}
Then your first form can create an instance of a person like this:
Person bob = new Person();
bob.Id = 1;
bob.Name = "Bob Dylan";
(or perhaps you would be assigning values from a control)
You then need to pass your person object instance to your other form. There are several ways that can be done and without understanding your problem domain, I cannot make judgement on which would be most appropriate. But if your second form had a public Person property, you could do something as simple as
Form2 secondForm = new Form2();
secondForm.Person = bob;
secondForm.Show();
or passing via constructor (if that is how it is defined)
Form2 secondform = new Form2(bob);
secondForm.Show();
Now your secondForm instance can access that bob object created above, either via the Person property, or within the constructor depending on how you wrote it.
Whilst this could also be done using static classes or even singletons, I think that until you are completely clear about regular classes, the use of these has the potential to lead you into various "code smells".

Transfer int values between class and form

I'm really confused by now.
I've got a WinForm which holds a large Array
int[,] map = new int[1000, 1000];
I've also got a class containing a method "Draw".
The draw method now needs to get the value of a position in the array in the form. I tried doing the following thing:
In my Form class, I added
public int mapContentAtXY(Point mapPosition)
{
return map[mapPosition.X, mapPosition.Y];
}
Now if I try to perform
myInt = Ingame.mapContentAtXY(myPoint);
//Note: Ingame is the name of my Form
It says
Error 2 'Neu.Ingame' does not contain a definition for 'mapAtPositionXY'
This is really confusing, I just added that definition, it's also set as public. So why the hell doesn't it work?
You will need to pass the instance of the Form to the draw-class by using this when you create or call that instance of the draw-class. Then you can access that method through that form instance.
OR
Store the map not in the form, but in that draw-class. Move the mapContentAtXY method to the draw-class. Use the one instance of the draw-class in your form to update that map.
Your method mapContentAtXY is an instance method.
Change Ingame to this, if you're calling it from within your form instance.
myInt = this.mapContentAtXY(myPoint);
Otherwise use the form instance
myInt = frmInGameInstance.mapContentAtXY(myPoint);

Confusion variable overwritten

I am really confused and hope somebody will be able to help me with the issue I'm having. I want to use the GET command to obtain a value from a new Form, but my code is overwriting the parameters I pass in the constructor and I am not sure why. Not very familiar with C#.
Here the script I use when I click on a specific button. It is a new Form where I pass into parameters a list of interfaces (the parameters will be modified and I do not want to):
private void btn_t1_Click(object sender, EventArgs e) {
InterfaceT1 Formulaire_T1 = new InterfaceT1(**this.Liste_T1**);
if (Formulaire_T1.ShowDialog() == DialogResult.OK) {
//I WOULD WANT TO USE THE GET COMMAND HERE ONLY IF I CLICK 'OK' ON THE FORM
}
Formulaire_T1.Dispose();
}
Here is the constructor of my Form Formulaire_T1 for reference:
public InterfaceT1(List<T1> Liste_T1) {
InitializeComponent();
this.Liste_T1s = new List<T1>(Liste_T1); //suggested, does not change anything
UpdateView(0);
}
The methods I use in Interface_T1 modify the Liste_T1s but why it is also changing Liste_T1 in the main function? I do not return any value. It seems those value are now linked? I know it must be a simple thing but can't figure it out.
The reason your method in InterfaceT1 modifies the list that you pass in is that the constructor stores the reference to the list, rather than copying it. Change the constructor as follows to fix this:
public InterfaceT1(List<T1> Liste_T1) {
InitializeComponent();
this.Liste_T1s = new List<T1>(Liste_T1); // Make a copy
UpdateView(0);
}
Note that this change would make a copy of the list itself, but not its elements: they would remain the same. Adding / deleting elements from the copied list will be OK, but modifying individual elements will be visible in the original. To overcome this problem, change the code as follows:
public InterfaceT1(List<T1> Liste_T1) {
InitializeComponent();
this.Liste_T1s = Liste_T1.Select(t => new T1(t)).ToList();
UpdateView(0);
}
In the code above I am assuming that a new instance of T1 can be created by calling a "copy" constructor that takes another instance of T1, and copies its fields.
List is a reference type. That means that if you pass it as a parameter into another method, you're not passing a copy of the list, you're passing a reference that points back to the original list.

Passing Values Between C# Winforms Working Intermittently

I'm trying to pass values between a few winforms, I've got a total of 6 winforms, that the user will cycle through. I'm passing values between the forms using TextBox and Label Controls.
When I open the Primary winform, then click a button to load the second winform, everything works fine (I can pass values to the First Form). My problem is that once I direct the user to another form and this.Hide(); the current (2nd Winform) then try to use the Third form to pass values to the first, I get the following error:
Object reference not set to an instance of an object.
I'm confused because the control that the should be passing the value is passing the value to the first Form isn't NULL
I'm using the same code to connect all the forms together.
public MainForm MainForm;
Then I'm trying to pass the values like so:
MainForm.textBox1.Text = txt_FileName.Text;
Note: All the TextBox and Label controls that are passing values between the forms are public
Anyone run into this? Or any Ideas?
.
You need to make sure that all your forms are instantiated (through new MyForm1()...). Just declaring a variable of type MainForm won't create a form instance - you'll have to do it. My guess is that one of your forms is not created yet when you try to access a control.
This is yet another reason to not to use public controls (see my comment too), since the lifetime of your controls are tied to the lifetime of your form. It's better to hide controls from public access and send data to the form through data objects - the form will set all those values to its own controls. This also makes validation a lot easier, since a control's value can only be set to values allowed by the form. If you set control values from the outside, you'll have a tough time validating them in all scenarios.
I assume you're trying to use modal forms that work similar to a wizard where users go from one form to the next, following a clear path. If so, you can do something like this:
// Data class to set data in Form2
internal class Form2Data
{
public string Name;
...
}
...
internal class Form2 : Form
{
public static DialogResult ShowDlg ( Form2Data oData )
{
Form2 oFrm = new Form2 ();
oFrm.SetData ( oData );
DialogResult nResult = oFrm.ShowDialog ();
if ( nResult == DialogResult.Ok )
oFrm.GetData ( oData );
return ( nResult );
}
private void SetData ( Form2Data oData )
{
// Set control values here
}
private void GetData ( Form2Data oData )
{
// Read control values here
}
}
...
// You call this as such:
Form2Data oData = new Form2Data ();
oData.Name = "...";
DialogResult nResult = Form2.ShowDlg ( oData );
// after the call, oData should have updated values from Form2
if ( nResult == DialogResult.Ok )
{
// show your next form in a similar pattern - set up data
// call form's static method to pass it and then wait for
// the form to finish and return with updated data.
}
You'd have to use a similar pattern in your other forms, too. This does require more work since you need to set up a different data object for all the forms but this way you can easily do validation before and after the form is shown (in SetData and GetData). It also encapsulates your program better, since controls are not accessible from the outside.
.Net 2.0 and later has a feature for windows forms called the "default instance", where it gives you an instance with the same name as the type. The purpose of this feature is for compatibility with code migrated from old vb6 apps. If you're not migrating from an old vb app, it's usually better to avoid the default instances. They will get you in trouble, such as you have now. Instead, create a variable to hold form instances you construct yourself.
You should pass the value by using the instance value of the form.
for example:
SecondForm secForm2 = new SecondForm();
secForm2.textBox1.Text = txt_FileName.Text
so if you pass the value from SecondForm to ThirdForm:
ThirdForm thiForm = new ThirdForm();
thiForm.textBox1.Text = textBox1.Text

Ways to Dynamically Create Controls in C#

What ways can you dynamically create controls in C#?
This was objects at first but it would have been more precise to say controls. My terminology was messed up. Thanks Joel.
Edit{
Controls that are created during runtime. And are able to be accessed and edited by the program.
Does this help?
}
I like the idea of Dynamic creation and was wondering what ways there were to do this.
Please only one per answer, I would like to see how people rank them.
eg
private Label _lblCLastName = new Label();
private static List<ChildrenPanel> _ListCP = new List<ChildrenPanel>();
public void CreatePanel(Panel Container)
{
// Created Controls
#region Controls
_pnlStudent.Controls.Add(_lblCLastName);
//
// lblCLastName
//
_lblCLastName.AutoSize = true;
_lblCLastName.Location = new System.Drawing.Point(6, 32);
_lblCLastName.Name = "lblCLastName";
_lblCLastName.Size = new System.Drawing.Size(58, 13);
_lblCLastName.TabIndex = 10;
_lblCLastName.Text = "Last Name";
// Adds controls to selected forms panel
Container.Controls.Add(_pnlStudent);
// Creates a list of created panels inside the class
// So I can access user input
ListCP.Add(this);
}
This is a code snippet from something that is close to what I'm talking about. I made another post but didn't quite post the question right. I will be deleting it but atm it is still viewable.
If there are still problems please be constructive I don't mind negitive input as long as it's helpful.
Edit:
I was able to get some answers I was looking for. Thank you to everyone who replied. I will close this when I am able too. If someone else can close it that would be appreciated.
I use the new keyword to dynamically create objects.
Creating GUI objects dynamically can be extremely useful, however, it can also be a nightmare for maintenance.
A good rule of thumb is to limit the amount of GUI object you dynamically create.
One situation where you may actually want to use a dynamically created GUI object is when you don't know the amount or count of objects you need. For example, one label for each row in a result set (even then you may consider a DataGrid or GridView type object).
This works for both WinForms and ASP.NET. Just be sure to document your code correctly.
My advice would be to stick with the Visual Designer for simpler forms and only create and add objects dynamically when it's absolutely necessary.
(FWIW, the code snippet you posted could probably be simplified and/or refactored as it seems to be going in the wrong direction.)
Anonymous Types, C# 3.x
This is fairly dynamic-esque because you don't have to code a class template to get custom objects.
// An anonymous object with two properties: obj.Name and obj.Age
var obj = new { Name = "Joe", Age = 35 };
The compiler will infer the Types of the properties from the initialization values you provide.
The type is not accessible from your source code, but can be seen in the IL. However if you create multiple anonymous objects with the same properties the C# compiler will use the same type for all of them.
// All objects use the same anonymous type
var obj1 = new { Name = "Joe", Age = 1 };
var obj2 = new { Name = "Art", Age = 30 };
var obj3 = new { Name = "Sally", Age = 25 };
// A different (second) anonymous type
var objDifferent = new { Phone = "555-555-1212", Name = "Joe", Age = 1 };
Stipulations There are more, but these are important.
var can only be used at the method scope (as a local variable), not the class scope.
anonymous objects have read-only properties; you cannot assign data back to them.
Activation (for remote objects too)
Use the System.Activator class' overloaded Activator.CreateInstance methods. This gets into the realm of creating objects locally or remotely.
using System;
/* Create instances of a Random number generator (or any class)
* without using the 'new' operator.
*/
Random rand1 = Activator.CreateInstance<Random>();
Random rand2 = (Random)Activator.CreateInstance(typeof(Random));
//etc...
(MSDN Documentation about Remote Objects.)
Assuming you are talking about the creation of dynamic objects:
You'll obviously need a library to support this, unless you want to get into Reflection.Emit yourself - LinFu supported this in version 1:
http://code.google.com/p/linfu/
However, it's a feature that was dropped before version 2 I seem to remember.

Categories