Binding Source Control - c#

I have a binding source control in my form. I utilize the binding source current_changed event in the form for doing some special tasks, the problem that I faces is, in the form_Load event I make a list as the datasource of this binding source and the current_changed event has been called multiple times. Why it's like that?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
List<Employee> listEmployee = new List<Employee>();
for (int i = 1; i <= 10; i++)
{
Employee emp = new Employee();
emp.EmployeeName = "user" + i;
emp.EmployeeAddress = "Address" + i;
listEmployee.Add(emp);
}
bindingSource1.DataSource = listEmployee;
dataGridView1.DataSource = bindingSource1;
}
private void bindingSource1_CurrentChanged(object sender, EventArgs e)
{
MessageBox.Show("Hai");
}
}
public class Employee
{
private string Name;
private string Address;
public string EmployeeName {
get {return Name;}
set { Name = value; }
}
public string EmployeeAddress
{
get { return Address; }
set { Address = value; }
}
}

For my special case I created a flag on the page load and prevented the execution of currentchanged event more than once. I couldn't find any other way to solve it.

Related

How to send Datagridview Values to Main form

I would like to send my Datagridview values to my Combobox in my mainform.
This is my code in my Datagridview form :
private void EquipmentList_Load(object sender, EventArgs e)
{
DataTable.RowCount = 30;
//Beam Description default value
DataTable.Rows[0].Cells[1].Value = "8.000m x 0.400m x 0.550m";
}
Below code is what i've used but nothing happened :
private void MainForm_Load(object sender, EventArgs e)
{
this.KeyPreview = true;
EquipmentList ELform = new EquipmentList();
//Beam Combo Box default values
var BCBi1 = ELform.DataTable.Rows[0].Cells[1].Value.ToString();
this.BeamCB.Items.Add(BCBi1);
}
When i run it i'm getting this error:
error when running
An advance thank you for all those who will help me.
DataTable.Rows[0].Cells[1].Value is assigned in EquipmentList form when it is loaded.
EquipmentList ELform = new EquipmentList(); - here form is created but not loaded (you need to invoke Show or ShowDialog for that).
I suggest to declare publicly accessible default value (and not rely on existance of DataTable object with 1 row, which is a low-level implementation detail)
public const string DefaultSize = "8.000m x 0.400m x 0.550m";
private void EquipmentList_Load(object sender, EventArgs e)
{
DataTable.RowCount = 30;
DataTable.Rows[0].Cells[1].Value = DefaultSize;
}
and then
private void MainForm_Load(object sender, EventArgs e)
{
this.KeyPreview = true;
this.BeamCB.Items.Add(EquipmentList.DefaultSize);
}
To the question "So is there any possible to load that values wihtout clicking/showing my equipmentlist form." Absolutely. Start by building a class for your data:
public class gridviewdata
{
public string content { get; set; }
public int row { get; set; }
public int cell { get; set; }
public gridviewdata(string content, int row, int cell)
{
this.content = content;
this.row = row;
this.cell = cell;
}
}
add a mediator class:
public static class mediator
{
public static List<gridviewdata> gridviewdatalist;
}
then add this code to your ELform load event:
private void EquipmentList_Load(object sender, EventArgs e)
{
DataTable.RowCount = 30;
//Beam Description default value
DataTable.Rows[0].Cells[1].Value = "8.000m x 0.400m x 0.550m";
mediator.gridviewdatalist.Add(new gridviewdata("8.000m x 0.400m x 0.550m", 0, 1);
}
then add a new method identifying your specific row to your MainForm:
private gridviewdata selectdata(int row, int cell)
{
foreach(gridviewdata data in mediator.gridviewdatalist)
{
if(data.row == row && data.cell == cell)
{
return data;
}
}
return null;
}
And finally call that code in your MainForm:
private void MainForm_Load(object sender, EventArgs e)
{
this.KeyPreview = true;
//and call it there
var BCBi1 = selectdata(0, 1);
this.BeamCB.Items.Add(new Item(BCDi1, 1)); //Add value and index
}
Hope this helps.

DGV updates only when cell is clicked

I have a WFA, at the moment it has 2 forms.
The first form contains a DataGridView, with it's data source being a list.
When the user clicks a button, this opens up form2. Within form2 I have a bubblesort algorithm which sorts the list by one of it's properties. It then passes the updates list back to form1, and sets the new datasource to the bubbledsorted updated list from form2.
Now this works, the bubblesort works. HOWEVER, the DGV on form1 doesn't update UNLESS I click on individual rows/cells of the DGV. I have to click on each one individually for them to be in their new sorted positions.
Here's the code I have:
FORM1:
//This just shows Form2
private void sortByPriority_Click(object sender, EventArgs e)
{
fm2 = new Form2();
fm2.Show();
}
//This is called by form2 to set the new datasource
public void refreshDataGrid(DataGridView p)
{
dataGridView1.DataSource = null;
dataGridView1.DataSource = p.DataSource;
}
FORM2:
private void sortPriority_Click(object sender, EventArgs e)
{
int temp = 0;
bool tempforComp;
string tempforDate = "";
string tempforDesc = "";
string tempforName = "";
for (int write = 0; write < 10; write++)
{
for (int sort = 0; sort < toDoGen.task.Count - 1; sort++)
{
if (toDoGen.task[sort].Priority > toDoGen.task[sort + 1].Priority)
{
temp = toDoGen.task[sort + 1].Priority;
tempforComp = toDoGen.task[sort + 1].Completed;
tempforDate = toDoGen.task[sort + 1].DateOfCompletion;
tempforDesc = toDoGen.task[sort + 1].Description;
tempforName = toDoGen.task[sort + 1].Name;
toDoGen.task[sort + 1].Priority = toDoGen.task[sort].Priority;
toDoGen.task[sort + 1].Completed = toDoGen.task[sort].Completed;
toDoGen.task[sort + 1].DateOfCompletion = toDoGen.task[sort].DateOfCompletion;
toDoGen.task[sort + 1].Description = toDoGen.task[sort].Description;
toDoGen.task[sort + 1].Name = toDoGen.task[sort].Name;
toDoGen.task[sort].Priority = temp;
toDoGen.task[sort].Completed = tempforComp;
toDoGen.task[sort].DateOfCompletion = tempforDate;
toDoGen.task[sort].Description = tempforDesc;
toDoGen.task[sort].Name = tempforName;
}
}
DataGrid n = new DataGrid();
n.DataSource = toDoGen.task;
refresh();
}
}
private void refresh()
{
fm1 = new Form1();
fm1.refreshDataGrid(n);
}
EDIT: updated and just to be clear - I need to use multiple forms (University Assignment), and nonetheless, it didn't update even when I had the sorting algorithm in Form1.
I'll make a simplified example that doesn't use the BubbleSort algorithm, I hope it helps:
This is the code of Form1 class. I define a StringValue class because of this: How to bind a List<string> to a DataGridView control?
public class StringValue
{
public StringValue(string s)
{
_value = s;
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = new List<StringValue> {
new StringValue("string1"),
new StringValue("string3"),
new StringValue("string2")
};
}
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2(this, dataGridView1.DataSource as List<StringValue>);
form2.Show();
}
public void RefreshGrid(List<StringValue> source)
{
dataGridView1.DataSource = source;
}
}
The button click event opens Form2 and passes to it the grid view datasource. Here's Form2:
public partial class Form2 : Form
{
Form1 _form1;
List<StringValue> _source;
public Form2(Form1 form1, List<StringValue> source)
{
_form1=form1;
_source=source;
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_source = _source.OrderBy(x => x.Value).ToList();
_form1.RefreshGrid(_source);
this.Close();
}
}
After the click on the button in Form2 the DataGridView1's data source is refreshed with a sorted version, and Form2 is closed.

