Add new rows to a gridview before submit to database - c#

Good afternoon,
I'm developing a form to place orders online.
I get the article from a combobox and get the details of that article using a sql query. So far, so good.
I put that article to a gridview. For one article, it's all ok.
I make the selection of the article, click on insert button, and the article with the details is inserted on the gridview.
My problem is on how to add more rows. When i click the insert button, with a different article and details, i only get one row, with overwritten data.
After all rows are in the gridview, i finally can submit that rows and process the order.
What should i use to add so many rows as i need? ViewState? Session State?
I read some articles, but none of them helped me as i needed.
Thank you.
EDIT:
I use a datatable to store the data.
DataTable DT = new DataTable();
DT.Columns.Add("Artigo");
DT.Columns.Add("Descricao");
DT.Columns.Add("IVA");
DT.Columns.Add("PU");
DT.Columns.Add("UN");
DT.Columns.Add("Qtd");
DT.Columns.Add("TotalLiq");
try
{
int Qtd = Convert.ToInt32(Quantidade.Text);
int PrecoUnit = glb._precolente;
float TotalLiq = Qtd * PrecoUnit;
string str = "SELECT TOP 1 A.Artigo as Artigo, A.Descricao as Descricao, (SELECT Taxa FROM prisalviani.dbo.Iva WHERE Iva = A.Iva)AS IVA, A.UnidadeBase as UN FROM prisalviani.dbo.ARTIGO A where A.Artigo='" + result.ToString() + "'";
ListaLentes = Motor.Consulta(ref str);
while (!ListaLentes.NoFim())
{
DT.Rows.Add(ListaLentes.Valor("Artigo"),
ListaLentes.Valor("Descricao"),
ListaLentes.Valor("IVA"),
PrecoUnit,
ListaLentes.Valor("UN"),
Qtd,
TotalLiq
);
ListaLentes.Seguinte();
}
}
catch (Exception ex)
{
Response.Write(ex.Message);
}

the description you have given is a bit vague, what kind of data structure are you using to hold the order rows? do you want to implement something similar to a shopping basket?
you can implement your own business entities or use a dataset/datatable to hold the new records, you can the keep these objects in the Session.
does it help a bit?

Assuming that your datagridview holds 3 cells of type String,
You can use:
object [] row1 = new object[] { "StringInCell1","StringInCell2","StringInCell3" }
dataGridView.Rows.Add(row1);
And if you need to edit a specific cell you can do it using:
dataGridView.Rows[rowIndex].Cells[cellIndex].Value = "newValue";

Related

DataAdapter_RowUpdated Event's row changes aren't reflected in DataSet and DataTable

My situation involves batch updates to individual tables in an SQLite database through ADO.NET objects. I use the DataAdapter.Update() method to push the changes which works well:
DataTable changes = dataset.Tables[table].GetChanges();
if (changes == null) return 0;
SQLiteCommandBuilder scb = new SQLiteCommandBuilder(adapter);
scb.ConflictOption = ConflictOption.CompareRowVersion;
int cnt = adapter.Update(changes);
return cnt;
However each time a record is inserted I also want the local DataSet tables to reflect with the newly inserted row id. For this I use the adapter_RowUpdated event :
static void adapter_RowUpdated(object sender,
System.Data.Common.RowUpdatedEventArgs e)
{
if (e.StatementType == StatementType.Insert)
{
SQLiteCommand cmd = new SQLiteCommand("select last_insert_rowid();", conn);
e.Row["id"] = cmd.ExecuteScalar();
}
}
The above fetches last_insert_rowid() because I'm able to see it when I debug by putting a breakpoint. However, the assignment statement to e.Row["id"] isn't working. The id change isn't reflected in my original DataSet and DataTable objects. For example when I test the following value (N refers to the specific row index), it still has a DBNull value. What is going wrong here? How can I ensure that the specific row which just got inserted is updated with its corresponding id field value?
dataset.Tables["projects"].row[N]["id"];
After a little experimenting, I found the solution to this myself.
As strange as it may sound but it looks like adapter.Update() requires a dataset along with the actual table name in order for this to work. I was passing the table object (DataTable.GetChanges()) so far which did the job of updating the database but failed only in this particular scenario. The moment I did that, the inserted id started reflecting in rows all over the dataset!
//int cnt = adapter.Update(changes); // doesn't work
int cnt = adapter.Update(dataset, tableName); // works perfectly!
edit
Lo and Behold! It even works when I just pass the table like this instead of entire dataset. It was only causing problem when I was just passing the changes table (got from dataset.Tables[tableName].GetChanges()).
int cnt = adapter.Update(dataset.Tables[tableName]); // works perfectly!

