Auto populating text box based on DGV selection - c#

I have a DGV that has data populated through a .json file. When I click on a cell/row I would like to grab the data from the active row to populate a number of textboxes dynamically.
Edits to explain:
below is showing that I did indeed have my text bound to the dataset as Caius had shown me on previous question.
and a bit of code to show that the datagridview is linked to dataset datatable
//json file holding all data to be parsed.
string myDynamicJSON = File.ReadAllText(#"testLibrary.json");
//the data
ToolJson ToolData = JsonConvert.DeserializeObject<ToolJson>
(myDynamicJSON);
//DataTable with something in it, do the binding
BindingSource SBind = new BindingSource();
SBind.DataSource = tooldataSet.Tables["Tool"];
//looks into File finds json fields, and assign them to
variables to be used in C# to create the rows.
foreach (var datum in ToolData.datum)
{
string description = datum.Description;
string vendor = datum.Vendor;
double cost = datum.Cost;
string serial = datum.ProductLink;
string employee = datum.employee;
string location = datum.location;
bool returntool = datum.returnTool;
int onHand = datum.onHandQty;
int stockQty = datum.stockQty;
int orderQty = datum.orderQty;
string toolType = datum.Type;
double diameter = datum.Geometry.Dc;
double OAL = datum.Geometry.Oal;
string productID = datum.ProductId;
//Populate the DataTable with rows of data
DataRow dr = tooldataSet.Tool.NewRow();
// Fill the values
dr["Description"] = description;
dr["Vendor"] = vendor;
dr["Cost"] = cost;
dr["Serial #"] = serial;
dr["Employee"] = employee;
dr["Location"] = location;
dr["OnHand"] = onHand;
dr["StockQty"] =stockQty;
dr["OrderQty"] = orderQty;
dr["Return"] = returntool;
dr["Diameter"] = diameter;
dr["OAL"] = OAL;
dr["Type"] = toolType;
dr["Product Id"] = productID;
//once all data is added to the row, add the row, and loop
untill all data is loaded.
tooldataSet.Tool.Rows.Add(dr);
}
//bind our dataset.table to the gridview
toolDataGridView.DataSource = SBind;
transactionEmployee_Box.Text = "";
transactionSerial_Box.Text = "";

I have found my own answer. The closest i had gotten to getting this accomplished was,
active_Description.text = Convert.ToString(toolDataGridView.CurrentRow.Cells[2]);
but I never realized I can add .value to the end of that and it works just fine.
active_Description.text = Convert.ToString(toolDataGridView.CurrentRow.Cells[2].Value) is what I needed.

I have misc. textboxes in my main form binded
Humor me; it'll take about 2 minutes to do this:
make a new winforms .net framework project
add a DataSet type file to it, open it
right click in the dataset surface and add a datatable
add two columns to the table
switch to the form designer
open the data sources window (view menu >> other windows)
expand every node in the data sources window
drag the table node to the form
drag the two column nodes to the form
run the app, bash 3 rows of data into the dgv with any random test data
click randomly up and down the rows, and see the textboxes change..
..that's data binding!

Related

Problem with format in C# with DataGridView and TextBox

I have a problem with format in C#.
I have a DataGridView and a TextBox. In this datagridview, there is a column: the single price (format int).
I want sum every elements of single price's column and insert the result into this textbox, but Visual Studio gives me a problem with format of string input ("Format of input's string is not correct").
this is the code than i used:
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
TOT = TOT + Convert.ToInt32(dataGridView3.Rows[i].Cells[6].ToString());
}
textBoxTot.Text = Convert.ToString(TOT);
Can you help me with this bad error?
UPDATE:
I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
If your datagridview is showing a datatable (I.e. your data is stored in a datatable) you can add a DataColumn to the datatable whose .Expression property is set to the string "SUM([Price])", where Price is the name of your numeric datatyped column holding the price info.
Now every row in the table will have the sum of the prices (the same value over and over again), so if you want to databind your textBox to this new column then it will always show the sum no matter which row is the current row (because all rows have the same value). It will also auto update without you having to do anything!
And if you're not using databinding to a datatable, I recommend that you do do it, because it represents good MVC practice of keeping your data in one thing (DataTable) and showing it in another (DataGridView) and keeping these concerns separate
It would look something like this, as a quick example:
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Price", typeof(int));
dt.Columns.Add("CalculatedTotal", typeof(int)).Expression = "SUM([Price])";
dt.Rows.Add("Apples", 100);
dt.Rows.Add("Oranges", 200);
BindingSource bs = new BindingSource();
bs.DataSource = dt;
WhateverDataGridView.DataSource = bs;
totalTextBox.DataBindings.Add(new Binding("Text", bs, "CalculatedTotal", true));
Here we have a data model (the datatable) where we keep our data. It has a couple of things we can set directly, and an third column that calculates based on the existing prices in all the table. If you look at this in the datagridview (assuming you have autogeneratecolumns turned on) you'll see that both rows have 300 for the CalculatedTotal, but they have individual amounts for price. There is a device called a BindingSource that sits between the datatable and the UI controls; you don't have to have one but it makes certain things easier regards updating controls when the data changes, and it maintains a concept of "current" - essentially whatever the current row is you're looking at in the datagridview; it all helps to avoid having to ask the DGV for anything - we just let the user type into the DGV, and it shows the data out of the datatable. All our dealings can be with the datatable directly - if you wrote a button to loop through the table and double all the prices, the controls in the UI would just reflect the change automatically. The textbox is connected to the CalculatedValue column via databinding; whatever the current row is, the textbox will show the CalculatedValue. Because the CalculatedValue column has the same value on every row, and they always all update if any price changes, the total textbox will always show the total. Add another textbox bound to Name to see what I mean; as you click around the grid and select different rows to be the "Current" row, the Name will change but the total does not. In truth it is actually changing in the same way that Name is, it's just that because the actual numeric value is the same on every row the contents of the textbox look like they don't change
UPDATE: I think that the problem now is another. I can't find the methods of MySql.Data.MySqlClient library that it can give me the result of query.
public string sommaFattura(String costo)
{
MySqlCommand command = new MySqlCommand();
String sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
command.CommandText = sumQuery;
command.Connection = conn.getConnection();
command.Parameters.Add("#prezzo", MySqlDbType.Int32).Value = costo;
conn.openConnection();
conn.closeConnection();
}
How is the command that give me the result of sumQuery. If i find this command, i can take the result of query and paste in textbox
It is weird that you are first converting to a string and then to an int.
int TOT = 0;
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
if (!dataGridView3.Rows[i].IsNewRow &&
int.TryParse(dataGridView3.Rows[i].Cells[6].Value.ToString(), out int v))
TOT += v;
}
textBoxTot.Text = TOT.ToString();
EDIT: Edited for your updated question. You shouldn't ask question inside a question buy anyway:
string sumQuery = "SELECT SUM(`prezzo`) FROM `fatturetemp`";
decimal total = 0M;
using (MySqlConnection cn = new MySqlConnection(" your connection string here "))
using (MySqlCommand cmd = new MySqlCommand(sumQuery, cn))
{
cn.Open();
total = Convert.ToDecimal(cmd.ExecuteScalar());
cn.Close();
}
Console.WriteLine(total);

