Sending Array List Between Forms [closed] - c#

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
Currently I am sending one Array List from form2 to form 1 and it works fine.
Form1 form2 = new Form1(this, SampleArrayList); //pass form reference and an arraylist
form2.Show();
this.Hide();
And on form1 I associate SampleArrayList with local Array List.
Form2 formParent;
ArrayList SampleArrayList;
public MainForm(Form2 par, ArrayList _SampleArrayList)
{
InitializeComponent();
this.formParent = par;
this.SampleArrayList = _SampleArrayList;
}
However I want to avoid creating new instance of Form1
form2 = new Form1(this, SampleArrayList);
I want to send Array List to currently running instance of Form1. What would be best way to do this. Thank you

Quote of OP in the comments above:
Form1 is created first, clicking add button creates Form2. Clicking
submit button hides Form2 and creates new instance of Form1 along with
old instance which I didn't want to dispose of. I want to click submit
button and go back to running instance of Form1.
That's really a larger problem then. Here's a nice solution that I like.
public partial class Form1 : Form
{
private string dataFromThisForm; //can be whatever
private void button1_Click(object sender, EventArgs e)
{
Form2 otherForm = new Form2();
//pass some data to other form
otherForm.SomeData = dataFromThisForm;
this.Hide();
otherForm.Show();
//when the other form is closed
otherForm.FormClosed += (sender2, e2) =>
{
this.Show();
string newData = otherForm.NewData;
};
//when the other form is hidden.
otherForm.VisibleChanged += (sender2, e2) =>
{
this.Show();
string newData = otherForm.NewData;
};
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
//Use SomeData to populate controls.
}
public string SomeData { get; set; } //data passed in from other form
public string NewData { get; private set; } //data to expose to other form
private void button1_Click(object sender, EventArgs e)
{
NewData = "SomeDataToPassToForm1";
//this.Close();
this.Hide();
}
}
A few notes:
You're passing around an ArrayList, rather than strings as I did in
this example. An ArrayList is a mutable reference type, whereas
string is immutable. This means that you can just modify the
ArrayList passed to Form2, and those changes will be reflected in
the variable in Form1 since they both point to the same underlying
ArrayList. I left this code in here as it covers the general case
though.
You say that you hide Form2 when you click the submit button.
Normally in this design you would close it since it won't be needed
anymore. If you really don't plan to use it again I suggest closing
it. If you really do plan to show that form again then just hiding
it is fine.
If you close Form2 on submit it will fire the FormClosing event, if
you just hide it it will fire the Visible event. You should probably
remove one of those two event handlers in my code depending on
whether you actually close it or hide it. If you sometimes do one and
sometimes the other then feel free to leave both. You won't actually
harm anything (other than confusing people) if you leave both in even
if you only use one.

A static class that would act as a communications platform within your application could solve the problem or both forms could be owned by the same object.

I would add a method to Form1 that accepts the Array list.
Something like:
public void Setup(ArrayList SampleArrayList)
{
// Do what you need here...
}
Then you could call this method from inside your constructor (to keep the constructor the same), and call Setup when you need to change the list the Form is using.
Your code above would be like this:
// If you needed a new instance of Form1, it wouldn't change
Form1 form2 = new Form1(this, SampleArrayList); //pass form reference and an arraylist
form2.Show();
this.Hide();
// If you already had an instance in the form2 variable
form2.Setup(SampleArrayList);
No matter what, if you are using .NET 2.0 or greater, I would recommend using a generic List to store list data instead of ArrayList.

You can write a static property in the Form1 class if you don't need to create a instance of it. For example:
private static ArrayList _SampleArrayList;
public static ArrayList SampleArrayList
{
get { return _SampleArrayList; }
set { _SampleArrayList = value; }
}
and when you want update the ArrayList write simply:
Form1.SampleArrayList = SampleArrayList;
PS: I reccomend you use a List<> instead of an ArrayList.
If you don't know the type instead of ArrayList use List<object> else List<T>.
EDIT:
If form1 and form2 are both an istance of the same class you only have to make the ArrayList static.

