I would like to provide a "Refresh" button on a form containing a DataGridView object bound to a MySQL database. I have gotten screens without columns populated from a query with calculated fields by "new"ing the MySQLCommand, MySQLDataAdapter, MySqlCommandBuilder and DataSet objects and rerunning the query and reloading the binding source to the DataGridView object.
For ones that have calculated columns, this does not work.
Surely, there must be some way to have a DataGridView object reload from the DB.
I am using SharpDevelop C# 5 with .NET framework 4.0, MySQL Community Server 5.3.33 and MySQL Data Connector/.NET V 6.7.4
Any leads much appreciated!
Jesse and Brian,
I am doing WinForms - sorry for not being clear. I have just worked out a solution. First, just executing what was run in the initial load is not enough. I found one must "new" the MySqlCommand, MySQLDataAdapter, MySqlCommandBuilder and DataSet objects, then run the data fetch as in the form load. Also, this cannot be called while doing anything that looks or smells like "editing" or it will throw an exception. I wanted my form to refresh just after edit, so I put a timer on the form and enabled it at the end of the RowValidated event and let the timer call the ReloadGrid routine. Also, if the user is on, say row 822, I found the focus went to row 0 and cell 0, so I save the current row and cell to a point and then set the focus back after the data refresh.
private void BindGrid(){
//retrieve data
//bind
DataGridView.DataSource = dataSource;
DataGridView.DataBind();
}
//call BindGrid() anytime you need to refresh data, for example in a button event click handler
Related
I have bound my MSSQL datatable to a datagridview using the designer (the datatable has atleast 30 columns), it fills the data like this:
this.produktaiTableAdapter.Fill(this.veiklosDuomenysDataSet.Produktai);
this.produktaiBindingSource.Filter = advancedDataGridView1.Columns[1].HeaderText + " = " + Veiklos_ID;
It is necessary for me to bind it like this, as I have a lot of code concerning every single column in the DGV (for example, width, currencies, and so on).
Now I want to save all the new, updated, and deleted data in datatagridview to my MSSQL datatable by clicking a Save button. How can I do that? How can I convert my edited datagridview to the datatable?
I also tried this code on my save button click:
this.Validate();
this.produktaiBindingSource.EndEdit();
this.produktaiTableAdapter.Update(this.veiklosDuomenysDataSet.Produktai);
And.. It doesn't work. I am fairly new with datagridview and datatables overall as this problem I think should have an easy fix.
EDIT:
Also, could this line help somehow?
DataTable Produktai = advancedDataGridView1.DataSource as DataTable;
EDIT2:
This doesn't work either.
veiklosDuomenysDataSet.Naudotojai.AcceptChanges();
this.Validate();
this.produktaiBindingSource.EndEdit();
this.produktaiTableAdapter.Update(this.veiklosDuomenysDataSet.Produktai);
MessageBox.Show("Data is saved!");
EDIT3:
This is a debug picture of my main form: Here
As you can see I have no textbox or buttons like INSERT, DELETE and UPDATE. The user can edit the DGV simply by clicking on a cell and editing the value, add new rows simply by pressing ENTER, deleting the row by clicking Delete (Ištrinti in picture) on the same selected row (NOTE: delete button column is the only unbound column in DGV).
I use MSSQL datatable to bound it with the datagridview, and I want all the rows that are new, deleted or edited in the datagridview to be renewed/updated in the datatable that it is bounded too by save button.
Maybe there should be something different with this information, a wild guess?
Start over - this will generate a basis for comparison
I didn't encounter any problems saving when I did:
Make a new project
Open server explorer, add a connection
Choose SQLServer file driver, put a path to a new file (new.mdf), click OK, say yes to create it
Expand the new node in server explorer, right click tables, add a new table with column names that are sensible (just letters and numbers, no spaces, no punctuation or other symbols - you could add percent signs etc and it'll still work, but there's a reason why no-one does it, and that's because it makes life very hard work all down the line. If you think want a column called "Profit %" call it "ProfitPercent" instead). Save the table.
Open data sources tool panel, add a new datasource, choose database, choose dataset, choose the connectionstring for new.mdf
Really carefully read the next question it asks. Do not just skip past it. If you say Yes then, by default your program will dynamically attach a database that gets erased and replaced every time you run the program (but this is typically what you want). If you say No, then understand that the db your program edits might not be in the project folder at all
Tixk the table in the wizard, or close the wizard and drag the new table out of server explorer into the dataset. Save the dataset
Open the form, drag the table representation out of the data sources tool panel and onto the Form. A datagridview appears
Run the program, add some rows, click the save button
Stop the program, run it again - the rows will be there if you said No to the important question earlier. If you said Yes, then stop the program, click the new.mdf file in the Solution Explorer, change "Copy Always" to "Copy if Newer", run the program again. Add rows, save, stop the program and run it again, the rows will be there. The only time they will disappear is if you change the design of the new.mdf database (so that it is newer)
Your form code will now just be something like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void myTableBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.myTableBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.newDataSet);
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'newDataSet.MyTable' table. You can move, or remove it, as needed.
this.myTableTableAdapter.Fill(this.newDataSet.MyTable);
}
}
And you won't have written any of it. It's all that's required to load, show, edit and save data using a datagridview. The call to tableAdapterManager.UpdateAll is equivalent to someTableAdapter.Update - a tableadaptermanager is a convenience device that calls Update in the correct order to ensure that parent rows are created before related child rows
There's nothing wrong with the posted code in terms of "that's how you save" so the diagnosis needs to methodically chase things through:
Run the program, load data into the grid, edit some of it
Pause in the debugger just before you update, and call GetChanges on the datatable that is about to be saved
If there are no changes, then that table was not edited (the grid is bound to a different table) or no edits were made (the grid edit was cancelled not committed) or the edit's were reverted or accepted (RejectChanges or AcceptChanges was called on the datatable)
if there are changes move to capturing the return value from tableadapter update (Write var x = tableadapter.update(..)) and step the debugger over the call to update
if the result is 0 then no rows were updated; this should result in a concurrencyexception if there were changes and the tableadapter query is enabled for concurrency (probably the default). If your tableadapter doesn't have an update query built in then again you should get an exception if you try to save edits ("update requires a valid updateconmand when passed a collection with modified rows". If it's just 0 and no exception is thrown then for some reason no rows were updated - not a situation I'd expect and would need some more investigation
if the result is > 0 then an update was made (changes were saved). On a tableadapter the Update method is responsible for all inserts, updates and deletes. If you can't see your changes it you're most likely looking in the wrong database file, or your build process is erasing your file and replacing it with a new one. This most often happens with file based databases like Access but can happen with sql server if your database file is being dynamically attached and detached
I have an edit form that uses a DropDownList, connected to a SQL server table using a DataSource. This edit form allows users to set the table's "IsDeleted" column value to 1, which would then hide it from all of the application's queries. (So the transaction still exists in the database, but not in the application)
The problem I've encountered with this is that if the page on which the edit form is is not left entirely, and then entered again, the entry still remains in the DataSource.
So essentially, the DataSource is not updating. (It's not running its select statement and repopulating until the whole page is reloaded). I've tried to use a page refresh and it doesn't seem to work, only going to a different page entirely and then coming back seems to update the DataSource.
How would I refresh the contents of the DataSource programmatically without having to recreate the entire DataSource itself?
You might want to add some code next time.
My best guess for now is that you're not doing anything OnPostback.
So I eventually resorted to doing what I did not want to do in the hopes that there would be a "Best-practice" way to do it (and one hopefully already built-in into DataSources), but it seems that was not to be.
All it took was to re-assign the DataSource's parameters to it again and then assign the DataSource back to the DropDownList, as if I were creating a new one.
I created the following method, which I then called at the end of my Delete button's event.
protected void DropDownList_Reload()
{
MyDataSource.ConnectionString = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
MyDataSource.SelectCommand = "SELECT * FROM [tblMyTable] WHERE [IsDeleted] <> 1";
cbxDropDownList.DataSourceID = "MyDataSource";
cbxDropDownList.DataTextField = "MyHeader";
cbxDropDownList.DataValueField = "MyHeader";
}
I'm having the following problem:
What I have is a search function that runs a query on my database using a SqlDataAdapter.
I then use:
DataSet ds = new DataSet();
dataAdapter.Fill(ds, "table title");
gridView1.DataSource = ds;
gridView1.DataBind();
I originally got an error that I then had both a dataSource and dataSourceId, so I cleared the previously used ID. The code works, I can search the table and my query will return rows and update the table. The problem is that I want the data that it returns to be editable. I have my grid view editable, and before I run the query, I can edit the rows of the table. But after the search is run, and the gridView is filled with my DataSet, I'm unable to update the rows. If I click the edit button, it gives me an error saying the RowEditing event wasn't handled.
I looked into that event, and understand what's happening, if I were to program in the events for RowEditing/RowUpdating/RowUpdated etc. I could get it to work, but is there no better way to do this? Is there a simpler way to set my dataSource in C# and be able to maintain the editablity of the rows?
Thanks a lot!
I suppose part of the question would be would you want to? I guess you're looking for a SaveDataChanges() method which brings about a few design concerns. One is you have to remember that web pages are stateless so to an extent your web page post isn't aware of the data it's just pulled and bound to the UI. The grid view control in a round about way nicely gets the user to help you out here and click update on the row they've amended. With this you have your event handler and you can just focus on the data that's been changed and just send one UPDATE statement.
I've added a MySQL database through the datasources in Visual Studio. I've then dragged and dropped the table I want onto my form design and changed the layout to suit here and there.
I have a background worker that inserts data into the database occasionally using the MySQL connector. I've then been trying to refresh the datagridview to reflect the changes inserted into the database, but I can't get the form to update to show the new data.
Having read a few questions from people having similar trouble I've tried:
Rebinding the data source as per this question Refreshing a DataGridView after DB has changed?
and this one http://social.msdn.microsoft.com/Forums/vstudio/en-US/a1cf64de-6e35-435c-943c-ed6e9b39525b/how-to-refresh-datagridview-component-using-designer?forum=csharpgeneral
this.rfidDataGridView.DataSource = null;
this.rfidDataGridView.Rows.Clear();
this.rfidDataGridView.DataSource = this.rfidBindingSource;
Which causes the datagridview to become a white square with an X in it
Calling the reset methods as per here http://msdn.microsoft.com/en-us/library/f61k6akt.aspx
this.mcbrideDataSet.Reset();
this.rfidBindingSource.ResetBindings(false);
Which gives me a SystemOutOfRangeException at Windows.Forms.CurrencyManager.getItem
Refilling and refreshing
this.rfidTableAdapter.Fill(this.mcbrideDataSet.rfid);
this.rfidDataGridView.PerformLayout();
this.rfidDataGridView.EndEdit();
this.rfidDataGridView.Refresh();
this.rfidDataGridView.Parent.Refresh();
I've tried a few other variations of all of the above.
As a lot of this data has been auto-generated by Visual Studio in Designer.cs I've tried following the data definitions and references to see if I could find anything useful in there, but I'm new enough to C# that I'm not getting anywhere. I can't see where the connection string is or where the dataSource is getting it's data. I've found it's declaration, but not where it's assigned values from the database.
Any help would be greatly appreciated.
I think you need to bind the grid view after it changes.
rfidDataGridView.DataBind();
DataGridView.BindingContext = new BindingContext();
In a nutshell: I have a DataSet with multiple DataTables inside, which are connected via multiple DataRelations. I've created a form using databinding on this DataSet, and you could say it is pretty complex.
The scenarios is next: the main purpose of the form is the insertion of a new record. For it to be inserted, various parent-child relations must be set. It all works fine with the databinding, but the problem is next: when user wants to enter a new "child" for one-of-those parent-child relations, new form opens, he enters it, yada yada yada, - and it works. Trouble is - how should I get that new data back to the original form, to appear in parent-child combobox?
One way I know of, is to refresh the entire form; but I am looking for a solution to refresh just the DataTable containing that data. I've tried getting a new DataTable with fresh data from DB, and merging it with DataTable in DataSet, but it doesn't work: "A child row has multiple parents" exception is thrown:
// basically just a Select * using dataadapter,
// nothing programmatically added
DataTable table = tableModule.GetPlainTable();
existingDataSet.Tables["tableName"].Merge(table);
The equivalent example of what I'm trying to do is to have a Order form, with Customer combobox on it. On the right of the combobox, there is a "add" button that opens a new "Add customer" form. Just to mention (maybe it is relevant), inside the DB, "Customers" table is in relation with the "Cities" table, and that data is linked in databindning on the Orders form as well...
EDIT: one solution I can think of is to "manually" loop throughout the new DataTable, and find all rows that are not in the original DataTable inside DataSet, but I'm not sure this would work either ...
Any help / suggestion / explanation / push in the right direction would be greatly appreciated :)
Well, i kind of solved the problem with manual row copy upon insertion in second form... I have created an event with object collection (row item array), and in first form registered a handler on that event, in which I manually add the new row via:
data.Tables["tableName"].Rows.Add(e.RowItems);
after which I call AcceptChanges() on that row to make its state Unchanged, rather than Added...
This solution, although quick-and-dirty, works. The problem is, I think there is a better, more "databinding" philosophy oriented one... :=)