updating existing row in a DataTable

iam developing a invoice program
in invoice form i have textboxes and a datagridview
here is my sample code
DataTable dt = new DataTable();
dt.Columns.Add("productCode");
dt.Columns.Add("qty");
dt.Columns.Add("price");
dt.Columns.Add("total");
string prodCode = txtProductCode.Text;
decimal qty = Convert.ToInt32(txtQty.Text);
decimal price = Convert.ToInt32(txtPrice.Text);
decimal total = qty*price;
dt.Rows.Add(prodCode,qty,price,total);
dataGridView1.DataSource = dt;
what i want to do is if i add same prodCode again i want to update qty and total in existing row instead of add new row
Using strongly typed datasets would make parts of this easier (Actually, they nearly always make all work with datatable and dataset easier; I would use them by default)
I would perform the following steps:
Add a DataSet to your project
Add a table to it (open it in the visual designer, right click the surface, add a datatable)
Add your columns to the table and choose their data types (string, decimal etc) - right click the datatable and choose "add column"
Right click the prodCode column and set it to be the primary key
Set the Expression property of the Total column to be [Qty] * [Price] - it will now auto-calculate itself, so you don't need to do the calc in your code
In your code:
string prodCode = txtProductCode.Text;
decimal qty = Convert.ToInt32(txtQty.Text);
decimal price = Convert.ToInt32(txtPrice.Text);
//does the row exist?
var ro = dt.FindByProdCode(prodCode); //the typed datatable will have a FindByXX method generated on whatever column(s) are the primary key
if(ro != null){
ro.Price = price; //update the existing row
ro.Qty += qty;
} else {
dt.AddXXRow(prodCode, qty, price); //AddXXRow is generated for typed datatables depending on the table name
}
If you have a back end database related to these datatables, you life will get a lot easier if you connect your dataset to the database and have visual studio generate mappings between the dataset and the tables in the database. The TableAdapters it generates take the place of generic DataAdapters, and manage all the db connections, store the SQLs that retrieve and update the db etc.
You can use DataTable.NewRow() method to have a reference to the new row.
var rowNew = dt.NewRow()
...
dt.AddRow(rowNew);
Prefer using strong typed DataTable if the schema is not generated at runtime.
Also you can find an existing row using:
int found = -1;
for (int index = 0; i < dt.Count; index++)
{
if ( !condition ) continue;
found = index;
break;
}
Or use the Find() method.
You can loop the whole datagridview rows and check if there is existing row with same new row product code, if yes update the columns you want of this row. This is not tested but something like this:
string prodCode = txtProductCode.Text;
decimal qty = Convert.ToInt32(txtQty.Text);
decimal price = Convert.ToInt32(txtPrice.Text);
decimal total = qty*price;
bool isRowExist = false;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (row.Cells[0].Value.ToString().Equals(prodCode))
{
var totalQty = Convert.ToInt32(row.Cells[1].Value.ToString()) + qty ;
var updateTotal = Convert.ToInt32(row.Cells[3].Value.ToString()) + total ;
row.Cells[1].Value = totalQty;
row.Cells[3].Value = total;
isRowExist = true
}
}
if(!isRowExist)
dt.Rows.Add(prodCode,qty,price,total);

