C# Send text from Form2 textbox to Form1 Textbox - winforms

I need some help, i want to set text from a textbox from Form2.cs to the another textbox in Form1.cs but i keep getting this error:
Error 2 An object reference is required for the non-static field, method, or property.
I'm coding in c# and i cannot find it anywhere on the internet how to do this?

you have to provide an istance of Form2 to Form1. Fore example you can pass it in the constructor like:
public Form2(Form1 frm)
and then you can call something like this
this.TextBox1.Text = frm.TextBox1.Text

I'm writing this answer only based your error code.
You try to access a non-static method without using any instance of belongs it class object. For example; this code will fail.
class Program
{
public static void Main()
{
WriteMethod();
}
public void WriteMethod()
{
Console.Writeline("Succes!");
}
}
But this code works;
class Program
{
public static void Main()
{
Program p = new Program();
p.WriteMethod();
}
public void WriteMethod()
{
Console.Writeline("Succes!");
}
}
Hope you get the main point.

Well your case is too simple, you can do too many things in order to exchange data between classes
Why don't you try saving data in another static class, or a singleton one...

//this code worked for me
//in form2 put following code prevent form from opening multiple times
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private static Form2 Instance;
public static Form2 GetInstance()
{
if (Instance ==null || Instance.IsDisposed)
{
Instance = new Form2();
}
else
{
Instance.BringToFront();
}
return Instance;
}
// in form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Button2_Click(object sender, EventArgs e)
{
Form2 form2 = Form2.GetInstance();
form2.textBox1.Text = textBox1.Text;
form2.Show();
}
}

Related

Error in loop when trying to make my array of labels match a list from another class