Check duplicates before copying rows from one datagrid to another datagrid

Actually I am copying rows from one datagrid to another on DataGridView Double Click Event, and it's going well. The code is here:
//Void App
void AddProducts(int ProdID, string Name, string ProductCode, int RetailPrice, int SalePrice, string BrandName, string Category, int QTY)
{
string[] row = { Convert.ToUInt32(ProdID).ToString(), Name, ProductCode,
Convert.ToInt32(RetailPrice).ToString(), Convert.ToInt32(SalePrice).ToString(), BrandName, Category, Convert.ToInt32(QTY).ToString()};
dgViewProductsToSell.Rows.Add(row);
}
//Code
private void dgViewProducts_MouseDoubleClick(object sender, MouseEventArgs e)
{
string Name1 = this.dgViewProducts.CurrentRow.Cells["Name"].Value.ToString();
int ProdID = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["ProdID"].Value);
string Name = dgViewProducts.CurrentRow.Cells["Name"].Value.ToString();
string ProductCode = dgViewProducts.CurrentRow.Cells["ProductCode"].Value.ToString();
int RetailPrice = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["RetailPrice"].Value);
int SalePrice = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["SalePrice"].Value);
string BrandName = dgViewProducts.CurrentRow.Cells["BrandName"].Value.ToString();
string Category = dgViewProducts.CurrentRow.Cells["Category"].Value.ToString();
int QTY = Convert.ToInt32(dgViewProducts.CurrentRow.Cells["QTY"].Value);
AddProducts(Convert.ToInt32(ProdID), Name, ProductCode, Convert.ToInt32(RetailPrice), Convert.ToInt32(SalePrice), BrandName, Category, Convert.ToInt32(QTY));
}
How I can check duplicate entries before copying the rows? So the 2nd datagridview could avoid duplicate entries.
I'm going to start off with this scrappy test app:
Don't worry that it's a screenshot of code - that's just for information purposes of how it came to be that I generated a datagridview with some data in it. This is how do "do it properly" - you keep your data in a DataTable and you use a grid to show it
The next step: we are going to make a strongly typed dataset, datatable, set its primary key, put it on the form along with a datagridview it is bound to, and we are going to fill it uniquely by double clicking the existing grid. I modeled the existing grid more like you have done. In reality I would make BOTH these grids be based on a strongly typed data table, but I wanted to show you you didn't have to, and my advice for making a strongly typed datatable can fit in with your existing idea of stuffing data into a datagridview directly, until you're ready to change over
Add a new DataSet type item to your project. Right click the project, Add.. New Item:
Give it a nice name. Nothing worse than code full of Form1, DataSet1, GridView3, Button27
When it's added, double click it to open the design surface. Right click the surface and add a new datatable:
Give it a nice name, right click it repeatedly and add columns for all you want, Name, Code, Price etc:
Don't forget to give them a datatype too, so not everything is a string!
You said you want to be unique by name so.. Click in the grey bit next to Name so the row goes all blue, then right click and choose Set primary key
Save it all, close the dataset designer, go to the forms designer, click the VIEW menu, go to OTHER WINDOWS >> DATASOURCES. You can also press Shift+Alt+D
Open the DATA SOURCES panel, find the grid node of your datatable (whatever you called it) and drag it onto the form
A datagridview, connected to your custom datatable has appeared, together with some new things at the bottom. You can delete the bindingnavigator:
(and rename the dataset instance so it has a nicer name than xxxxDataSet1)
That's all the setup we need for now to set up the receiver datatable, and grid. Let's edit the event handler for the mouse double click. I jiggled things around a bit and added another feature as a demonstration, that if the row IS there we can update it, otherwise we add it:
private void _dataGridViewSrc_MouseDoubleClick(object sender, MouseEventArgs e)
{
//my source datagrid is bound to a datatable. I use this to retrieve the current row related
//to the row in the grid that was double clicked
DataRow sourceRow = (_dataGridViewSrc.CurrentRow.DataBoundItem as DataRowView)?.Row;
if(sourceRow == null)
return;
//because we made Name the primary key, the strongly typed datatable has a FindByName method
//we pass it the string Name from the source datatable row (a grid row cell value in your case)
NiceNameDataSet.UniqueProductsRow destRow = _niceNameDataSet.UniqueProducts.FindByName((string)sourceRow["Name"]);
//FindByName returns NULL if the row wasn't found
if(destRow == null)
{
//the row isn't there, so add it, using the data from the source row
_niceNameDataSet.UniqueProducts.AddUniqueProductsRow(
(string)sourceRow["Name"],
(string)sourceRow["Code"],
(double)sourceRow["Price"]
);
} else
{
//the row IS there, how about we update the fields using the row that was just clicked?
//this demonstrated how much nicer it is to work with a strongly typed dataset/datatable
//because all the columns have proper Properties, like row.Code, with proeprt datatypes
//like string and double, rather than having to be referred to with a string name like
//row["Code"] and having to be cast from object to string, double all the time: messy
//and error prone
destRow.Code = (string)sourceRow["Code"];
destRow.Price = (double)sourceRow["Price"];
}
}
I changed the prices and codes a bit to demo this other featuer. Now you can double click either bread row as much as you like and you only get one row in the destination grid, and it changes its values back and forth:
You can create an object which represents each row with properties for each column. For this object you can create an public bool Equals(object obj) method.
With the object you can compare already read objects with newly read objects. Either manually or by using something Contains or similar methods which are part of List<> and Dictionary<> classes.
It all depends on how much data you have and which line you consider to be equal to another line. Is it equal / a collision if the product ID is a duplicate or do all properties also have to match
Each row should have a primary key, usually an ID. I am assuming this is the case for you.
Second assumption: both datagridview controls are bound to datatables/datasets or binding sources.
So, when the user selects a row in the grid, retrieve the underlying datarow. This can be done using the databounditem function. Then you can fetch the ID or primary key.
Then compare the two datatables. This is more efficient and safer than accessing UI controls. There are different ways to check that a record already exists in a datatable, for example the select function. Another option is using LINQ.
Do not try to update the second datagridview directly, instead you add a record to its underlying datatable, and you let the datagridview update itself.
Your code seems to be unsafe. What happens if the user double-clicks on the edges of the grid ? The current row could be -1. You need to add a check.
You should also test what happens if the user sorts the columns in the datagrid or drag the columns to change the display order.
To sum up I strongly advise to use datatables, even if you are not reading from or saving to database.
You can use the following code to remove duplicate entries before copying the datagridview.
Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Id");
table.Columns.Add("Age");
table.Rows.Add("test1",1001,22);
table.Rows.Add("test1", 1001, 22);
table.Rows.Add("test2", 1002, 23);
table.Rows.Add("test3", 1003, 24);
dataGridView1.DataSource = table;
}
private void dataGridView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
DataTable dt = (DataTable)dataGridView1.DataSource;
dt = dt.DefaultView.ToTable(true);
dataGridView2.DataSource = dt;
}
}
Result:
I don't know if I correctly understand your question but maybe this will help
before adding into my gridview I already checked the possibility of duplicate
//Validate duplicate data b4 adding to gridview
for (int i = 0; i < dataGridView2.Rows.Count; i++)
{
if (textBox1.Text == dataGridView2.Rows[i].Cells[1].Value.ToString())
{
MessageBox.Show("Product already on the list, if you wish to add this product click the product name and edit the quantity", "System Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
textBox1.Text = "";
textBox2.Text = "";
textBox1.Focus();
return;
} else { }
}
then pass the datagridview1(form1) to datagridview2(form2)
List<PurChaseRcpT> cdgv = new List<PurChaseRcpT>();
foreach (DataGridViewRow Item in dataGridView2.Rows)
{
cdgv.Add(new PurChaseRcpT {
Particular = Item.Cells[0].Value.ToString(),
Qty = Item.Cells[2].Value.ToString(),
UM = Item.Cells[3].Value.ToString(),
Price = Item.Cells[4].Value.ToString(),
Total = Item.Cells[5].Value.ToString()
});
}
FrM_SubChange ChangeFrm = new FrM_SubChange();
ChangeFrm.dataGridViewPassed = this.dataGridView2;
ChangeFrm.TempVal = cdgv;
ChangeFrm.Show();
hope it help..

C# Manually added dataset, how to retrieve data to text columns

I have added a dataset to the solution (Windows Form) by "Add"-> New item ->DataSet & created a new tableadapter query that fetches desired data against passed parameter in the design time.
Now I want to assign the data filled in the tableadapter to few textboxes while a button is clicked.
How I can achieve this?
I think I found an answer specific to my situation. I am not sure whether it is the best or the standard, as I am not getting much help with searches, I am accepting my own finding as a solution.
private void getnameid2()
{
PersonDataSet newPersonDataSet = new PersonDataSet(); //PersonDataSet is the manually created dataset
PersonDataSetTableAdapters.L_PEOPLETableAdapter newPersonDataSetTableAdapter = new PersonDataSetTableAdapters.L_PEOPLETableAdapter();
DataTable mytable = new DataTable();
mytable = newPersonDataSetTableAdapter.GetData(decimal.Parse(this.civilidTextbox.Text.ToString()));
//foreach (DataRow row in newPersonDataSetTableAdapter.GetData(decimal.Parse(this.civilidTextbox.Text.ToString()))
foreach (DataRow row in mytable.Rows)
{
nameTextBox.Text = row["FIRST_NAME"].ToString();
personidTextBox.Text = row["PERSON_ID"].ToString();
}
// if (mytable.Rows.Count > 0) { MessageBox.Show(mytable.Rows.Count.ToString()); }
}
Now I am calling the procedure while cell is validating to avoid the already saved transactions being updated while browsing the records, I am checking the transaction id column and calling a return to avoid.
Hope this helps someone else out there or brings the attention of experts who can device better approach :)

