I've built a frontend to update an individual column for selected records in a GridView. I've gotten that all setup the way that I want it to work including performing a check to be sure that more than one row is selected (via a template field checkbox I added to the GridView) and that a column has been selected from a dropdown list.
I have everything down to the block of code that has to be built to do the actual update of the column for the selected rows. This will cycle through each row, so if I've selected 5 rows it would trigger this code 5 times and update the record ID associated with that row.
I'm mainly debating with myself which would be the simplest to build into this. I at first thought about doing a stored procedure on the SQL Server and feeding it the record ID, column to update, and the value to write in the update. But then I got to thinking about it and realized that I have a GridView with a Data Source that was already setup to update the record as long as I called it
In either case I'll need to refresh the GridView after the update has been completed.
Just wondering what others might think would be the cleanest approach to this and just what my options might be. I've never seen a multi row column edit implemented so figure someone may have a better idea than me on how to go about this.
Here is my code block for the update as it is right now...
protected void SaveColEditBtn_Click(object sender, EventArgs e)
{
//Read the column select drop down List into Local Varriables
String SelectedColumnItem = ColumnSelectDDL.SelectedItem.ToString();
String SelectedColumnValue = ColumnSelectDDL.SelectedValue.ToString();
List<int> EditRows = new List<int>();
List<string> recordnumber = new List<string>();
foreach (GridViewRow grv in ActVulListGV.Rows)
{
if (((CheckBox) grv.FindControl("TagRowChkBx")).Checked == true)
{
//get current row rowindex if checkbox in it is checked
EditRows.Add(grv.RowIndex);
//get the record number (RecID)
recordnumber.Add(grv.Cells[2].Text.ToString());
}
}
int[] ERows = EditRows.ToArray();
if (recordnumber.Count > 1)
{
if (ColumnSelectDDL.SelectedValue.ToString() == "TicketNumber")
{
// Save Ticket number //
}
else if (ColumnSelectDDL.SelectedValue.ToString() == "TicketClosed")
{
// Save Ticket Closed Value //
}
else if (ColumnSelectDDL.SelectedValue.ToString() == "Notes")
{
// Save Notes //
}
else if(ColumnSelectDDL.SelectedValue.ToString() == "Exception_ID")
{
// Save Exception ID //
}
EditColMsgLbl.Font.Bold = true;
SelectedRowsMsgLbl.Font.Bold = true;
ColEditPnlExt.Show();
EditColLbl.Text = SelectedColumnItem;
SelectedRowsLbl.Text = "";
foreach (string record in recordnumber)
{
// Insert the call of the procedure here to update the database
}
}
else
{
UserMessageLbl.Text = " *** Choose 2 or more rows to use column edit feature! ***";
mpePopUp.Show();
}
}
It depends. If you are updating all at once, by looping, use a Stored Procedure. However updating one by one with EditIndex, it is easier to use the source. However I would recommend using code behind and a SP to update a row, then you could use the same SP for updating a single or all rows.
See this excellent tutorial. It covers all the basics of GridView editing and updating.
And a tip if you have some time to spare in the near future, try to disable ViewState for the GridView. It will save a lot of tranfer kb's and overhead. But get the above to work first ;)
Related
I'm creating a windows form that will allow my group at work to check in & out computers from our spare cabinet. I have two tables, an 'Assets' table & Inventory Log table. The user will fill out the GUI and select the asset they want from the check out screen. The problem I am having is trying to pass the foreign key 'InventoryID' to the log table. I have the main textbox's bound to datagrid cells but I am unable to do this with the inventory ID because I have it bound to a textbox so the user does not have to enter it every time.
I have tried creating an insert query that takes the textbox and converts it to int and then inserts it into the method but it catches an exception. Note, this query works when I test it in the query builder. I have also tried adding it with the binding source property but it cant find the index.
private void BtnSubmit_Click(object sender, EventArgs e)
{
//get asset number
string asset = txtAssetNumber.Text;
//get invID from textbox
int InventoryID = Convert.ToInt32(txtinv.Text);
//this query changes available status to 'No'
inventoryTableAdapter.SetNo(asset);
//runs query to determine what rows have 'Yes'
inventoryTableAdapter.Available(this.loanerCabDataSet.Inventory);
try
{
//add new row to log table
inventoryLogBindingSource.AddNew();
//suppose to insert the ID into table
inventoryLogTableAdapter.insertinvid(InventoryID);
//set textbox back to today's date
txtOutDate.Text = DateTime.Today.ToString("MM/dd/yyyy");
this.Validate();
this.inventoryBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.loanerCabDataSet);
MessageBox.Show("Success");
}
catch (Exception)
{
throw;
}
}
Query:
INSERT INTO InventoryLog (InventoryID)
VALUES (?)
Finally figured out a way around it.
Created insert query and instead of binding all of the textboxes to the column, I created variables and passed them into the function.
Heres what it looks like now.
inventoryLogTableAdapter.Insert(InventoryID, customer, tech, loaneddate, datein, location, ticket, notes);
I have a dataGridView in which I can insert, delete and update values but something is bothering me.
The user can only modify the 2 columns that are displayed (size and quantity), 2 others are hidden (ID and chosenComponent).
ID is PK in my table.
This is what I did to set ID and chosenComponent of new rows :
private void dataGridViewStock_DefaultValueNeeded(object sender,
System.Windows.Forms.DataGridViewRowEventArgs e)
{
e.Row.Cells["id"].Value = "1";
e.Row.Cells["codeArticleComponent"].Value = labelComponentChosen.Text;
}
Whatever value I put for the ID, the first available number will be inserted to the database. It works but I'm afraid it might later cause bugs.
Is there a better way to achieve this ? Or can I leave it as is ?
You may need a separate column(Only in the GirdView) to identify whether the current row is newly added or existing one. And increment id column with negative values based on the new column.
While saving the data you can identify the newly created rows, based on that you can save the data by inserting without id column or update the existing data.
Hope this clarifies you.
This is my code for the auto-increment primary key in a datagrid view
private void Row_Added(object sender,
DataGridViewRowsAddedEventArgs e){
foreach(DataGridViewRow dtr in dataGridView1.Row){
dataGridView1.Rows[e.RowIndex-1].Cells[0].Value =
e.RowIndex;
}
}
i used this...
If I use OnAutoGeneratingColumn to cancel some columns that I don't necessarily want to generate, will it affect the number of columns in Table.Columns.Count?
Context
I'm iterating through a table, row by row, taking each value and passing it through to an insert SQL command. Right now it lines up so that each entry is associated properly. Will I disrupt this with e.cancel? Will row[1] no longer point to what it once did if row[0] was e.cancel'd?
for (int i = 0; i < table.Dummy.Columns.Count; i++)
{
// if we're past our first entry, add room for the next before entering it
if (i != 0)
{
InsertIntoTableQuery.AddIntPrm();
}
//if our column has an entry, add it into our table.
if (row[i] != null)
{
InsertIntoTableQuery.Prms[i].Val = row[i];
}
}
No! I figured out why I was erroring and this wasn't the cause. you can cancel column generation in the wpf datagrid without actually altering the table index's. In hindsight that's pretty obvious.
I have a data grid view with my table information in there. Just don't know how to know what the use selected. Then once I have that figured out how to get a value that is selected and run a query to my database with it.
My tables have a GUID and nothing really else to use to run queries off of. Should I use something else or is there a way to use the GUID to find and do querys on it?
Have you tried using the _SelectedIndexChanged event?
when using query's below change [GridViewName] to the ID of your gridview
to then get the row use.
GridViewRow row = [GridViewName].Rows[e.NewSelectedIndex];
then to get individual cell values you can then use.
row.Cells[1].Text;
to run a query with it I would recommend using the two like this.
void [GridViewName]_SelectedIndexChanged(Object sender, [GridViewName]SelectEventArgs e)
{
GridViewRow row = [GridViewName].Rows[e.NewSelectedIndex];
if (row.Cells[1].Text == "ABCDE")
{
//do database stuff here
}
}
If you want to run a query to get children add the PK of your database table to the gridview in the first Column. Then use below code to get the PK value and you will be able to run queries.
[GridViewName]_SelectedIndexChanged(Object sender, [GridViewName]SelectEventArgs e)
{
//gets the current selected row
GridViewRow row = [GridViewName].Rows[e.NewSelectedIndex];
// gets the the PK for running querys
string PKselectedRow = row.Cells[0].Text
}
Here is the Microsoft documentation on GridViewRow. http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridviewrow(v=vs.110).aspx
To whom this may concern, I have searched a considerable amount of time, to work a way out of this error
"Deleted row information cannot be accessed through the row"
I understand that once a row has been deleted from a datatable that it cannot be accessed in a typical fashion and this is why I am getting this error. The big issue is that I am not sure what to do to get my desired result, which I will outline below.
Basically when a row in "dg1" is deleted the row beneath it takes the place of the deleted row (obviously) and thus inherits the deleted rows index. The purpose of this method is to replace and reset the rows index (via grabbing it from the corresponding value in the dataset) that took the deleted rows place and as such the index value.
Right now I am just using a label (lblText) to try and get a response from the process, but it crashes when the last nested if statement trys to compare values.
Here is the code:
void dg1_Click(object sender, EventArgs e)
{
rowIndex = dg1.CurrentRow.Index; //gets the current rows
string value = Convert.ToString(dg1.Rows[rowIndex].Cells[0].Value);
if (ds.Tables[0].Rows[rowIndex].RowState.ToString() == "Deleted")
{
for (int i = 0; i < dg1.Rows.Count; i++)
{
if (Convert.ToString(ds.Tables[0].Rows[i][0].ToString()) == value)
// ^ **where the error is occurring**
{
lblTest.Text = "Aha!";
//when working, will place index of compared dataset value into rowState, which is displaying the current index of the row I am focussed on in 'dg1'
}
}
}
Thanks ahead of time for the help, I really did search, and if it is easy to figure out through a simple google search then allow myself to repeatably hate on me, because I DID try.
gc
You can also use the DataSet's AcceptChanges() method to apply the deletes fully.
ds.Tables[0].Rows[0].Delete();
ds.AcceptChanges();
The current value for the data column in the inner if statement will not be available for deleted rows. To retrieve a value for deleted rows, specify that you want the original value. This should fix your error:
if (Convert.ToString(ds.Tables[0].Rows[i][0, DataRowVersion.Original].ToString()) == value)
In your "crashing if", you can check if the row is deleted before accessing it's values :
if (ds.Tables[0].Rows[i].RowState != DataRowState.Deleted &&
Convert.ToString(ds.Tables[0].Rows[i][0].ToString()) == value)
{
// blaaaaa
}
Also, I'm not sure why you ToString() the RowState instead of comparing it to DataRowState.Deleted.
after deleting the row , rebind your grid with the datatable , no need to manually resetting index , datatable handels it.
so you onl;y need to rebind grid's datasource.