Related

C# Get variable from popup form that will be closed

I have a form populated with an array of userControls that is created from the main form. I need to be able to access this array of userControls from the main form once the popup has been closed when a button is pressed. If I fill out the forms and then press the button on the main form without closing the popup, the values are present. However, if I close the popup window, the values are not present. My main form is static so I can use it's variables in other forms.
Code for the popup:
public ScanChannel[] controls;
public ScanListSetup()
{
InitializeComponent();
int numChans = Convert.ToInt32(Form1.Self.numChannels.Text);
controls = new ScanChannel[numChans];
// Create the UserControls
for(int i = 0; i < numChans; i++)
{
controls[i] = new ScanChannel();
}
// Place them
for (int i = 0; i < numChans; i++)
{
controls[i].Location = new Point(13,(35+25*(i)));
this.Controls.Add(controls[i]);
}
doneButton.Location = new Point(82, 35 + (25 * (numChans + 1)));
this.Size =new Size(280, 110 + (25 * (numChans + 1)));
}
private void doneButton_Click(object sender, EventArgs e)
{
Form1.Self.setChannelsToScan(controls);
}
I need to access the controls array in the main form. The code for the main form is as follows:
private ScanChannel[] channelsToScan;
private void configureScanListButton_Click(object sender, EventArgs e)
{
var form = new ScanListSetup();
form.Show(this);
scanListConfigured = true;
this.channelsToScan = new ScanChannel[Convert.ToInt32(numChannels.Text)];
}
public void setChannelsToScan(ScanChannel[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
this.channelsToScan[i] = arr[i];
}
}
private void scanButton_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Test: " + this.channelsToScan[0].getDeviceType());
// THIS PRINTS AN EMPTY STRING
}
So, the Debug writeLine outputs the correct value if I click the scanButton while the popup form is still open. However, if I close the form after clicking the doneButton on the popup form, the Debug writeLine outputs Test: with nothing else.
Any help with this would be greatly appreciated. Thanks.
Your problem essentially boils down to sending data from a secondary window (your 'pop-up' window) to the main window from where it was created. It doesn't matter whether you're working with Windows Control objects or simple data types like string, so I'm going to use a simple example to illustrate how to handle such a situation.
Let's assume you have a Main form that looks like this. It has an OPEN button and a TextBox.
When you click OPEN, it opens up this secondary input window (your pop-up) which looks like this:
Now the idea is this. You click OPEN and opens the Input form, and lets the user enter some text into the TextBox there. Once you click the OK button, it should close the Input window, and display the text entered by the user in the Main window. Remember that at this point the Input window is closed, which is equivalent to your situation.
So I'd make use of Delegates to accomplish this goal. A delegate lets you transfer data between windows which is what you want.
In my Main I'd declare a public delegate with a signature like this:
public delegate void DataTransfer(string data);
That is, this delegate represents a method that takes in a single string parameter, and has void return type. The idea is to let the secondary Input window 'call' a method in the Main, and that method takes in a string parameter. So, if there was a way for us to call a method that resides in the Main from Input, and pass a string, we can then take the user input text in the Input window, and pass it to the Main window. With me so far?
Now, if I write a method like this in the Main, and let it be called from Input, that should accomplish our goal. Here, txtDisplay is the TextBox in the Main form.
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
To accomplish this, I would define a delegate of type DataTransfer in the Main form like below, and register the ReceiveInput() method to it. Your Main form code behind should look like this:
public delegate void DataTransfer(string data);
public partial class MainForm : Form
{
public DataTransfer transferDelegate;
InputForm inputForm = null;
public MainForm()
{
InitializeComponent();
transferDelegate += new DataTransfer(ReceiveInput);
}
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
private void BtnOpen_Click(object sender, EventArgs e)
{
inputForm = new InputForm(transferDelegate);
inputForm.Show();
}
}
BtnOpen is the OPEN button in the Main form, and when it's clicked, it passes the delegate to the Input form, then opens it. So, accordingly, we need to now modify our Input form:
public partial class InputForm : Form
{
DataTransfer transferDel;
public InputForm(DataTransfer del)
{
InitializeComponent();
transferDel = del;
}
private void BtnOK_Click(object sender, EventArgs e)
{
string data = txtInput.Text;
transferDel.Invoke(data);
Close();
}
}
Here, we modify the constructor so that it takes in a delegate of type DataTransfer, and sets it to the local instance of the same type. Then, at the click of BtnOK on the Input form, we take in the text input by user, and pass that text to the said delegate and invoke it. 'Invoking' is the same as calling the method in the Main form. At this point, you can Clsoe() the Input window as shown above, and you'd still have access to the user input string data from your Main form.
You can use this same approach, and instead of strings you can pass around Controls. However, it's not the best approach to pass around a bunch of controls back and forth, so ideally you would extract the data you need from those controls in your pop-up, and pass only the said data instead of the whole controls.
EDIT: After OP posted the erroneous code.
OK, so here's your issue. The testUserControl class is not a regular class but a control element derived from UserControl. In otherwise, a GUI element. You shouldn't use GUI elements to pass data around. Because, when you do your controlArr[i].getText();, it tries to get the text from the textItem, but textItem is a TextBox Control which doesn't exist at this point because you closed your window. Remember, you do the delegate.Invoke() only once, and at that point *you must send ALL the data back to your main window*.
What you should do is, simply define a class to hold ALL the data you want to pass to your main. For example something like this:
public class DataToPass
{
public string TextBoxText { get; set; }
public string SomeOtherData { get; set; }
// Other stuff you want...
}
Now, instead of passing an array of testUserControl, pass an array of DataToPass. That way, at the Main form you don't have to do the following:
controlArr[i].getText();
Instead you'd simply do something like:
controlArr[i].TextBoxText;
where controlArr now is an array of type DataToPass.
Simply, passing a control derived from UserControl is not a good idea. Just create one class that is capable of holding ALL the data you want to pass and pass it back to the main once.