ComboBox Index Changed

Need to know: I am working with Windows Forms in Visual Studio and C#.
I have 5 comobobox's that I populate from SQL with the parts available in the DB. Part of the coding to it, one uses a DataTable and set the DataSource of the comboBox to that DataTable.
In this same DataTable via my SQL query, I have listed the cost of the part in the list. What I want to do is whichever part you pick from the dropdown list, the related price must show in the textbox next to it.
I am trying to use the comboBox1_SelectedIndexChanged for this, but the problem I run into is as soon as the DataSource gets set to the DataTable while the form's initial loading, it gets picked up as a Index change and the comboBox1_SelectedIndexChanged wants to run. But at this point in time, the SelectedIndex Value is null due to it still loading, causing it to give me a exception cast error.
how can I work around this?
DataTable SparePart = new DataTable() is declared outside the function to make it available as "public" so that the comboBox1_SelectedIndexChanged can access it.
Then I have this code to populate the comboBox:
//Read Status info from DB
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
and then I have this for the comboBoxFinJCSpares1_SelectedIndexChanged:
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
enter image description here
The solution is as easy as making one boolean variable and call it formLoaded.
Set it to false, then set it to true after the form loads.
Put your code for populating combobox inside if statement and that should do it
Cheers ~ ChenChi
demo:
//Read Status info from DB
if(formLoaded)
{
SqlDataAdapter SparePartReader = new SqlDataAdapter(SQLSparePartDropbox);
SparePartReader.Fill(SparePart);
comboBoxFinJCSpares1.DataSource = SparePart;
comboBoxFinJCSpares1.DisplayMember = "DisplayMember";
comboBoxFinJCSpares1.ValueMember = "PartID";
//Set Combox1 affiliated Cost value to cost textbox
int ComBo1PartID = (int)comboBoxFinJCSpares1.SelectedValue;
string CostPrice = (from DataRow dr in SparePart.Rows
where (int)dr["PartID"] == ComBo1PartID
select (string)dr["PartCost"]).FirstOrDefault();
textBoxFinJCCost1.Text = CostPrice.ToString();
}
Thanks guys, the "SelectedChangeCommitted" option suggested by Marcel Hoekstra solved my problem.

Search DataSet and Display Multiple Results(Rows) in TextBoxes

I would like to search my DataSet for a customer name, this name will occur more than once throughout the dataset, meaning there will be more than 1 result (multiple rows returned)
When my search button is clicked, form2 opens up, and in theory should display all rows containing the customer name, but how do I achive this?
I can get it to display 1 row without a problem, but how would I make it display all rows, and the data in textboxes.
At the moment I am using a foreach loop to fill text boxes with returned data, but this only takes data from 1 row within my DataSet.
Is there a way I can make my form auto generate textboxes and populate them will all the data from the array? When I run my query at the moment, it fills the textboxes on form2 with the last rotation of the foreach.
DB Sample
Appreciate any help
Adam
DataRow[] returnedRows;
returnedRows = ds.Tables["Table_Data_1"].Select("cust_name='" + searchFor + "'");
foreach (DataRow returned in returnedRows)
{
tbName.Text = returned[1].ToString();
tbAddress.Text = returned[2].ToString();
tbPhone.Text = returned[3].ToString();
tbMake.Text = returned[4].ToString();
tbModel.Text = returned[5].ToString();
tbReg.Text = returned[6].ToString();
tbYear.Text = returned[7].ToString();
tbParts1.Text = returned[8].ToString();
tbParts2.Text = returned[9].ToString();
tbParts3.Text = returned[10].ToString();
tbParts3.Text = returned[11].ToString();
}
The reason you're having just a single value appear is that you're setting the text of your text boxes to a new value for each row that you've selected. You could change your code to instead add to the Text in the the Textboxes:
tbName.Text += returned[1].ToString() + Environment.NewLine;
Or you could instead bind it to a DataGridView, which is designed to display tabular data. Assuming the DataGridView was named something like customerDataView,
returnedRows = ds.Tables["Table_Data_1"].Select("cust_name='" + searchFor + "'");
var newTable = returnedRows.CopyToDataTable();
BindingSource bindSource = new BindingSource();
bindSource.DataSource = newTable;
var customerDataView.DataSource = bindSource;
You can generate textboxes dinamicaly
Its something like this
foreach (DataRow returned in returnedRows)
{
TextBox txt = new TextBox();
txt.ID = "textBox1"; //generate id dinamically can be a count
txt.Text = returned[1].ToString();
form1.Controls.Add(txt);
}
The way you've implemented the loop override the data in each interation
I've improved the sample code from following this post
https://stackoverflow.com/a/2229040/5252904 answer provided by #rahul.