Using next and previous buttons to navgiate through a list

So I am having some trouble with my C#forms. I have created a list of customers in which they have a there name, suburb, and bank account balances stored. Using a next and previous buttons I need to be able to allow the user to navigate through the current 5 objects in the list. How I was planning on doing so was when the user would click either the button, the text boxes would be filled with the relevant information. The reason why customer and other details are buttons is that later i need to be able to update the information stored in those fields, so i thought a good way to do that would be to erase what was already in the text box, type the new information, then press the button to update.
Anyways, my main issue is i need to use my view buttons to move through my list
This is how my form looks like:
My current form code is this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Customer c1 = new Customer("Sibel Yilmaz", "Wollongong", 2500, 3000, 5000);
Customer c2 = new Customer("John Doe", "Figtree", 2547, 2500, 3655);
Customer c3 = new Customer("Mariah Moore", "Coniston", 2500, 7000, 36000);
Customer c4 = new Customer("Jessica Blackshaw", "Bellambi", 3500, 6000, 4750);
Customer c5 = new Customer("Suzan Yilmaz", "Wollongong", 2500, 2000, 47110);
List<Customer> customers = new List<Customer>();
customers.Add(c1);
customers.Add(c2);
customers.Add(c3);
customers.Add(c4);
customers.Add(c5);
}
private void Form1_Load(object sender, EventArgs e) { }
private void button2_Click(object sender, EventArgs e) { }
private void button6_Click(object sender, EventArgs e) { }
private void textBox4_TextChanged(object sender, EventArgs e) { }
private void Customer_Click(object sender, EventArgs e) { }
}
And my Customer class is:
public class Customer
{
protected string name;
protected string suburb;
protected int postcode;
protected double credit_balance;
protected double saving_balance;
public Customer(string name, string suburb, int postcode, double credit_balance,
double saving_balance)
{
this.name = name;
this.suburb = suburb;
this.postcode = postcode;
this.credit_balance = credit_balance;
this.saving_balance = saving_balance;
}
public string Name
{
get { return name; }
set { name = value; }
}
public string Suburb
{
get { return suburb; }
set { suburb = value; }
}
public int Postcode
{
get { return postcode; }
set { postcode = value; }
}
public double Credit_Balance
{
get { return credit_balance; }
set { credit_balance = value; }
}
public double Savinig_Balance
{
get { return saving_balance; }
set { saving_balance = value; }
}
}
Please help me out, and let me know what the best way to go about this would be.
The first thing that you need to do is make your customers list have class level visibility so that you can access it in your button click events.
public partial class Form1 : Form
{
int index = 0;
List<Customer> customers = new List<Customer>();
public Form1()
{
... The remainder of your Constructor code
Once you do that you should be able to do something like this.
private void next_Click(object sender, EventArgs e)
{
if (index < customers.Count - 1)
{
index += 1;
textBox1.Text = customers[index].Name;
...
}
}
private void previous_Click(object sender, EventArgs e)
{
if (index > 0)
{
index -= 1;
textBox1.Text = customers[index].Name;
...
}
}
Using DataBinding ,and if you need to change the content of some field you could use the button to update or simply set the DataSourceUpdateMode as i do here to OnPropertyChange and every time you change the text in one of the textboxes it will update the datasource(in this case the List).You could define the Binding object seperatly then add it to the textbox.DataBindings so you could format and parse it,but here i just added them directly for demonstration purposes:
List<Customer> customers;
public Form1()
{
InitializeComponent();
//you could add the Customers directly to the add method of the list.
Customer c1 = new Customer("Sibel Yilmaz", "Wollongong", 2500, 3000, 5000);
Customer c2 = new Customer("John Doe", "Figtree", 2547, 2500, 3655);
Customer c3 = new Customer("Mariah Moore", "Coniston", 2500, 7000, 36000);
Customer c4 = new Customer("Jessica Blackshaw", "Bellambi", 3500, 6000, 4750);
Customer c5 = new Customer("Suzan Yilmaz", "Wollongong", 2500, 2000, 47110);
customers = new List<Customer>();
customers.Add(c1);
customers.Add(c2);
customers.Add(c3);
customers.Add(c4);
customers.Add(c5);
textBox1.DataBindings.Add("Text", customers, "Name",true,DataSourceUpdateMode.OnPropertyChanged);
textBox2.DataBindings.Add("Text", customers, "Suburb", true, DataSourceUpdateMode.OnPropertyChanged);
textBox3.DataBindings.Add("Text", customers, "Postcode", true, DataSourceUpdateMode.OnPropertyChanged);
textBox4.DataBindings.Add("Text", customers, "Credit_Balance", true, DataSourceUpdateMode.OnPropertyChanged);
textBox5.DataBindings.Add("Text", customers, "Savinig_Balance", true, DataSourceUpdateMode.OnPropertyChanged);
}
Then in your previous and next buttons:
private void PreviousBtn_Click(object sender, EventArgs e)
{
--this.BindingContext[this.customers].Position;
}
private void NextBtn_Click(object sender, EventArgs e)
{
++this.BindingContext[this.customers].Position;
}

Binded DataGridView to List<T> not showing data

This is the code I have (it a very simple example):
public partial class Form1 : Form
{
List<Person> listPersons;
public Form1()
{
InitializeComponent();
listPersons = new List<Person>();
dataGridView1.DataSource = listPersons;
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length > 0)
{
Person p = new Person();
p.Name = textBox1.Text;
listPersons.Add(p);
}
}
}
class Person
{
public string Name { get; set; }
}
When you press the button, data IS added to the list, but it doesn't show up in the DataGridView. What am I missing?
I have tried setting AutoGenerateColumns and VirtualMode to true, but that didn't resolve the issue either.
It's been awhile, and I've switched jobs since working on WinForms code that tried to bind List<T>s to DataGridViews. If I recall correctly, whatever you bind needs to implement IBindingList, which List<T> doesn't. I may be wrong on that.
In any case, what I used was BindingListView, which was incredibly fast and easy. You just do:
List<Customer> customers = GetCustomers();
BindingListView<Customer> view = new BindingListView<Customer>(customers);
dataGridView1.DataSource = view;
And you're done. I haven't looked at the source in a few years, but I believe it wraps the List<T> with a class that implements IBindingList.
But if I use only BindingList<T> instead of List<T> it does work.
Example code:
BindingList<Person> bl;
public Form1()
{
InitializeComponent();
bl = new BindingList<Person>();
dataGridView1.DataSource = bl;
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length > 0)
{
Person p = new Person();
p.Name = textBox1.Text;
bl.Add(p);
textBox1.Text = "";
textBox1.Focus();
}
}
But I would still like to figure out how to show data in DataGridView after bindng it with List.
Centralize your FillGrid functionality and call it when you want to update the grid
public Form1()
{
InitializeComponent();
listPersons = new List<Person>();
FillGrid();
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length > 0)
{
Person p = new Person();
p.Name = textBox1.Text;
listPersons.Add(p);
FillGrid();
}
}
private void FillGrid()
{
dataGridView1.DataSource = listPersons;
}
use array for binding datagridview ie
public partial class Form1 : Form
{
Person[] listPersons = new Person[0];
public Form1()
{
InitializeComponent();
dataGridView1.DataSource = listPersons;
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length > 0)
{
Person p = new Person();
p.Name = textBox1.Text;
Array.Resize<Person>(ref listPersons, listPersons.Length+1);
listPersons[listPersons.Length-1]=p;
dataGridView1.DataSource = listPersons;
}
}
}
class Person
{
public string Name { get; set; }
}
I don't think you can directly bind list to datagridview.
Instead use BindingList.
public partial class Form1 : Form
{
BindingList<Person> lstBinding;
public Form1()
{
InitializeComponent();
lstBinding = new BindingList<Person>();
dataGridView1.DataSource = lstBinding;
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length > 0)
{
Person p = new Person();
p.Name = textBox1.Text;
lstBinding.Add(p);
FillGrid();
}
}
private void FillGrid()
{
dataGridView1.DataSource = lstBinding;
}
}
class Person
{
private string name;
public string Name
{
get {return name;}
set { name = value; }
}
}
Try calling dataGridView1.Refresh(); after adding to the list.