I'm trying to create a loop that will change my array of labels to match a list from another class. I declared the list as
ADDITIONAL INFO: I am creating a payroll program. When the Pay button is clicked for an employee, the Status list with that employee index gets updated into "Paid". I want the label on the other form to reflect the word "Paid" as well
private List<string> Status = new List<string>(2);
public List<string> GetList()
{
return Status;
}
private void btnFind_Click(object sender, EventArgs e)
{
Status.Add("Unpaid");
Status.Add("Paid");
Status.Add("Unpaid");
}
And in the second form
public partial class Form2 : Form
{ Label[] Labels = new Label[3];
private void Form2_Load(object sender, EventArgs e)
{
Labels[0] = this.lblTony;
Labels[1] = this.lblSteve;
Labels[2] = this.lblPeter;
Form1 f1 = new Form1 ();
for (int i = 0; i !=3 ; i++)
{
List<string> Status = f1.GetList();
Labels[i].Text = Status[i];
}
}
}
'''
I tried to only put the relevant codes but I may be missing something? The error is IndexOutOfRangeException which I do not get because the are the same size. I tried changing the sizes but the error only changes to argumentoutofbounds
try this :
status.Add(lables[i].Text);
insted of
lables[i].Text = status[i];
I Dont Test it But I think its going to work!
go forward
There are a lot of things that are not great in the code you have shown but if you want to follow this approach then why not just:
class Form1
{
private List<string> Status = new List<string>();
public List<string> GetList()
{
return Status;
}
// I'm guessing as to how you add elements to Status
public Form1()
{
Status.Add("Item 1");
Status.Add("Item 2");
Status.Add("Item 3");
}
}
public partial class Form2 : Form
{
Label[] Labels = new Label[3];
private void Form2_Load(object sender, EventArgs e)
{
Labels[0] = this.lblTony;
Labels[1] = this.lblSteve;
Labels[2] = this.lblPeter;
Form1 f1 = new Form1();
List<string> Status = f1.GetList();
Debug.Assert(Labels.Length == Status.Count());
for (int i = 0; i < Status.Count(); ++i)
{
Labels[i].Text = Status[i];
}
}
}
It looks like your main problem is that you have allocated a space of 2 for Status when you construct the object but then run the loop for 3 when copying the values over. If you are using a List you rarely need to pre-allocate its size.
I would create your Label array using this kind of syntax so you don't have to specify a size:
Label[] Labels;
private void Form2_Load(object sender, EventArgs e)
{
Labels = new Label[] { this.lblTony, this.lblSteve, this.lblPeter };
}
Also, I suspect that you're getting the error because of this line in Form2:
Form1 f1 = new Form1 ();
...as this is creating an "invisible" instance of Form1 and is likely not the Form1 on your screen where presumably the "btnFind" button was clicked to add items to the List (is that a typo in your posted code?).
If that's the case, then you need a reference to the actual visible Form1. You can do use by either passing Form1 into Form2 via a constructor or method, via the Show() method, or by iteration over the Application.OpenForms collection and finding Form1 there.
I'm just trying to make the label array text become the status list
from form1.
Here's one way to pass Form1 into Form2 via the Show() method:
private void button1_Click(object sender, EventArgs e)
{
// ... in Form1 ...
Form2 f2 = new Form2();
f2.Show(this); // <-- pass Form1 via "this"
}
Now, over in Form2, you can cast this.Owner back to Form1 and use that to access the list:
private void button1_Click(object sender, EventArgs e)
{
// ... in Form2 ...
Form1 f1 = (Form1)this.Owner;
List<String> status = f1.GetList();
// ... do something with "status" ...
}

In which window should I instantiate my object?

My WPF application has multiple windows:
MainWindow
ChildWindow1
Childwindow2
I instantiate the children from MainWindow by...
public partial class MainWindow : Window
{
ChildWindow1 CW1;
ChildWindow2 CW2;
public MainWindow()
{
InitializeComponent();
}
private void btnButton1_Click(object sender, RoutedEventArgs e)
{
CW1 = new ChildWindow1();
CW1.Show();
CW1.Owner = this;
CW2 = new ChildWindow2();
CW2.Show();
CW2.Owner = this;
}
}
Awesome!
But here's where I run into trouble: I have a non-UI class that I need to instantiate.
public class MyClass
{
public void DoSomething()
{
//Do something here
}
}
The object of that class should "live" inside ChildWindow1, because that's where it logically belongs. So, I instantiate it inside ChildWindow1 like so:
public partial class ChildWindow1 : Window
{
public MyClass MyObject = new MyClass();
public ChildWindow1()
{
InitializeComponent();
}
}
But eventually comes a point where ChildWindow2 needs to interact with the object in ChildWindow1:
Call the 'DoSomething()' method of the object in Childwindow1.
Subscribe to an event raised by the object in ChildWindow1
I can do all that from the main window, because it owns the children, but I want the children to be able to interact directly.
Am I violating a design principle by allowing CW1 <--> CW2 interaction?
How else would you get them to interact if not by calling methods or subscribing to events?
Thanks to all here, for providing this awesome learning resource! Much appreciated!
Make this the instance of MyClass both public and static, to access it from almost anywhere because that should be accessed based on a certain instance of window.
If you wanna access a variable from any window, either make it static or call it based on an instance of that window like:
public partial class ChildWindow1 : Window
{
public static MyClass MyObject = new MyClass();
public ChildWindow1()
{
InitializeComponent();
}
}
access like this CW1.MyObject

Defining eventhandlers outside MainWindow?

I am trying to define some event handlers inside auser class but im not sure how. The MainWindow needs the handler definitions.
public abstract partial class MainWindow: Window {
public User user = new User();
}
public class User {
internal void ExampleMouseEventDown(object sender, MouseEventArgs e) {
// Does stuff;
}
}
Isnt there a way to somehow make this work? Such as:
mainWindow.AddHandleDefinition += ExampleMouseEventDown();
Also tried this:
public partial class MainWindow : Window {
public MainWindow() {
User user = new User(this);
}
}
public class User
{
internal User(MainWindow w)
{
w.AddObserverButton.MouseUp += ExampleMouseEventDown;
}
internal void ExampleMouseEventDown(object sender, MouseEventArgs e)
{
// Does stuff;
}
}

Interaction between forms

I am using visual studio 2012 (windows form application) and I have two forms, one with a label and the other with a button. I want it so that when you click the button the label on the other form goes up by one. I already have:
Label1 = Label1 + 1
I just need to know how to make the connection with the two forms. Maybe call a function?
Btw I am new to the program and script so in simple terms plz.
Here is a sample I create for you. Add Fomr2 Like this:
public partial class Form2 : Form
{
private void button1_Click(object sender, EventArgs e)
{
Form1.Instance.Controls.Find("label1", true).First().Text = "Some thing";
}
}
And Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
_Instance = this;
}
private static Form1 _Instance;
public static Form1 Instance
{
get { return _Instance; }
set { Instance = value; }
}
private void button1_Click(object sender, EventArgs e)
{
new Form2().Show();
}

DataGridViewColumn.DataPropertyName Property

I have a DataGridView control and I want to populate it with data.
I use DataSource property
// dgvDealAsset is DataGridView
private void DealAssetListControl_Load(object sender, EventArgs e)
{
dgvDealAssets.AutoGenerateColumns = false;
dgvDealAssets.DataSource = DealAssetList.Instance.Values.ToList();
}
Now problem number one. The class of my collection does not contain only simple types that I can map to columns using DataPropertyName. This is the class that is contained in collection.
class MyClass
{
public String Name;
MyOtherClass otherclass;
}
class MyOtherClass
{
public String Name;
}
Now I am binding properties of MyClass to columns
col1.DataPropertyName = "Name" // Ok
col2.DataPropertyName = "otherclass" // Not OK - I will have empty cell
The problem is that I want to display otherclass.Name field. But if I try to write
col2.DataPropertyName = "otherclass.Name"
I get empty cell.
I tried to manually set the column
private void DealAssetListControl_Load(object sender, EventArgs e)
{
dgvDealAssets.AutoGenerateColumns = false;
dgvDealAssets.DataSource = DealAssetList.Instance.Values.ToList();
// iterate through rows and set the column manually
foreach (DataGridViewRow row in dgvDealAssets.Rows)
{
row.Cells["Column2"].Value = ((DealAsset)row.DataBoundItem).otherclass.Name;
}
But this foreach cycle takes about minute to complete (2k elements). How to solve this problem?
DataGridView doesn't support databinding to child properties. For more info, check this post
I like the solution that uses the CellFormatting event.
Problem nr.1:
Try to do the following:
extend MyOtherClass from Object (this step might not be needed)
and override, or create, method ToString().
That should do it.
In case you want to use many child elements like this:
class MyClass
{
public int Id;
public MyOtherClass OtherClass;
}
class MyOtherClass
{
public string Name;
public int Number;
}
How about
1st solution
Set value for each cell in some event (mabye other one is better), manually, after setting datasource, for example:
private void dgv_CellFormatting( object sender, DataGridViewCellFormattingEventArgs e )
{
MyClass data = dgv.Rows[ e.RowIndex ].DataBoundItem as MyClass;
dgv.Rows[ e.RowIndex ].Cells[ "colName" ].Value = data.OtherClass.Name;
dgv.Rows[ e.RowIndex ].Cells[ "colNumber" ].Value = data.OtherClass.Number;
}
2nd solution
What about creating a DataTable from the data and then bind it?
I'd be thankful for any opinion ;-)
It sounds like the DataGridView's virtual mode would solve your problem. In virtual mode, the DataGridView will fire an event whenever it needs to display a cell. The event lets you populate the cell however you please. The advantage of virtual mode is the system only needs to pull the data that's actually being displayed, so there's no slow start-up time while you load everything.
private void my_init_function() {
datagridview.VirtualMode = true;
datagridview.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(datagridview_CellValueNeeded);
}
private void datagridview_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = get_my_data(e.RowIndex, e.ColumnIndex);
}
The way of databinding a specific column of a datagrid to a child property of the datagrid's datasource is using the DataGridView.Column.Tag property, along with the ToString() override method inside the child object. It goes as follows:
public class Car
{
public int Id { get; set; }
public int Name { get; set; }
public string Colour { get; set; }
public Wheel Wheel { get; set; }
}
public class Wheel
{
public string WheelName { get; set; }
public override string ToString()
{
return WheelName;
}
}
public class Main
{
private void LoadGrid(List<Car> data)
{
this.dataGridView.Columns["Wheel"].Tag = "WheelName";
}
}

Resources