c# - DataSet and DataGridView

I have made a basic program to add values to a dataSet and display it to a dataGridView:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DataTable table1 = new DataTable("People");
table1.Columns.Add("id");
table1.Columns.Add("Name");
table1.Columns.Add("Age");
table1.Rows.Add(1, "Jack", 18);
table1.Rows.Add(2, "Tim", 18);
DataSet set = new DataSet("SetPeople");
set.Tables.Add(table1);
dataGridView1.DataSource = set;
dataGridView1.Update();
}
}
When I try it out nothing seems to happen. The dataGridView remains blank. Any idea where I am going wrong?
try this
dataGridView1.DataSource = table1;
you don't need a Ds for just showing a data table in a Gridview
Massimiliano Peluso is correct. The GridView will reference a"Table", but more specifically, when using ADO.NET in a Disconnected fashion you will be filling the GridView with DataColumn objects that are part of a DataTable object. You will also want to bind your dataTable to the GridView.
A bit of Detail:
ADO.Net's DataSet construct allows you to represent your database in a "table" like manner and allow those tables to share references. All of this comes at the cost of additional memory overhead, but if this is not going to be a highly scalable applicaiton and you want to give the users the ability to edit rows without having to go to the database every time, DataSet is a good option.
If you are not using the featuers of DataSet (e.g. table relationships) you can save yourself a little overhead by just using DataTable objects and populating them.
To answer your questions:
A GridView expects to recieve a DataTable as a data source. That table can contain several columns (which will fill the columns of the grid). You can write the following code to specifically access your data table:
dataGridView1.DataSource = set.Tables["table1"]; // or by index if you prefer as there are several overloads.
Additionally, I would bind the data by adding the following line of code after the one perscribed above:
dataGridView1.DataBind();
The fact you are missing your DataBind() method call is part of your issue.
There is a very good example at C sharp corner site: Example
You could also do this:
dataGridView1.DataSource = set;
dataGridView1.DataMember = set.Tables["People"].TableName;
dataGridView1.Update();

