Databound DataGridView Empty Despite Full DataSource - c#

I have a base form class that contains a method that returns a DataTable:
protected DataTable GetTableData(string sql, OracleConnection connection)
{
DataTable table = null;
OracleDataAdapter adapter = null;
try
{
table = new DataTable();
adapter = new OracleDataAdapter(sql, connection);
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
adapter.Fill(table);
}
catch (Exception e)
{
MessageBox.Show("An error occurred while trying to process your request:\n\n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
if (null != adapter)
{
adapter.Dispose();
}
}
return table;
}
Another window is a subclass of it, and invokes it as follows:
private void LoadViewData(OracleConnection connection)
{
DataTable table = null;
try
{
var sql = "SELECT * FROM " + this.ObjectName;
table = GetTableData(sql, connection);
this.resultBindingSource.DataSource = table;
}
catch (Exception e)
{
MessageBox.Show("An error occurred while trying to process your request:\n\n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
this.sqlEditor.Focus();
}
}
resultBindingSource is a System.Windows.Forms.BindingSource. It is set as the DataSource property of a System.Windows.Forms.DataGridView. (The expression, this.ObjectName, evaluates to the name of a table or view in the database.)
When I run through the code in the debugger, I can see that the SQL executes just fine. I can see that the DataTable contains data. I can see that the DataGridView control is properly bound to the data source, and that I can see the data in the data table through its DataSource property. However, no data is displayed in the control itself. There are no row or column headers, and no data is displayed whatsoever.
I have tried everything I can think of to pin down the cause of this problem. This code works exactly as shown on another form. I tried deleting the controls in question and recreating them, to no avail. I consulted the articles on MSDN on how to properly databind to a DataGridView control. I tried it with and without an OracleCommandBuilder (which doesn't seem necessary to me, since this is a read-only view of the data).
I'm frankly out of ideas. It's likely something fairly obvious that I've overlooked. I know that databinding works, because I've done it before with great success.
Any pointers in the right direction would be greatly appreciated.

I tried recreating your program using the pieces you mentioned here. I didn't actually get data from a datatable but that's irrelevant. Here's what I did:
public partial class Form1 : BaseForm
{
BindingSource source = new BindingSource();
public Form1()
{
InitializeComponent();
this.dataGridView1.DataSource = source;
}
private void button1_Click(object sender, EventArgs e)
{
DataTable table = GetDataTable();
this.source.DataSource = table;
}
}
public class BaseForm : Form
{
protected DataTable GetDataTable()
{
DataTable result = new DataTable();
result.Columns.Add("Name");
result.Columns.Add("Age", typeof(int));
result.Rows.Add("Alex", 27);
return result;
}
}
Is this roughly the same thing you have? I had no issues at all. Based on what you're posting this SHOULD work. Are you sure you're binding everything to each other correctly? Post more of your binding code if possible...

Related

Duplicate columns from MySql db to c#, why?

id pojam opis id pojam opis(duplicate columns)
I am just testing connection from db to c#, and instead of columns id pojam opis I am actually getting id pojam opis id pojam opis in datagridview in c#. Here is part of code which I use to connect database to c#:
public partial class Form1 : Form
{
BindingSource bindingSource1 = new BindingSource();
MySqlConnection conn = new MySqlConnection("Data Source=localhost;database=test;user=root;password=;");
public Form1()
{
this.Load += new System.EventHandler(Form1_Load);
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = bindingSource1;
ubaciPodatke();
}
public void ubaciPodatke()
{
try
{
MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM csharp", conn);
DataTable table = new DataTable();
da.Fill(table);
bindingSource1.DataSource = table; dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Is it my mistake, or It has to do something with phpmyadmin: Version information: 4.7.0-rc1. I was thinking it can happen because this version isnt stable yet?
edit: what do You think if I delete this form.resx file
user added rows, would this solve the problem?
Few things:
There is no need to do the data binding in the Load event. You can just do it in the constructor after the InitializeComponent() call. This is irrelevant to your issue.
I don't know what ubaciPodatke means since I don't speak that language, but hopefully it is equivalent of InitializeGrid(). In that case you should put
dataGridView.DataSource = null;
dataGridView.Rows.Clear();
dataGridView.Columns.Clear();
as the first line after try. I do such "clean initialize" since I sometimes design the Grid in designer, for "documentation & visualization" purposes, but do the actual grid from the code. Also, it keeps the InitializeGrid() reusable, to be called from other places.
Also, related to the question in the comments,
Am I reading data from dgv wrong?
You should read the data from the bound DataTable and not directly from the DataGridView when binding.
Solution: I had to comment some lines link1 in form.designer.cs and problem disappeared as shown in this photo link2. I am still curious why this happened as I remember only dragging dgv from toolbox and not adding manually column names.

How connect adapter from view to model in MVP

Am not shure how to do this. Am litle confused, in my project c# winforms am using MVP pattern for deskotp application.
I have datagridview where i show products gorup. Database query for selecting products group is stored in model and that method for selecting return DataTable. Next, presenter call that model function for selecting and pass it to view. In view i put that DataTable in BindingSource and in gridview as DataSource i pass binding source.
This work good but what when i try to add new row in grid and try to save that new row?
What if i want to edit existing row and update that record to database.
If i want to create/update record from database i need to access to adapter and call update. Problem is becouse my adapter is in model not in view.
Am not shure how to from view access to adapter and dataset to model.
Check my code for selecting:
Model:
public DataTable SelectAll()
{
using (MySqlConnection conn = new MySqlConnection(Properties.Settings.Default.ConnectionString))
{
try
{
conn.Open();
string query = "SELECT Naziv, Opis FROM grupe";
using (MySqlDataAdapter adapter = new MySqlDataAdapter(query, conn))
{
dt = new DataTable();
ds = new DataSet();
adapter.Fill(ds, "grupe");
dt = ds.Tables["grupe"];
}
conn.Close();
}
catch(MySqlException ex)
{
MessageBox.Show(ex.Message);
}
}
return dt;
}
Presenter:
public DataTable SelectAll()
{
return _model.SelectAll();
}
View:
private void GrupeArtikala_Load(object sender, EventArgs e)
{
bs = new BindingSource();
bs.DataSource = _presenter.SelectAll();
groupDataGridView.DataSource = bs;
}
So now when i want to save changes to database i need to access to model database adapter but i dont know how.
private void saveToolStripButton_Click(object sender, EventArgs e)
{
changes = ds.GetChanges(); // DatSet changes is in model but i must access here but dont know how
if (changes != null)
{
int updatedRows = dataAdapter.Update(changes); // Adapter is in model and i need him here
ds.AcceptChanges();
}
}
Am not shure how to connect this to model to avoid mixing database queries in view forms.
Anyone can give me example to do this.
If I understand correctly, you need to call functions on objects belonging to your model, but you don't want your view to have a reference to your model. Is that right? If so, you could follow the pattern you used with the SelectAll function:
bs.DataSource = _presenter.SelectAll();
You are calling _presenter.SelectAll in the view, but ultimately getting the returned value from the model. So to call ds.GetChanges in your view, you could add a GetDataSetChanges function to your presenter:
public DataSet GetDataSetChanges()
{
return _model.GetDataSetChanges();
}
Same thing for calling update on your adapter. Add a function to the presenter:
public int UpdateAdapter(DataSet dataSet)
{
return _model.UpdateAdapter(dataSet);
}

How to read and write DataGridView data to Sql Table

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);
}

WPF C# - Loading MySQL Query into DataGrid

I am attempting to build a simple application that allows me to interact with a MySQL database I have set up. I can add records just fine; however, I cannot get them to display. I am simply presented with a blank datagrid control.
It could be something simple, but I have tried different approaches, searched online, and messed with it longer than I should have - to no avail. I have a feeling the issue might lie in my lack of understanding the DataGrid control. Any help is sincerely appreciated.
The Select method from the Database Connection class:
public DataTable Select(string tableName)
{
string query = "SELECT * FROM " + tableName;
this.Open();
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataAdapter adapter = new MySqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
adapter.Fill(dataSet);
this.Close();
return dataSet.Tables[0];
}
The following is a portion of the code for the window (called View) containing the datagrid. The table name is passed to it from the main window upon the click of a button.
public View()
{
InitializeComponent();
}
public View(string table)
{
this.table = table;
InitializeComponent();
}
private void windowLoad(object sender, RoutedEventArgs e)
{
DatabaseConnection myConnection = new DatabaseConnection();
dataGrid.DataContext = myConnection.Select(table).DefaultView;
}

Update changed DataGrid to the database?

Okay guys,
After many readings and finding solutions down here I just need to ask this.
I already searched for it but it didn't help me as good as it should to sort this out.
Also, excuse me for my grammatical mistakes if any...
What's the problem?
I load up a WPF form with a combobox in. This combobox gets all the names from all the tables in my database. I choose a table name and press a button to fill up a DataGrid (WPF) with the chosen table. This all works perfectly. But, then when I changed a cell or added/deleted a row or column I have to update this to the database.
This is where I'm stuck. I got it working trough a not so optimal way. So that's why I ask if there is a better solution.
//fill the datagrid with data from chosen table in combobox!
selectedTable = cboxTables.SelectedItem.ToString();
dataset = db.getDataFromTable(selectedTable);
datatable = dataset.Tables[selectedTable];
datagridAdmin.ItemsSource = datatable.DefaultView;
And when the selection in the DataGrid has changed, I set the 'Submit' button as active wich calls this code:
db.updateTable(selectedTable, datatable);
Note that 'db' is a instance off my databaseclass. The method is as following:
public bool updateTable(String tableName, DataTable datatable)
{
using (SqlBulkCopy bulkcopy = new SqlBulkCopy(thisConnection.ConnectionString, SqlBulkCopyOptions.CheckConstraints))
{
//Set destination table name
//to table previously created.
bulkcopy.DestinationTableName = tableName;
try
{
thisCommand = new SqlCommand("DELETE FROM " + tableName, thisConnection);
thisCommand.ExecuteNonQuery();
bulkcopy.WriteToServer(datatable);
}
catch (Exception ex)
{
logger.WriteLine(applicationName, ex.Message);
}
}
}
But the problem is, the first column is a auto increment ID wich keeps raising every time I submit the changed DataGrid.
Isn't there a better way to do this?
Thanks!
PS: I'm coding in Visual Studio 2010 with C# in WPF.
In short for the method you have given you would be better off using the Truncate table method before calling your bulk copy, this will reset the Identity column back to 0:
thisCommand = new SqlCommand("TRUNCATE TABLE " + tableName, thisConnection);
However either method is going to cause problems with foreign keys in your database. I am not sure how you are retrieving your data in your database class, but I would look at using the SqlCommandBuilder to update your database rather than deleting and re-inserting all the data with each update.
EDIT
To further explain my suggestion of the SqlCommandBuilder.
A ViewModel such as the following should allow use of the SqlCommandBuilder (Note: this is hugely cut down and in real terms this requires better validation, exception and event handling, but the rough idea is there):
public class YourViewModel
{
private SqlDataAdapter adapter;
private DataTable table;
private SqlCommandBuilder commandBuilder;
public DataTable Table { get { return table; } set { table = value; } }
public void LoadTable(string connectionString, string tableName, int[] primaryKeyColumns)
{
adapter = new SqlDataAdapter(string.Format("SELECT * FROM {0}", tableName), connectionString);
table = new DataTable();
adapter.Fill(table);
List<DataColumn> primaryKeys = new List<DataColumn>();
for (int i = 0; i < primaryKeyColumns.Length; i++)
{
primaryKeys.Add(table.Columns[primaryKeyColumns[i]]);
}
table.PrimaryKey = primaryKeys.ToArray();
commandBuilder = new SqlCommandBuilder(adapter);
commandBuilder.GetUpdateCommand();
}
public int Update()
{
if (table == null || table.Rows.Count == 0 || adapter == null)
{
return 0;
}
if (table.PrimaryKey.Length == 0)
{
throw new Exception("Primary Keys must be defined before an update of this nature can be performed");
}
else
{
return adapter.Update(table);
}
}
}
Bind the Table property to the grid view, then call the Update method when required. You can even bind the update to the table's rowchanged events etc to automatically update the db. The Code Project has a fairly good article on WPF, Data grids and database integration.

Categories