How to pass data from one datagrid to another,but with different number of columns

This is my fist time here so i'll do my best describing what's my problem:
I have one form, and on that form I have two datagrids,let's call them dg1 and dg2.
dg1 is connected to an mssql database via dataadapter,while dg2 is not!. Lets say I have in dg1 information about a product:
productID
description
price
In dg2 i have something we might call bill.
So in dg2 i have columns
billID
accountnumberID
productID
description
price
Quantity
As you may predict billID is primary key, all the other one are Foreign. Since dg1 is filled with data from database i want when user clicks on a row in dg1 to pass data to dg2, while other data from dg2 are need to be inserted somehow(that is my problem anyway).
I have in database table bill, but i want to pass data from one to another by celldoubleclickevent, and all that data to be stored in bill table in database.
public void loadData()
{
try
{
SqlConnection con1 = getConnection();
con1.Open();
SqlCommand com1 = new SqlCommand();
com1.Connection = con1;
com1.CommandType = CommandType.Text;
com1.CommandText = "select * from bill";
SqlDataReader reader = com1.ExecuteReader();
dataGridView2.Rows.Clear();
while (reader.Read())
{
dataGridView1.AutoGenerateColumns = false;
dataGridView2.Rows.Add();
dataGridView2.Rows[i].Cells[0].Value = reader["billID"].ToString();
dataGridView2.Rows[i].Cells[1].Value = reader["acountnumberID"].ToString();
dataGridView2.Rows[i].Cells[2].Value = reader["productID"].ToString();
dataGridView2.Rows[i].Cells[3].Value = reader["Quantity"].ToString();
dataGridView2.Rows[i].Cells[4].Value = reader["Description"].ToString();
dataGridView2.Rows[i].Cells[5].Value = reader["price"].ToString();
i++;
}
}
Thx
There are several steps here.
First, you need to get the information from dg1. You can do that using the RowIndex property of the event args, although you'll need to check that the user didn't double click a header.
//This will depend on how the grid is bound
var dg1ProductID = GetProductID(dg1.datasource, e.RowIndex);
The body of this method could be quite simple
private void GetProductID(Int32 RowIndex)
{
return (Int32)(dg1.Rows[RowIndex].Cells[0]);
}
Second you'll need to put the information in dg2.
var newRow = dataGridView2.Rows.Add();
var bill = dataSet1.Tables[0].NewRow();
var accountNumber = GetCurrentAccountNumber();
var userQuantity = AskUserForQuantity();
dataGridView2.Rows[newRow].Cells[0].Value = -1;
dataGridView2.Rows[newRow].Cells[1].Value = accountNumber;
dataGridView2.Rows[newRow].Cells[2].Value = dg1ProductID;
dataGridView2.Rows[newRow].Cells[3].Value = userQuantity;
dataGridView2.Rows[newRow].Cells[4].Value = dg1Description;
dataGridView2.Rows[newRow].Cells[5].Value = dg1price;
Since the bill id is the primary key I assume it's automatically filled in.
Third you want to save the data to the bill, not sure if you want to do this in the double click event or a seperate button click event (like when the user hits OK).
If you are doing it in the double click then just pass the same values just added to a method to save them to the db.
Save(accountNumber, dg1ProductID, userQuantity, dg1Description, dg1price);
If not then you can enumerate the data and save from the Cell values
foreach(DataGridViewRow Row in dg2.Rows)
{
if (Row.Cells[0] == -1)
{
Save(Row.Cells[1], Row.Cells[2], Row.Cells[3], Row.Cells[4], Row.Cells[5]);
}
}

Categories