Refresh a listbox's datasource

I have a form for my update method, the form is in detail view. Next to the textboxes I have a listbox which shows the names of all the names in the database table. Under the listbox I also have an extra textbox to quick search the name in case user would like to type it in.
When I go to update one of the names, such as changing John to Jonathan, the database updates with the new name as I have checked on sql server, but the name in the listbox does not change! There's a dirty way to fix this by moving the position the listbox is selected on currently to movefirst(). However, under the listbox I have the textbox which is a quick search as I've mentioned, so I go to type Jonathan in the search text box, but nothing appears. However, if I type the former name John, then I get the details of this row in the table.
Is there a way I can fix this?
UPDATE 1:
Ive tried making the listbox datasource null then reassigning it again but it doesen't work. Ive put my code for my update form below.
namespace WindowsFormsApplication1
{
public partial class updateContact : Form
{
public updateContact()
{
InitializeComponent();
}
private void updateContact_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'tblcontactsupdate.tblContacts' table. You can move, or remove it, as needed.
this.tblContactsTableAdapter.Fill(this.tblcontactsupdate.tblContacts);
}
private void btnUpdateContact_Click(object sender, EventArgs e)
{
int x;
Program.da.UpdateCommand = new SqlCommand("Update tblContacts SET FIRSTNAME = #FIRSTNAME, LASTNME = #LASTNME WHERE ID = #ID", Program.cs);
Program.da.UpdateCommand.Parameters.Add("#FIRSTNAME", SqlDbType.VarChar).Value = fIRSTNAMETextBox.Text;
Program.da.UpdateCommand.Parameters.Add("#LASTNME", SqlDbType.VarChar).Value = lASTNMETextBox.Text;
Program.da.UpdateCommand.Parameters.Add("#ID", SqlDbType.VarChar).Value = iDTextBox.Text;
Program.cs.Open();
x = Program.da.UpdateCommand.ExecuteNonQuery();
Program.cs.Close();
if (x >= 1)
{
MessageBox.Show("Record(s) has been updated");
Program.ds.Clear();
Program.da.Fill(Program.ds);
txtfindUpdatecontact.Text = "";
//lbupdateContact.DataSource = null;
//lbupdateContact.DataSource = this.tblcontactsupdate.tblContacts;
}
}
private void txtfindUpdatecontact_TextChanged(object sender, EventArgs e)
{
if (!txtfindUpdatecontact.Text.Equals(""))
{
this.tblContactsBindingSource.Filter = "FIRSTNAME = '" + txtfindUpdatecontact.Text + "'";
}
else
{
this.tblContactsBindingSource.RemoveFilter();
}
}
private void lbupdateContact_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void iDTextBox_TextChanged(object sender, EventArgs e)
{
}
private void fIRSTNAMETextBox_TextChanged(object sender, EventArgs e)
{
}
private void lASTNMETextBox_TextChanged(object sender, EventArgs e)
{
}
}
}
You will have to set the DataSource of your listbox one more time after updating the source.
Something like below: It's my data:
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
}
public class MyDataSource
{
public static List<Person> Persons = new List<Person>
{
new Person{Age=30,Name="Ram"},
new Person{Age=33,Name="Rahim"},
};
}
then in the form's constructor you can do:
listBox1.DataSource = MyDataSource.Persons;
listBox1.DisplayMember = "Age";
then for updation, something like below:
private void button1_Click(object sender, EventArgs e)
{
MyDataSource.Persons[0].Age = 45;
listBox1.DataSource = null;
listBox1.DataSource = MyDataSource.Persons;
listBox1.DisplayMember = "Age";
}
This is just an example change code according to your need.
If your DataSource is a DataTable, all you have to do is calling AcceptChanges(), like this:
listBox.DataSource = null;
((DataTable)listBox.DataSource).AcceptChanges();

Categories

Resources