I have a problem with arrays which are made from class; actually I can make an array from a class and in the first form I set the data in may array, but when I switch to my second form and create an object from my class, I find my array empty so I can't use the information witch I had entered into my array.
public partial class Form1 : Form
{
string _name;
string _department;
int _id;
int _count;
int counter = 0;
Mediator m = new Mediator();
Employee ee = new Employee();
public Form1()
{
InitializeComponent();
}
private void Add_to_Array_Click(object sender, EventArgs e)
{
_name = txtName.Text;
_department = txtDepartment.Text;
_id = int.Parse(txtID.Text);
_count = counter;
m.Set_Value(_name, _department, _id,_count);
counter++;
Exchange();
//-----------------------------------
txtDepartment.Text = "";
txtID.Text = "";
txtName.Text = "";
}
private void Search_Click(object sender, EventArgs e)
{
listBox1.Items.Add(m.array[0].E_Name);
listBox1.Items.Add(m.array[0].E_Department);
listBox1.Items.Add(m.array[0].E_ID.ToString());
//---------------------------------------------------
listBox1.Items.Add(m.array[1].E_Name);
listBox1.Items.Add(m.array[1].E_Department);
listBox1.Items.Add(m.array[1].E_ID.ToString());
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
}
public partial class Form2 : Form
{
Mediator M;
public Form2()
{
InitializeComponent();
}
private void Show2_Click(object sender, EventArgs e)
{
listBox1.Items.Add(M.array[0].E_Name);
listBox1.Items.Add(M.array[0].E_Department);
listBox1.Items.Add(M.array[0].E_ID.ToString());
//---------------------------------------------------
listBox1.Items.Add(M.array[1].E_Name);
listBox1.Items.Add(M.array[1].E_Department);
listBox1.Items.Add(M.array[1].E_ID.ToString());
}
class Employee
{
string Name;
string Department;
int ID;
//**************************
public string E_Name
{
get { return Name; }
set { Name = value; }
}
public string E_Department
{
get { return Department; }
set { Department = value; }
}
public int E_ID
{
get { return ID; }
set { ID = value; }
}
}
class Mediator
{
public Employee[] array = new Employee[5];
public void Set_Value(string name,string department,int id,int count)
{
array[count] = new Employee();
array[count].E_Name = name;
array[count].E_Department = department;
array[count].E_ID = id;
}
}
I would strongly suggest that you don't make Mediator m static.
IMHO this is a hack and you don't want to get in the habit of effectively making global variables everywhere, it will come back to bite you as you progress through your career.
The better solution is to pass Form2 only the data it needs to work on.
I'm guessing Form2 only needs to display the list of Employees, so you should create a Property in Form2 as follows:
public Employee[] Employees {get; set;}
[If you need more than just the list of employees then you should rather have a property for the Mediator - public Mediator Mediator {get; set;} ]
You then need to send this data to the second form just before you show it:
Form2 f2 = new Form2();
f2.Employees = m.array;
f2.Show();
Because the data is sent by reference any changes you make in form2 will reflect in the objects stored in form1.
Another option is to structure your program using the MVC pattern. It's a little bit more advanced, but it's a great pattern to keep your winForms apps neat and tidy. If you are building a wizard style app then I would strongly suggest this approach.
As an aside note you can also clean up the code quite a bit by using a list instead of an array to store the employee data - this will also make the code more adaptable to larger numbers of employees in the future.
You can also use C#s automatic properties to reduce the amount of code you need to write. So your code can look like this this instead:
public partial class Form1 : Form
{
private Mediator _mediator = new Mediator();
public Form1()
{
InitializeComponent();
}
private void Add_to_Array_Click(object sender, EventArgs e)
{
var newEmployee = new Employee
{
Name = txtName.Text,
Department = txtDepartment.Text,
ID = int.Parse(txtID.Text)
};
_mediator.Employees.Add(newEmployee);
Exchange();
//-----------------------------------
txtDepartment.Text = "";
txtID.Text = "";
txtName.Text = "";
}
private void Search_Click(object sender, EventArgs e)
{
foreach (var employee in _mediator.Employees)
{
listBox1.Items.Add(employee.Name);
listBox1.Items.Add(employee.Department);
listBox1.Items.Add(employee.ID.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Employees = _mediator.Employees;
f2.Show();
}
}
public partial class Form2 : Form
{
public List<Employee> Employees { get; set; }
public Form2()
{
InitializeComponent();
}
private void Show2_Click(object sender, EventArgs e)
{
foreach (var employee in Employees)
{
listBox1.Items.Add(employee.Name);
listBox1.Items.Add(employee.Department);
listBox1.Items.Add(employee.ID.ToString());
}
}
}
class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public int ID { get; set; }
}
class Mediator
{
public List<Employee> Employees { get; private set; }
public Mediator()
{
Employees = new List<Employee>();
}
}
You need an instance of Form1 in Form2 to use the array you've created.
You have two options;
First one, you can store an instance of Form1 in a common class so you can reach it from Form2.
Second option; you need to pass reference of Form1 to your Form2 instance.
A quick fix for your problem would be to add the static keyword in your array definition. this will make it stateless and therefor there won't be a new (instance of the) array being created each time you access it.
You should also consider placing this array in some kind of a static class that will be in charge of handling this kind of global variables.
As for your edits, you have at least 2 options here: the first one is making the Mediator class and the array inside static; or create a property in your second form like public string [] SomeArray {get; set;} and pass the array to it after declaring the ... = new Form2(); and before calling the .Open()
Related
In my C# windows form I have 2 forms. I would like to display a collection of strings in a label on a form. When I debug I show the 2 elements in my array but they are not showing in the label I am passing it to. When I hover of toString the data is there but how to I pass it to sender so it will display in the label control I have on my form?
In the snippet of code below to data is in toString but how do I get it from there down to sender.ToString????
public AccountReport_cs(Func<string> toString)
{
this.toString = toString;
}
private void AccountReport_cs_Load(object sender, EventArgs e)
{
label1.Text = sender.ToString();
}
This is another piece of the code that will open form2 where the information should be displayed.
private void reportButton2_Start(object sender, EventArgs e)
{
AccountReport_cs accountReport = new AccountReport_cs(allTransactions.ToString);
accountReport.ShowDialog();
}
Here is the last piece of code and this will show how the data gets to EndOfMonth.
public class Transaction
{
public string EndOfMonth { get; set; }
}
public override List<Transaction> closeMonth()
{
var transactions = new List<Transaction>();
var endString = new Transaction();
endString.EndOfMonth = reportString;
transactions.Add(endString);
return transactions;
}
If you need to send information between forms, the best thing you can do is create a property in the target form and assign the value you want to send before displaying the form; thus you will not need to change the default constructor of the form.
// Destiny form
public partial class FormDestiny : Form {
// Property for receive data from other forms, you decide the datatype
public string ExternalData { get; set; }
public FormDestiny() {
InitializeComponent();
// Set external data after InitializeComponent()
this.MyLabel.Text = ExternalData;
}
}
// Source form. Here, prepare all data to send to destiny form
public partial class FormSource : Form {
public FormSource() {
InitializeComponent();
}
private void SenderButton_Click(object sender, EventArgs e) {
// Instance of destiny form
FormDestiny destinyForm = new FormDestiny();
destinyForm.ExternalData = PrepareExternalData("someValueIfNeeded");
destinyForm.ShowDialog();
}
// Your business logic here
private string PrepareExternalData(string myparameters) {
string result = "";
// Some beautiful and complex code...
return result;
}
}
Currently in my program a user opens form 1 to create a new instance of a class and it is then saved to a list. After form 1 closes I would like the main form to reload and show the updated list on the screen. I am having trouble figuring out how to refresh the main navigation and how I would get the list to show on the form.
MainNaviagation
public partial class MainNavigation : Form
{
private Model m_modelObj;
public MainNavigation(Model modelObj)
{
InitializeComponent();
m_modelObj = modelObj;
m_modelObj.ChocolateAdded += m_modelObj_ChocolateAdded;
}
void m_modelObj_ChocolateAdded(Chocolate newChocolate)
{
//whole list of chocolates
List<Chocolate> chocolateList = m_modelObj.ChocolateList;
}
private void button1_Click(object sender, EventArgs e)
{
string candy = comboBox1.SelectedItem.ToString();
Form1 aForm1 = new Form1(textBox1.Text, candy, m_modelObj);
aForm1.ShowDialog();
}
}
Model Class:
{
public delegate void ChocolateAddedEventHander(Chocolate newChocolate);
public class Model
{
public event ChocolateAddedEventHander ChocolateAdded;
public List<Chocolate> ChocolateList = new List<Chocolate>();
public void AddChocolateInList(Chocolate chocolate)
{
ChocolateList.Add(chocolate);
if (ChocolateAdded != null)
ChocolateAdded(chocolate);
}
}
form1
public partial class Form1 : Form
{
Model m_model;
public Form1(string name, string candy, Model modelObj)
{
InitializeComponent();
m_model = modelObj;
string str = name + " selected : ";
label1.Text = str;
}
private void button1_Click(object sender, EventArgs e)
{
Chocolate newChocolate = new Chocolate(comboBoxChocolateSelection.SelectedItem.ToString(), 12.5, true, 2);
m_model.AddChocolateInList(newChocolate);
this.Close();
}
}
chocolates
public class Chocolate
{
#region Fields
public string flavor;
public double cost;
public bool giftWrap;
public int quantity;
#endregion End of Fields
#region Constructors
public Chocolate(string flavor, double cost, bool giftWrap, int quantity)
{
this.flavor = flavor;
this.cost = cost;
this.giftWrap = giftWrap;
this.quantity = quantity;
}
#endregion End of Constructors
}
The goal of the program assignment I'm working on requires me to fill a listbox with items taken from a data file, and then allowing the user to modify parts of the selected item. To do this, I need assistance in figuring out how to pass part of a listbox's selected item in one form to a textbox in another form.
Here's the coding I have for the first form in my program:
public partial class Form1 : Form
{
const char DELIM = '\\';
const string FILENAME = #"C:\Visual Studio 2015\Data Files\Training Workshops data";
string recordIn;
string[] Fields;
static FileStream file = new FileStream(FILENAME, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(file);
public int X;
public Form1()
{
InitializeComponent();
}
public class Workshop
{
public string title { get; set; }
public int days { get; set; }
public string categrory { get; set; }
public double cost { get; set; }
public string[] categrorynames =
{
"Application Development",
"Databases",
"Networking",
"System Administration"
};
}
Workshop shop = new Workshop();
private void button1_Click(object sender, EventArgs e)
{
Form2 secondForm = new Form2();
secondForm.Show();
}
private void PopulateList(string filePath)
{
while(recordIn != null)
{
try
{
recordIn = reader.ReadLine();
Fields = recordIn.Split(DELIM);
X = Convert.ToInt32(Fields[0]);
shop.categrory = shop.categrorynames[X];
shop.days = Convert.ToInt32(Fields[1]);
shop.title = Fields[3];
shop.cost = Convert.ToDouble(Fields[2]);
}
catch (Exception A)
{
if (X < 0 && X > 3)
{
shop.categrory = "invalid";
}
if (shop.days != Convert.ToInt32(Fields[1]))
{
shop.days = 0;
}
if (shop.title != Fields[3])
{
shop.title = "invalid";
}
if (shop.cost != Convert.ToDouble(Fields[2]))
{
shop.cost = 0;
}
}
}
}
}
And below is a link to a screenshot of the second form:
http://i.stack.imgur.com/IRqVh.png
I need to transfer the shop.categrory data of form1's listbox's selected item to the second form's, and the shop.title, shop.days and shop.cost to the corresponding textbox's. From there I can make it so that whatever the user enters in the textboxes would change the data of the selected item when they press the "save and exit" button.
Any help would be appreciated, and if anyone notices an error in the coding I have now, please feel free to point them out.
Create a Parameterized constructor in form2 that accepts a String, and create it's instance in first form, and pass the value you want to pass to the second form:
private void button1_Click(object sender, EventArgs e)
{
Form2 secondForm = new Form2("DATA TO BE SENT");
secondForm.Show();
}
and in form2 Create a Constructor:
public Form2(string data)
{
InitializeComponent();
txtData.Text=data;
}
I have a list of objects on my main form - GUI - and while I can access that list using a foreach loop for example foreach (Employee emp in employees)
this allows me to access the employees within the list.
On the other form I have some code that requires it to access the list of employees.
So far I have tried to copy the private List<Employee> employees;
but it gives me a null reference exception obviously meaning that there's nothing in the list that has been copied over.
I'll provide a view of my code so you can have something to base your solution off:
Code
Main form
private List<Employee> employees;
public Form1()
{
InitializeComponent();
employees = new List<Employee>();
}
Employee e1 = new Employee(MemberJob.Employee, "Name", MemberSkills.CPlus);
Added this bit of code in case I need to send some variables into the form
private void btnAddJob_Click(object sender, EventArgs e)
{
CreateAJob newForm2 = new CreateAJob();
newForm2.ShowDialog();
}
**Additional Form code **
private string _jobName = "";
private string _jobDifficulty = "";
private string _skillRequired = "";
private int _shiftsLeft = 0;
private List<Employee> employees; // tried to copy this over but there's nothing in it
public CreateAJob()
{
InitializeComponent();
}
public CreateAJob(string _jobName, string _skillRequired, int _shiftsLeft)
{
this._jobName = JobName;
this._skillRequired = SkillRequired;
this._shiftsLeft = ShiftsLeft;
}
private void Distribute(string _jobName, int _shiftsLeft, string _skillsRequired)
{
foreach (Employee emp in employees)
{
while (emp.Busy == true)
{
if (emp.Busy == false && emp.Skills.ToString() == _skillRequired)
{
emp.EmployeeWorkload = _jobName;
emp.ShiftsLeft = _shiftsLeft;
}
... additional code to finish method
Create another constructor and pass the Employee list like this
CreateAJob form:
internal CreateAJob(List<Employee> employees)
: this() // Make sure the normal constructor is executed
{
this.employees = employees;
}
Main form:
private void btnAddJob_Click(object sender, EventArgs e)
{
CreateAJob newForm2 = new CreateAJob(employees);
newForm2.ShowDialog();
}
Hi coders I have yet another question involving data binding in winforms. I set up a test applications where I have a bindinglist composed of structs called CustomerInfo. I have bound a listbox control to this list and spun a thread to add CustomerInfo items to the bindinglist.
namespace dataBindingSample {
public partial class Form1 : Form {
public BindingList<CustomerInfo> stringList = new BindingList<CustomerInfo>();
public Thread testThread;
public Form1() {
InitializeComponent();
stringList.AllowNew = true;
stringList.RaiseListChangedEvents = true;
listBox1.DataSource = stringList;
testThread = new Thread(new ThreadStart(hh_net_retask_request_func));
testThread.Priority = ThreadPriority.Normal;
}
private void hh_net_retask_request_func() {
int counter = 1;
while (true) {
CustomerInfo cust = new CustomerInfo();
cust.Name = "Customer "+ counter.ToString();
this.Invoke((MethodInvoker)delegate {
stringList.Add(cust);
});
counter++;
Thread.Sleep(1000);
}
}
private void Form1_Load(object sender, EventArgs e) {
testThread.Start();
}
}
public struct CustomerInfo {
public string Name {
set {
name = value;
}
get {
return name;
}
}
private string name;
}
}
What I see in the list box is the name of the struct dataBindingSample.CustomerInfo as opposed to the property of the struct. I was under the impression that non complex binding took the first available property.
Please educate me as to what I am doing wrong.
Thanks,
You'll need to either add an override of ToString() to your CustomerInfo class that returns what you'd like displyed in your list box, or set listBox1.DisplayMemer = "Name" before setting the DataSource.