Filling a DataTable based on row values in a DataSet

I want to show some news posts on the front page of a website. The news have different categories but are stored in the same mysql database. All news items are loaded into a dataset but from there I just want to extract some specific news and show them in a ListView control.
At the moment I'am using the workaround solution of using a foreach loop on the dataset and formatting the result with html in the code behind. It works but I want all html formatting to be done in the aspx file, thus I'am looking for a better solution.
DataSet articles = db.loadAllArticles();
foreach (DataRow item in articles.Tables["articles"].Select("category = 1"))
{
result += "<h1 class='headline'>" + item["headline"] + "</h1><h2 class='introduction'>" + item["introduction"] + "</h2><p class='content'>" + item["content"] + "</p><p class='authorAndDate'>" + item["author"] + " " + item["datePosted"].ToString().Substring(0,10) + "</p><br/>";
}
lblDisplay.Text = result;
What I was hoping I could do was simply something like this:
DataSet articles = db.loadAllArticles();
ListView1.DataSource = articles.Tables["articles"].Select("category = 1");
ListView1.DataBind();
But the ListView control is not too happy about trying to bind DataRow to it or something.
The best workaround I can think of is to create a new Table within the "articles" DataSet which contains only articles of the chosen category, so something like this:
DataSet articles = db.loadAllArticles();
articles.Tables.Add("frontPageArticles");
articles.Tables["frontPageArticles"] = ???
And then thats where it stops. How can I fill the new datatable with rows from the other datatable where the value of a column is x?
-Eric.
You should be looking at binding you ListView to a DataView, it is filterable and sortable.
You can design your web form using control like repeater, datalist etc. and can bind these control to your datatable on codebehind.
An example can be found here

Categories