Passing updating listbox to other form

As the title, i know that many people asked this kind of questions. I have read manys, i success in passing the items in listbox to other form, but in case listbox is adding many new items, i don't know how.
The listbox only update when i reopen the form. This is my code. My way to open new form is modified the Program.cs cuz the listbox is non-static
.....
static class Program
{
private static Lm f1; //This is my Main form
private static Form1 f2; // This is the second
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
f1 = new Lm();
f1.VisibleChanged += OnLmChanged;
Application.Run(f1);
}
static void OnLmChanged(object sender, EventArgs args)
{
if (!f1.Visible)
{
f2 = new Form1(f1.listBox2, f1.listBox3, f1.label7);
f2.Show();
f2.FormClosing += OnFormChanged;
}
}
static void OnFormChanged(object sender, EventArgs args)
{
f1.Show();
}
My code on the second form (Form1)
public partial class Form1 : Form
{
public Form1(ListBox listBox, ListBox list1, Label ll)
{
InitializeComponent();
listBox2.Items.AddRange(listBox.Items);
//listBox.SelectedIndexChanged += (s, args) => //This didn't work
//{
//listBox2.Refresh();
//listBox2.Items.AddRange(listBox.Items);
//};
}
I realize that i shouldn't put the "listBox2.Items.AddRange" in public Form1(..) but i don't know how.. :(
(listBox2 is updating in Lm Form, i'm trying to passing it to Form1 Form)
What does "in public Form1" mean? Do you mean the constructor? The constructor is actually a very good place for initialization. In fact, that's exactly what they were invented for. You've put that code where it belongs, but you can and should improve the way it's written.
What's not so good is passing a listbox to the constructor as a parameter, when all the constructor wants is a collection of items. Maybe the collection you're providing this time happens to belong to a listbox, but that's not important. The same goes for the label text: All Form1 really wants is some text. It doesn't care if the text came from a label somewhere. So have it ask for just the text.
So just pass the items:
public Form1(System.Collections.IEnumerable items,
System.Collections.IEnumerable otherItems,
String labelText)
{
InitializeComponent();
listBox2.Items.AddRange(items);
// etc.
}
And call it like so
static void OnLmChanged(object sender, EventArgs args)
{
if (!f1.Visible)
{
f2 = new Form1(f1.listBox2.Items, f1.listBox3.Items, f1.label7.Text);
f2.Show();
f2.FormClosing += OnFormChanged;
}
}
It would be good to give listBoxItems and otherListboxItems much more specific and descriptive names, but you've provided no information about what the listboxes mean. listBox1 and listBox2 communicate nothing about what's in the listboxes or what purpose they serve in the user interface. That's very bad programming practice. A year from now if you come back to fix this code, you will not know at a glance what this is doing:
listBox2.Items.AddRange(items);
listBox3.Items.AddRange(otherItems);
This, however, actually tells you something:
recipeListBox.Items.AddRange(recipes);
ingredientListBox.Items.AddRange(ingredients);
Maybe it's cars or animals or zipcodes instead of recipes. The same principle applies. It would be easy to get items and otherItems mixed up as to which is which. It's much harder to mix up recipes and ingredients.

Reset/Reload current form

I've been trying to reset my current form to it's original state by closing it, and opening a new one. I want the form objects to be reset,the variables to be re-declared, the class objects to be cleared etc I've got everything working but the class being cleared, no matter what I do it won't create a new one with blank data.
Here is my code:
if (btnRandom.Text == "Reset")
{
SetupScreen form = new SetupScreen();
form.Show();
this.Dispose();
//Create new class for form / or launch load events as normal
form.Mybattleship = new battleship()
form.SetupScreen_Load(this, null);
}
I've tried many methods over the internet and none have worked.. even the overly complicated ones..
Oh I forgot to mention I need the new form to act as if it's just been loaded as normal, so the load events etc trigger
You would be better off making a method that you can call that will set default values for items that you can use when opening form and resetting...
public SetupScreen()
{
InitializeComponent();
SetDefaultValues();
}
private void SetDefaultValues()
{
//start values..
}
public void ResetBtn_Click(object sender, EventArgs e)
{
SetDefaultValues();
}

c# Windows form application forms problem

I have a c# windows form app which contains several forms.
Generally, for example, in form1, I create a instance of form2 and then
form1.hide();
form2.show();
But sometimes I want the previous form to show and dispose current form. How can I call the previous form?
Thanks in advance.
To answer your question, you need to maintain references in your views to each other. While this might work it's messy and error prone. It sounds like all your control logic is probably contained within your form class code and I would suggest moving away from that and separate your concerns.
Solving your form management issues becomes very simple if you create a controller class that, at a minimum, manages the creation and disposal of your forms in whatever way you see fit.
So your code sample would actually be launched from a controller class as something like:
public class FormsController
{
private Form form1 = new Form();
private Form form2 = new Form();
public void SwitchForms()
{
form1.hide();
form2.show();
}
}
For further edification checkout the MVC architectural pattern for cleanly working with data, biz logic and UI.
You might consider extending Form to include some properties/fields that allow you to access other forms. the Form class can be inherited from just like most other .Net classes.
You may also consider doing some of that management in the Program.cs file that is part of you project, if neither form is really supposed to be a child of the other.
If you inherit a new class for your form1 from Form and add a method like closeSecondForm you can have it close and dispose the second form.
There are probably a bunch of different ways to solve the issue. These are just a few.
If you set the new form's Owner to a reference to the current form, you can reference that Owner from the new form. You could also subscribe to the new form's Closed() event from the old form, with code to dispose it (though the form can dispose itself by overriding OnClosed, if it doesn't happen there anyway).
This logic should be handled in Program.cs. The Main() method initializes Form1. You want to take control there instead of passing control to the form.
Example:
static class Program
{
internal static Form1 MyForm1;
internal static Form2 MyForm2;
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
// Initialize Form1
MyForm1 = new Form1();
MyForm1.FormClosing += new FormClosingEventHandler(MyForm1_FormClosing);
// You may want to initialize Form2 on-demand instead of up front like here.
MyForm2 = new Form1();
MyForm2.FormClosing += new FormClosingEventHandler(MyForm2_FormClosing);
// Show Form1 first
MyForm1.Show();
// Now we need to occupy the thread so it won't exit the app. This is normally the job of Application.Run.
// An alternative to this is to have a third form you pass on control to.
while (true)
{
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
}
static void MyForm1_FormClosing(object sender, FormClosingEventArgs e)
{
// Do something, for example show Form2
MyForm2.Show();
// EXAMPLE: We only want to hide it?
e.Cancel = true;
MyForm1.Visible = false;
}
static void MyForm2_FormClosing(object sender, FormClosingEventArgs e)
{
// Do something, for example show Form1
MyForm1.Show();
// EXAMPLE: We only want to hide it?
e.Cancel = true;
MyForm2.Visible = false;
}
}
Since Program is static you can access MyForm1 and MyForm2 anywhere in that project by:
Program.MyForm1.Show();
Program.MyForm2.Hide();
If you plan to have many forms/complex logic I suggest moving this to a separate class. Also consider using a single form and rotate user controls inside it instead.
Form2 myform = new Form2();
myform.show();
this.hide();
You could do this in form1:
...
var form2 = new form2();
form2.Closing += (form2_Closing);
this.hide();
form2.show();
...
private void form2_Closing(object sender, System.EventArgs e)
{
this.show();
}

Changing the property of a control on another form

Basically, I have a settings window, and when you click "OK", it's suppose to apply settings to the main form (eg, set font of a control, etc), and then close.
frmmain frm = new frmmain();
frm.OLVAltBackColor = Color.Aquamarine ;
I tried that, but it only applies the settings to that instance, and you can see it if you do frm.Show();
I'm trying to make it so the already opened form has it's control's properties changed.
What you are trying to do is not working because you are creating a NEW instance of your main form and updating that rather than the first instance. It is possible to update the main form by keeping a reference to it in your settings form... but...
...it sounds like you are approaching this from the wrong direction.
Don't make the settings form dependent on the main form. Instead create the settings form from the main dialog.
class SettingsForm : Form
{
// You need to ensure that this color is updated before the form exits
// either make it return the value straight from a control or set it
// as the control is updated
public Color OLVAltBackColor
{
get;
private set;
}
}
In your main form
(I'm assuming some kind of button or menu click)
private void ShowSettingsClicked(object sender, EventArgs args)
{
using (SettingsForm settings = new SettingsForm())
{
// Using 'this' in the ShowDialog parents the settings dialog to the main form
if (settings.ShowDialog(this) == DialogResult.OK)
{
// update settings in the main form
this.OLVAltBackColor = settings.OLVAltBackColor;
}
}
}
Apply the property change to the form that already exists and is already shown instead of creating a new form and changing that one.
In this code you're creating a new instance of the frmmain. Any changes you make to that new object will happen in the new object, not the one you actually want to change.:
frmmain frm = new frmmain(); //Creating a new object isn't the way.
frm.OLVAltBackColor = Color.Aquamarine ;
What you're looking for is a way to call on the already existant frmmain class and change the property of that.
Edit, for example:
using System;
class Statmethod
{
//A class method declared
static void show()
{
int x = 100;
int y = 200;
Console.WriteLine(x);
Console.WriteLine(y);
}
public static void Main()
{
// Class method called without creating an object of the class
Statmethod.show();
}
}

Categories