I posted this not long ago, but no I have to update the question to ensure I get the right answer.
I have a GridView. I need to update an SQL table based on values from the GridView.
When a user clicks the default EDIT button on the GridView, changes whatever they change, then hits UPDATE. Here is where I run into problems. I've tried multiple OnRowEditing, OnRowUpdating, OnRowUpdate as the button control.
Here is the code I use to that.
protected void gvReviewedPolicy_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DateTime dateTime = DateTime.Now;
//GridViewRow editRow = gvReviewedPolicy.Rows[gvReviewedPolicy.EditIndex];
//string Emailed = editRow.Cells[7].Text;
//string UniqClient = editRow.Cells[1].Text;
//string UniqPolicy = editRow.Cells[3].Text;
string UniqClient = gvReviewedPolicy.SelectedRow.Cells[2].Text;
string UniqPolicy = gvReviewedPolicy.SelectedRow.Cells[3].Text;
//string Email = Emailed.ToString();
//string dt = dateTime.ToString();
//string Up = UniqClient.ToString();
MessageBox.Show(UniqClient);
MessageBox.Show(UniqPolicy);
//MessageBox.Show(dt);
string query = "UPDATE [Reviewed_Renewal_Policy] SET [DateUpdated] = #dateTime where ([UniqClient] = #UniqClient) AND ([UniqPolicy] = #UniqPolicy)";
using (SqlConnection conn = new SqlConnection("Data Source=GTU-BDE01;Initial Catalog=TestDB;Integrated Security=True"))
{
using (SqlCommand comm = new SqlCommand(query, conn))
{
comm.Parameters.AddWithValue("#UniqClient", UniqClient);
comm.Parameters.AddWithValue("#UniqPolicy", UniqPolicy);
//comm.Parameters.AddWithValue("#Emailed", Emailed);
comm.Parameters.AddWithValue("#dateTime", dateTime);
conn.Open();
comm.ExecuteNonQuery();
conn.Close();
}
}
}
I have some commented out because I was trying different things. However, the code that says
GridViewRow editRow = gvReviewedPolicy.Rows[gvReviewedPolicy.EditIndex];
string Emailed = editRow.Cells[7].Text;
string UniqClient = editRow.Cells[1].Text;
string UniqPolicy = editRow.Cells[3].Text;
It's supposed to access the values in those cells when UPDATE button is pushed. However, using MessageBox.Show , comes back blank.
Anyone have any idea how I can capture those values after hitting Edit, then the default UPDATE button?
I've tried to make that Winforms Datagrid usable for "write through" in the past, by implementing an DataGridView subclass (this allows you to access everything) but since immutable databases and queue transactions came into view, my Access-flavour DataGrid did not survive modern paradigm. Nowadays I tend to support ASP.NET MVC 5 to "edit" databases.
Anyway have you considered to connect a DataSource ? You don't have to access cells.. you can update using a connection like
private SqlDataAdapter daGrid = new SqlDataAdapter();
and this type of approach, you will have to fill in the details yourself, the complete code consists of several classes and is too large to post,
protected void dataGridView1_KeyUp(object sender, KeyEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
/// .. perform actions according to keyboard events ..
/// .. for example below one ..
}
public override void UpdateAfterEditGrid(DataSet ds, DataGridView dataGridView1, bool DoRestoreCursor)
{
if (daGrid != null)
{
if (conn.State == ConnectionState.Closed) conn.Open();
dataGridView1.EndEdit();
try
{
if (ds == null)
{
//DataGridView dgv = dataGridView1;
//Console.WriteLine("Go datasource update .. " + dgv[cColumnIndex, cRowIndex].Value);
daGrid.Update((DataTable)dataGridView1.DataSource);
}
else daGrid.Update(ds);
LoadGridRestoreCursor(dataGridView1, DoRestoreCursor);
}
catch { ErrorReporting.ErrorMessage("== cannot update this content =="); }
}
}
Related
Goal:
My goal is to format 1 column to password characters *.
Resources I have tried:
I have used an example from here :
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datagridview.cellformatting?view=netframework-4.8
and tried this answer here:
https://stackoverflow.com/a/38074239/12485722
This is my current code to load DataGrid View:
private void Form3_Load(object sender, EventArgs e)
{
RefreshGrid();
}
//Refresh Data Grid from external Forms
public void RefreshGrid()
{
// MySQL connection string
using (var conn = new MySqlConnection(ConnectionString()))
{
using (var mySqlDataAdapter = new MySqlDataAdapter("select * from user", conn))
{
using (var dataSet = new DataSet())
{
DataSet DS = new DataSet();
mySqlDataAdapter.Fill(DS);
dataGridView1.DataSource = DS.Tables[0];
}
}
}
}
This simply loads up the DataGridView with Usernames and passwords.
Now I need to format 2nd column to password characters, so the passwords do not show as text but formatted as *.
I have tried adding this piece of code from the 2nd resource mentioned above:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == 1 && e.Value != null)
{
e.Value = new String('*', e.Value.ToString().Length);
}
}
This does not work - no errors show up, but I have noticed this references is set to 0.
(Note: this is what it should be)
Question:
I am confused where it is going wrong.. can somebody assist me to achieve this task?
Update (1) - Events and cell formatting not showing:
Your method is not wired to an event of GridView (thats why it has 0 references, because nothing is using your function).
The solution in the mentioned link is correct, but you should wire your method to an event in designer (right click on grid view > properties > events) and choose an event to fire up in CellFormatting event. Also dont forget to handle EditingControlShowing, but everything what you need is already written in a solution thread that you mentioned.
Why don't you modify your query to just say the below:
select username, repeat('*', length(password)) from users
I am currently working on a database system. In the system a user can search for a specific member using their ID. Searching for them filters all DataGridView results to just that specific member.
private void button3_Click(object sender, EventArgs e)
{
dataGridView1.ReadOnly = false;
using (SqlConnection con = new SqlConnection(constring))
{
int id = Convert.ToInt32(textBox1.Text);
con.Open();
DataTable FindAaron = new DataTable();
SqlDataAdapter adapt = new SqlDataAdapter("SELECT * FROM MembersTable WHERE MemberID =" + id, con);
adapt.Fill(FindAaron);
dataGridView1.DataSource = FindAaron;
con.Close();
}
}
This code filters the DataGridView results down to one row from the table 'MembersTable'. The user can now physically click on the table cell and edit the data as much as they want. Once they are finished they hit a 'Save Changes' button which I want to save the changes they made, update the source table and refill the DataGridView with all the members, now with updated info. This is the code I have behind the 'Save Changes' button at the moment.
try
{
//MemberClass.UpdateMember();
this.membersTableTableAdapter.Update(mainDatabaseDataSet.MembersTable);
dataGridView1.Refresh();
MessageBox.Show("Details updated");
}
catch
{
MessageBox.Show("An error has occured");
}
This unfortunately does not update the DataGridView in the form to display all the updated data or save the data that has been edited back to the Sql table. Have puzzled over this for a few days and can't figure out what I'm doing wrong. Any and all help is much appreciated.
Actually there is no connection seen between membersTableTableAdapter and adapt or mainDatabaseDataSet.MembersTable and FindAaron.
Try as following;
//Get the changed data
DataTable changes = FindAaron.GetChanges();
if (changes != null)
{
//Update data
adapt.Update(changes);
}
I am really stuck and non of the books or tread here are user-friendly enough to explain how to delete data from data grid object using C#
from varies of books and fourm threads I have managed to get this coded but it fails to executes the sql command , I have One table call 'SpellingList' and two columns one is ID and the other is Words, all I want to do is delete a row from the datagrid.
Can someone point me to the correct direction , once I solved this , I shall upload some basic easy to follow tutorial so the rest of the newbie can follow this example.
I have used this thread How to delete a selected DataGridViewRow and update a connected database table?
and MCSD Certificaiton Toolkit Exam 70-483 book Page 392 , all attempts have failed.
there is a catch 22 here if I comment out if(dataGridView1.SelectedRows.Count > 0) line , I get the index out of range error .
private void btnDelete_Click(object sender, EventArgs e)
{
// My SQL connectionString
SqlConnection myConnection = new SqlConnection("Data Source=Epic-LaptopWR;Initial Catalog=words;Integrated Security=True");
myConnection.Open();
foreach (DataGridViewCell oneCell in dataGridView1.SelectedCells)
{
if(dataGridView1.SelectedRows.Count > 0)
{
int selectedIndex = dataGridView1.SelectedRows[0].Index;
// gets the RowID from the first column in the grid
int rowID = int.Parse(dataGridView1[0, selectedIndex].Value.ToString());
// your code for deleting it from the database
string sql = "DELETE FROM SpellingList WHERE Words =" + selectedIndex;
SqlCommand deleteRecord = new SqlCommand();
deleteRecord.Connection = myConnection;
deleteRecord.CommandType = CommandType.Text;
deleteRecord.CommandText = sql;
SqlParameter RowParameter = new SqlParameter();
RowParameter.ParameterName = "#Words";
RowParameter.SqlDbType = SqlDbType.Int;
RowParameter.IsNullable = false;
RowParameter.Value = rowID;
deleteRecord.Parameters.Add(RowParameter);
deleteRecord.Connection.Open();
deleteRecord.ExecuteNonQuery();
if (oneCell.Selected)
dataGridView1.Rows.RemoveAt(oneCell.RowIndex);
deleteRecord.Connection.Close();
wordsDataSet.GetChanges();
// booksDataset1.GetChanges();
spellingListTableAdapter.Fill(wordsDataSet.SpellingList);
}// end of if
// then your code for refreshing the DataGridView
}// end of for each statement
myConnection.Close();
}// end of delete Button
We could simplify a lot. And fix some evident bugs.
The ID field is the key field of your table and thus you should use it to find the row to delete, then, a parameter, to be useful, needs a parameter placeholder in the command text that you want to execute
private void btnDelete_Click(object sender, EventArgs e)
{
// No row selected no delete....
if(dataGridView1.SelectedRows.Count == 0)
return; // show a message here to inform
// Prepare the command text with the parameter placeholder
string sql = "DELETE FROM SpellingList WHERE ID = #rowID";
// Create the connection and the command inside a using block
using(SqlConnection myConnection = new SqlConnection("...."))
using(SqlCommand deleteRecord = new SqlCommand(sql, myConnection))
{
myConnection.Open();
int selectedIndex = dataGridView1.SelectedRows[0].Index;
// gets the RowID from the first column in the grid
int rowID = Convert.ToInt32(dataGridView1[0, selectedIndex].Value);
// Add the parameter to the command collection
deleteRecord.Parameters.Add("#rowID", SqlDbType.Int).Value = rowID;
deleteRecord.ExecuteNonQuery();
// Remove the row from the grid
dataGridView1.Rows.RemoveAt(selectedIndex);
}
}
As you can see, connections and commands are disposable objects and should be enclosed in a using statement to ensure proper closing and disposing also in case of exceptions.
Finally, removing the row from the grid should be done simply using the index of the row, removing the line in a single command. You don't need to loop over the cells to delete them one by one.
I would humbly like to thank Steve for his contribution , without guru's like him us newbies would have spent hours to end in trying to solve a simple yet complex problem.
Here is the working code with few modification that by passes the index out of bound error:
private void btnDelete_Click(object sender, EventArgs e)
{
// No row selected no delete....
if(dataGridView1.SelectedRows.Count == 0)
{
MessageBox.Show("No row selected !");// show a message here to inform
}
// Prepare the command text with the parameter placeholder
string sql = "DELETE FROM SpellingList WHERE ID = #rowID";
// Create the connection and the command inside a using block
using(SqlConnection myConnection = new SqlConnection("Data Source=Epic-LaptopWR;Initial Catalog=words;Integrated Security=True"))
using (SqlCommand deleteRecord = new SqlCommand(sql, myConnection))
{
myConnection.Open();
MessageBox.Show("The SQL Connection is Open");
// this overcomes the out of bound error message
// if the selectedRow is greater than 0 then exectute the code below.
if(dataGridView1.CurrentCell.RowIndex > 0)
{
int selectedIndex = dataGridView1.SelectedRows[0].Index;
// gets the RowID from the first column in the grid
int rowID = Convert.ToInt32(dataGridView1[0, selectedIndex].Value);
// Add the parameter to the command collection
deleteRecord.Parameters.Add("#rowID", SqlDbType.Int).Value = rowID;
deleteRecord.ExecuteNonQuery();
// Remove the row from the grid
dataGridView1.Rows.RemoveAt(selectedIndex);
}
}
}// end of delete Button
Please ensure that your datagrid property for SelectionMode is set to 'FullRowSelect' this as mention by Steve will populated with selected rows.
In additional to the above this is for the newbies , please ensure you have a Primary key set as ID with integer values ,in my first error I did not have any data in the primary key it was NULL with one field { Colum called Words} .
Within a week or so I shall post a step by step guide on how to create a simple database watch out for this space.
How do I use a LinqServerModeDataSource to insert or edit rows of the underlying data table when I do not show all fields of that table in the ASPxGridView?
Similar questions have been asked, but this is not a duplicate. For example, this one asks about a LinqServerModeDataSource and the accepted answer tells how to use an ordinary SqlDataSource.
I have an ASPxGridView hooked up to a table via a LinqServerModeDataSource. But I do not show all columns in the grid. For example, there are columns for the date created and some others that the user doesn't need to know about. I am allowing inline editing in the grid, but in the Inserting or Updating event, the new values passed are just a dictionary of the values displayed in the grid.
What about the other values? I would expect to be able to set any of the values for the underlying data row programmatically in the event handler, regardless of whether they are displayed and thus edited by the user. How do I get access to them and set the other values in the events of the LinqServerModeDataSource? I am having no luck reading the devexpress documentation.
I'm guessing that there must be a Linq class that hooks into the table that I can use in those events, similarly to the Selecting event. But how?
Here's what the Selecting event handler looks like... Is there not some similar interface I can use to access the underlying data in the other events?
protected void dsRecipients_Selecting(object sender, DevExpress.Data.Linq.LinqServerModeDataSourceSelectEventArgs e)
{
SmsRecipientsDataContext context = new SmsRecipientsDataContext();
IQueryable<NotificationParty> val = context.NotificationParties;
int notificationGroupID = Convert.ToInt32(Context.Session["NotificationGroupID"]);
val = val.Where(n => n.NotificationGroupID == notificationGroupID && n.Active);
e.KeyExpression = "ID";
e.QueryableSource = val;
}
As much as I hate answering my own question...
I can't figure out how to get this control to do what I want. However, a simple workaround is to handle the insert and update on the grid itself.
So, it's working now. I set the EnableUpdate and EnableInsert properties on the LinqServerModeDataSource to false, and simply handle the grid's RowInserting and RowUpdating events, where I go directly to the database.
For example, my inserting event handler is this:
protected void recipientsGrid_RowInserting(object sender, DevExpress.Web.Data.ASPxDataInsertingEventArgs e)
{
using (SqlConnection connection = new SqlConnection(App_Logic.Wrappers.DatabaseConnectionString()))
{
connection.Open();
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.Transaction = connection.BeginTransaction();
try
{
command.CommandText = " INSERT INTO NotificationParty(NotificationGroupID, FirstName, LastName, CellNumber, Active, UserCreated, DateCreated) VALUES " +
"(#NotificationGroupID, #FirstName, #LastName, #CellNumber, #Active, #UserCreated, GETDATE())";
command.Parameters.AddWithValue("#NotificationGroupID", Convert.ToInt32(Context.Session["NotificationGroupID"]));
command.Parameters.AddWithValue("#FirstName", e.NewValues["FirstName"]);
command.Parameters.AddWithValue("#LastName", e.NewValues["LastName"]);
command.Parameters.AddWithValue("#CellNumber", e.NewValues["CellNumber"]);
command.Parameters.AddWithValue("#Active", 1);
command.Parameters.AddWithValue("#UserCreated", Session["UID"]);
command.ExecuteNonQuery();
command.Transaction.Commit();
}
catch
{
command.Transaction.Rollback();
}
}
}
recipientsGrid.CancelEdit();
e.Cancel = true;
}
And my updating event handler is this:
protected void recipientsGrid_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
using (SqlConnection connection = new SqlConnection(App_Logic.Wrappers.DatabaseConnectionString()))
{
connection.Open();
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.Transaction = connection.BeginTransaction();
try
{
command.CommandText = " UPDATE NotificationParty SET FirstName = #FirstName, LastName = #LastName, CellNumber = #CellNumber, UserModified = #UserModified, DateModified = GETDATE() WHERE ID = #ID";
command.Parameters.AddWithValue("#ID", e.Keys[0]);
command.Parameters.AddWithValue("#FirstName", e.NewValues["FirstName"]);
command.Parameters.AddWithValue("#LastName", e.NewValues["LastName"]);
command.Parameters.AddWithValue("#CellNumber", e.NewValues["CellNumber"]);
command.Parameters.AddWithValue("#UserModified", Session["UID"]);
command.ExecuteNonQuery();
command.Transaction.Commit();
}
catch
{
command.Transaction.Rollback();
}
}
}
recipientsGrid.CancelEdit();
e.Cancel = true;
}
I'm having a problem with data set. I'm using one to populate text boxes of my form. The user selects a value to search from, they press a button and then the text boxes are populated. This works fine for the first record but I want to page through them. I've declared a data set to be used by my other methods but when it gets to paging the returned rows I keep getting an Object reference error. Can anyone shed some light on where I'm going wrong?
Declaring Variables:
//creates a global dataset for the copies table
DataSet dataSetHM;
//create default row values
int MaxRows = 0;
int inc = 0;
The connection to the database and filling the data set:
protected void ExecuteSelectCopies(string sName)
{
SqlConnection connection = new SqlConnection(GetConnectionString());
string sql =
"SELECT tblCopies.CopyID, tblSoftware.SoftwareName, tblCopies.AssetName, tblCopies.Location,"
+ " tblCopies.LicenceKey, tblCopies.OEM, tblCopies.State, tblCopies.InstallationDate"
+ " FROM tblCopies"
+ " INNER JOIN tblSoftware ON tblCopies.SoftwareID = tblSoftware.SoftwareID"
+ " WHERE tblSoftware.SoftwareName = #SoftwareName"
+ " ORDER BY tblCopies.CopyID";
SqlDataAdapter adapterHM = new SqlDataAdapter();
SqlCommand select = new SqlCommand(sql, connectionHM);
adapter.SelectCommand = select;
select.Parameters.Add(new SqlParameter("#SoftwareName", sName));
//open the connection
connectionHM.Open();
dataSetHM = new DataSet();
adapterHM.Fill(dataSetHM, "Copies");
NavigateCopies();
MaxRows = dataSetHM.Tables["Copies"].Rows.Count;
connectionHM.Close();
}
The method for filling the text boxes:
private void NavigateCopies()
{
DataRow dRow = dataSetHM.Tables["Copies"].Rows[inc];
TextBoxCopyID.Text = dRow.ItemArray.GetValue(0).ToString();
TextBoxSoftwareName.Text = dRow.ItemArray.GetValue(1).ToString();
DropDownListAssetName.SelectedItem.Text = dRow.ItemArray.GetValue(2).ToString();
DropDownListLocation.SelectedItem.Text = dRow.ItemArray.GetValue(3).ToString();
TextBoxLicence.Text = dRow.ItemArray.GetValue(4).ToString();
DropDownListType.SelectedItem.Text = dRow.ItemArray.GetValue(5).ToString();
DropDownListState.SelectedItem.Text = dRow.ItemArray.GetValue(6).ToString();
TextBoxInstall.Text = dRow.ItemArray.GetValue(7).ToString();
}
And finally the button for the next record:
protected void ButtonNext_Click(object sender, EventArgs e)
{
if (inc != MaxRows - 1)
{
inc++;
NavigateCopies();
}
else
{
MessageBox.show("No more Rows");
}
}
Any help with this would be very much appreciated. I honestly can't understand why the data set works for the navigation method initially but not for the second. I've been using this http://www.homeandlearn.co.uk/csharp/csharp_s12p7.html as a guide, their example displays data on page load where as mine is displayed when a search parameter is selected. I don't know if this is a problem but a bit more information never hurts!
Persist the DataSet in the Session/Cache/ViewState (which ever one of these is the most applicable solution for you).
That way you can retrieve the DataSet between postback's and continue to display the data that is required.
Here is how to accomplish this (albeit a simple example) and an article that delves into object persistence within asp.net: asp.net object persistence.