I need your help with something I am working on.
It's very simple, but it has been bugging me.
I am creating a ComboBox[DropDown Menu] in a WPF application and I want to fill it with all the current Tables I have in my DB.
This is what I'm struggling to do:
When I click on the ComboBox it will show all the available tables in the DataBase. Then when I click on one of them it will show the information that is contained within the selected table in a DataGrid I've placed below the menu.
And here Is the code I am using when the ComboBox opens:
private void tableComboBox_DropDownOpened(object sender, EventArgs e)
{
SqlCommand cmd = new SqlCommand("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE';", db.connection);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
foreach(DataRow row in dataSet.Tables)
{
tableComboBox.Items.Add(row);
}
}
I've already looked and tried some different approaches but non of them work.
And I've tried to show the Content of a Table in the DataGrid but I got stuck again.
Please fellow coders. Help this newbie over here! :)
So this is what I quickly came up with.
remove the tableComboBox_DropDownOpened event.
add the event comboBox_SelectionChange
Change your db connection string, names of the combobox and dataGrid to match yours.
Here is the code below, I moved the loadCombo() below your initialize to make it simple.
public partial class MainWindow : Window
{
SqlConnection db = new SqlConnection("Your Connection String Here");
public MainWindow()
{
InitializeComponent();
loadCombo();
}
private void loadCombo()
{
SqlCommand cmd = new SqlCommand("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE';", db);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
foreach (DataRow row in dataSet.Tables[0].Rows)
{
comboBox.Items.Add(row[0]);
}
}
private DataTable loadDataGrid(String inTableName )
{
SqlCommand cmd = new SqlCommand("SELECT COLUMN_NAME,* FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '"+ inTableName + "';", db);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
return dataSet.Tables[0];
}
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string text = e.AddedItems[0].ToString(); ;
dataGrid.ItemsSource = loadDataGrid(text).DefaultView;
}
}
Hope this helps
I have updated your code below. Paste this in a give it a shot. I am not sure what is happening with the create buttons but lets see if we can fix the combobox and datagrid. I added some comments in the code to help explain my rational.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DatabaseManagement
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Database db = new Database();
public MainWindow()
{
InitializeComponent();
// Add the loadCombo back
loadCombo();
// comment this out until you get the desired functionality
//TableCreateGrid.Visibility = Visibility.Hidden;
}
private void createButton_Click(object sender, RoutedEventArgs e)
{
try
{
// I am not sure what you are doing here -
if (string.IsNullOrEmpty(column3TextBox.Text) && string.IsNullOrEmpty(column4TextBox.Text))
{
db.CreateTable(tableTextBox.Text, column1TextBox.Text, column2TextBox.Text);
informationBlock.Text = db.infoBoxString;
}
else if (string.IsNullOrEmpty(column4TextBox.Text))
{
db.CreateTable(tableTextBox.Text, column1TextBox.Text, column2TextBox.Text, column3TextBox.Text);
informationBlock.Text = db.infoBoxString;
}
else if (!string.IsNullOrEmpty(column3TextBox.Text) && !string.IsNullOrEmpty(column4TextBox.Text))
{
db.CreateTable(tableTextBox.Text, column1TextBox.Text, column2TextBox.Text, column3TextBox.Text, column4TextBox.Text);
informationBlock.Text = db.infoBoxString;
}
}
catch (Exception ex)
{
informationBlock.Text = ex.Message;
}
}
private void button_Click(object sender, RoutedEventArgs e)
{
db.Connect();
informationBlock.Text = db.infoBoxString;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
db.Close();
informationBlock.Text = db.infoBoxString;
}
private void loadCombo()
{
SqlCommand cmd = new SqlCommand("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE';", db.connection);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
foreach (DataRow row in dataSet.Tables[0].Rows)
{
tableComboBox.Items.Add(row[0]);
}
}
private DataTable loadDataGrid(String inTableName)
{
// Here you need to specify the columns you want in the TableCreateGrid
// example this just will show the COLUMN NAME,DATA TYPE, CHARACTER MAXIMUM LENGTH and so on
// SqlCommand cmd = new SqlCommand("SELECT COLUMN_NAME,DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, TABLE_SCHEMA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + inTableName + "';", db.connection);
SqlCommand cmd = new SqlCommand("SELECT COLUMN_NAME,* FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + inTableName + "';", db.connection);
SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
return dataSet.Tables[0];
}
private void tableComboBox_DropDownOpened(object sender, EventArgs e)
{
//loadCombo();
// dont need since this is loaded on Initialize
}
private void tableComboBox_DropDownClosed(object sender, EventArgs e)
{
// tableComboBox.Items.Clear();
// dont need since this will clear all the items in the tableComboBox
}
private void tableComboBox_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
try
{
string text = e.AddedItems[0].ToString(); ;
dataGrid.ItemsSource = loadDataGrid(e.AddedItems[0].ToString()).DefaultView;
}
catch (Exception ex)
{
informationBlock.Text = ex.Message;
}
}
}
}
This is a code to store disply name and value in combobox
private void Form1_Load(object sender, EventArgs e)
{
var Header = new BindingList<KeyValuePair<string, string>>();
List<string> LV = ListHeader();
foreach (var listOut in LV)
{
Header.Add(new KeyValuePair<string, string>(listOut, "val"+listOut));
}
tableComboBox.DataSource = Header;
tableComboBox.DisplayMember = "Key";
tableComboBox.ValueMember = "Value";
}
public List<string> ListHeader()
{
List<string> list = new List<String>();
try
{
cmd.Connection = db.connection;
cmd.CommandText = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE';";
var reader = cmd.ExecuteReader();
for(int i=0;i<reader.FieldCount;i++)
{
list.Add(reader.GetName(i));
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Get Header",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
con.Close();
}
return list;
}
You can get the combobox value like this :
Console.WriteLine(((KeyValuePair)tableComboBox.SelectedItem).Value.ToString());
Or you only want to get a display name :
tableComboBox.SelectedItem.ToString()
Related
When trying to edit the datagridview, an error appears "The CommandText property has not been properly initialized.". I read that some other stored procedure is needed, which as input parameters it takes the first name, last name and patronymic and phone number of the user and returns his id, if so, how to implement it on mysql link to the source: https://metanit.com/sharp/adonet/2.11.php , https://metanit.com/sharp/adonet/3.5.php
Program code:
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SD = System.Data;
namespace DBredaction
{
public partial class Form1 : Form
{
DataSet ds;
MySqlDataAdapter adapter;
MySqlCommandBuilder commandBuilder;
string connectionString = "Server=localhost;Database=catalog;Uid=root;pwd=;charset=utf8;";
string sql = "SELECT * FROM employee";
public Form1()
{
InitializeComponent();
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.AllowUserToAddRows = false;
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
adapter = new MySqlDataAdapter(sql, connection);
ds = new DataSet();
adapter.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
// делаем недоступным столбец id для изменения
dataGridView1.Columns["Id"].ReadOnly = true;
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
//public MySqlConnection mycon;
//public MySqlCommand mycom;
//public string connect = "Server=localhost;Database=catalog;Uid=root;pwd=;charset=utf8;";
//public SD.DataSet ds;
//public MySqlCommand mycon2;otchestvo
private void button1_Click(object sender, EventArgs e)
{
try {
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
adapter = new MySqlDataAdapter(sql, connection);
commandBuilder = new MySqlCommandBuilder(adapter);
adapter.InsertCommand = new MySqlCommand("", connection);
adapter.InsertCommand.CommandType = CommandType.StoredProcedure;
adapter.InsertCommand.Parameters.Add(new MySqlParameter("#imia", MySqlDbType.VarChar, 50, "Имя"));
adapter.InsertCommand.Parameters.Add(new MySqlParameter("#familia", MySqlDbType.VarChar, 50, "Фамилия"));
adapter.InsertCommand.Parameters.Add(new MySqlParameter("#otchestvo", MySqlDbType.VarChar, 50, "Отчество"));
adapter.InsertCommand.Parameters.Add(new MySqlParameter("#telephon", MySqlDbType.VarChar, 11, "Телефон"));
MySqlParameter parameter = adapter.InsertCommand.Parameters.Add("#id", MySqlDbType.Int16, 0, "Id");
parameter.Direction = ParameterDirection.Output;
adapter.Update(ds);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void button4_Click(object sender, EventArgs e)
{
try
{
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
MessageBox.Show("DB CONNECT");
connection.Close();
}
}
catch
{
MessageBox.Show("Connection lost");
}
}
private void button3_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.SelectedRows)
{
dataGridView1.Rows.Remove(row);
}
}
private void button5_Click(object sender, EventArgs e)
{
DataRow row = ds.Tables[0].NewRow();
ds.Tables[0].Rows.Add(row);
}
}
}
It doesn't work quite like that; if you're assigning a command builder to an adapter you don't then also set the XxxCommand DML properties yourself; the command builder does that from looking at the SelectCommand, working out the table schema and writing the queries.
I'd have the adapter at class level in a dedicated repository class, where the select, connstr and command builder are set:
//in the constructor of the repo class
_myDataAdapter = new MySqlDataAdapter("SELECT here", "connstr here");
_commandBuilder = new MySqlCommandBuilder(_myDataAdapter);
the fill code runs:
//in a GetData method of the repo class
DatTable dt = new DataTable();
_myDataAdapter.Fill(dt);
return dt;
and the relevant I/U/D commands can be triggered:
//in a SaveChanges(DataTable) method of the repo class
_myDataAdapter.Update(dt);
See https://www.devart.com/dotconnect/mysql/docs/Devart.Data.MySql~Devart.Data.MySql.MySqlCommandBuilder.html for more background info on the CB; their example code is based on a complete programmatic "fill, change, save" workflow so it's all in one method, but your workflow is essentially interrupted by the user needing to do the changes in the grid, hence breaking it up.
If you want to do it in one method, you can make your adapter, make your command builder and then set the I/U/D commands on the adapter by calling the relevant GetXxx on the command builder
Note that the command builder doesn't use stored procedures; that thing you've read about needing to make a stored procedure to update/insert data isn't the only way to save data to a db, and if you have created a sproc and are hoping to use it, forget a command builder; you'll have to do the command setup yourself
I'll start off by saying that I'm pretty inept at coding (have yet to learn how to utilize classes and how they work in depth), and that I've never worked with sql before doing this project.
The idea here is that you connect to an sql database, after which a datagridview element gets filled with data from a table called TABLE_1 by default. The user should then be able to input, delete and save data.
The first two work operations work perfectly, but the saving is the problem. I've banged my head against a wall for about 4 days trying to get the saving to work, but I just cant get it to do so. The saving is done with the method Button3_click.
Any insight as to what I should do?
Is the main chunk of the code where you connect the part where I'm
messing up?
//initialize the classes I guess, on some youtube guides they did so
SqlConnection con;
DataSet ds;
SqlDataAdapter a;
DataTable t;
SqlCommandBuilder scb;
static string tablename = "TABLE_1";
string constring;
//connect button
private void button1_Click(object sender, EventArgs e)
{
try
{
//connect using info from textboxes, connection is ok
constring = "server=" + Server.Text + ";database=" + DB.Text + ";UID=" + UID.Text + ";password=" + Password.Text;
SqlConnection con = new SqlConnection(constring);
con.Open();
DataSet ds = new DataSet();
Save.Enabled = true;
//check if table name is empty, if so default to TABLE_1
if (textBox1.Text != "")
{
tablename = textBox1.Text;
}
else
{
tablename = "TABLE_1";
}
a = new SqlDataAdapter("SELECT * FROM " + tablename, con);
DataTable t = new DataTable();
a.Fill(t);
datagrid.DataSource = t;
//
label5.Text = Server.Text;
con.Close();
}
catch(Exception es)
{
MessageBox.Show(es.Message);
}
}
//save button
private void button3_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection(constring);
con.Open();
DataSet ds = new DataSet();
DataTable t = new DataTable();
a.TableMappings.Add(tablename, "t");
scb = new SqlCommandBuilder(a);
a.Update(t);
con.Close();
}
Use the following example which sets up the adapter, dataset and table name as private variables.
Also, I recommend to never use one letter variable names as a) it's difficult to debug b) when getting into more lines of code it's going to be difficult to know what a variable is for.
Next up, using SELECT *, it' unknown if you have setup a auto-incrementing primary key which is needed to perform updates. In the example below, Id is auto-incrementing.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
namespace WindowsFormsDataAdapterExample
{
public partial class Form1 : Form
{
private SqlDataAdapter _companiesSqlDataAdapter;
private DataSet _companiesDataSet;
private string _tableName = "Companies";
public Form1()
{
InitializeComponent();
Shown += OnShown;
}
private void OnShown(object sender, EventArgs e)
{
_companiesDataSet = new DataSet();
_companiesSqlDataAdapter = new SqlDataAdapter(
"SELECT Id, FirstName, LastName, PhoneNumber, City FROM dbo.Companies;",
"Data Source=.\\sqlexpress;Initial Catalog=ForumExample;" +
"Integrated Security=True");
var builder = new SqlCommandBuilder(_companiesSqlDataAdapter);
_companiesSqlDataAdapter.Fill(_companiesDataSet, _tableName);
dataGridView1.DataSource = _companiesDataSet.Tables[_tableName];
}
private void SaveButton_Click(object sender, EventArgs e)
{
_companiesSqlDataAdapter.Update(_companiesDataSet, _tableName);
}
}
}
I share with you a piece of code that works except the part where I'm trying to loop in the items of my listbox. That's why I'm here asking you for some help.
Lately, I switched from VBA to C# so I'm still new on this and don't undertsand everything yet.
So, the below code connect to my SQL server DB and fetch data both within my listbox and a DataGridView. I can filter with two textboxes also.
So now I have items within my listbox and my db's view within the DataGridview. I'd like to filter my DataGridview (which is filled by a datatable ) with my Listbox's item. I miss only a silly part I guess. Why Do I get this CS0246 "ListItem could not be found"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsAppTest
{
public partial class Form1 : Form
{
//Initialize the component and display the items within my listbox CS_Bonds_listBox
public Form1()
{
InitializeComponent();
string connetionString = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
SqlConnection conn = new SqlConnection(connetionString);
conn.Open();
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT DISTINCT RatingProvider FROM Bonds", conn);
adapter.Fill(ds);
this.CS_Bonds_listBox.DataSource = ds.Tables[0];
this.CS_Bonds_listBox.DisplayMember = "RatingProvider";
}
private void Form1_Load(object sender, EventArgs e)
{
}
DataTable dtTEST = new DataTable();
// Next, when clicking on my button Connect, I retrieve my db into a Datatable that is displayed within //the Datagridview1
private void buttonConnect_Click(object sender, EventArgs e)
{
string connetionString = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
SqlConnection cnn= new SqlConnection(connetionString);
cnn.Open();
MessageBox.Show("Connection Open !");
String sql = "Select * from Bonds";
SqlCommand command = new SqlCommand(sql, cnn);
SqlDataAdapter sqlDA = new SqlDataAdapter();
sqlDA.SelectCommand = command;
sqlDA.Fill(dtTEST);
dataGridView1.DataSource = dtTEST;
cnn.Close();
}
private void ISIN_Bonds_textBox_TextChanged(object sender, EventArgs e)
{
DataView dv = dtTEST.DefaultView;
dv.RowFilter = "ISIN LIKE '" + ISIN_Bonds_textBox.Text + "%'";
dataGridView1.DataSource = dv;
}
private void Ticker_Bonds_textBox_TextChanged(object sender, EventArgs e)
{
DataView dv1 = dtTEST.DefaultView;
dv1.RowFilter = "Ticker LIKE '" + Ticker_Bonds_textBox.Text + "%'";
dataGridView1.DataSource = dv1;
}
private void CS_Bonds_listBox_SelectedIndexChanged(object sender, EventArgs e)
{
string conString = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
string query = "SELECT ISIN, Ticker, CrediSight, FROM Bonds";
string condition = string.Empty;
foreach (ListItem item in CS_Bonds_listBox.Items)
{
condition += item.Selected ? string.Format("'{0}',", item.Value) : "";
}
if (!string.IsNullOrEmpty(condition))
{
condition = string.Format(" WHERE Country IN ({0})", condition.Substring(0, condition.Length - 1));
}
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlCommand cmd = new SqlCommand(query + condition))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
cmd.Connection = con;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
dataGridView1.DataSource = dt;
//dataGridView1.DataBind();
}
}
}
}
}
}
}
This line has a problem:
foreach (ListItem item in CS_Bonds_listBox.Items)
A ListItem is a WebForms thing, and your application is a WinForms thing; your listbox doesn't contain a list of ListItem objects so this line of code wouldn't work out anyway, even if the relevant web namespace was imported.
Because you've bound your listbox to a datatable the list it is showing is full of DataRowView objects, so that's what you need to process. A DataRowView has a Row property that gives you the underlying row, which in turn can be accessed by a column name.
Additionally, to make your life easier a listbox has a SelectedItems property so you don't need to check every item for being selected:
foreach (DataRowView drv in CS_Bonds_listBox.SelectedItems)
{
var dr = drv.Row as DataRow;
var rp = dr["RatingProvider"];
condition += $"'{rp}',"
}
Your condition will end up with a trailing comma as a result of this, so trim it off before you build an IN clause with it:
condition = condition.TrimEnd(',');
This technique could be susceptible to SQL Injection hacking if the user manages to change the text showing in the list items.
A better way to handle the problem is via parameterization. You'd do it like this:
var cmd = new SqlCommand("SELECT * FROM table WHERE Country IN(", connStr);
int i = 0;
foreach (DataRowView drv in CS_Bonds_listBox.SelectedItems)
{
var dr = drv.Row as DataRow;
var rp = dr["RatingProvider"];
cmd.CommandText += $"#p{i},";
cmd.Parameters.Add($"#p{i}", SqlDbType.VarChar).Value = rp;
i++;
}
cmd.CommandText = cmd.CommandText.TrimEnd(',') + ")";
using(var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
someGridView.DataSource = dt;
}
This builds an sql that looks like SELECT * FROM table WHERE Country IN(#p0,#p1,#p2.... i.e. we have concatenated parameter placeholders in rather than concatenating values in. At the same time we have filled the parameters collection with the parameter values
It also means that our database can't be hacked via our program, and our app doesn't die in a heap when the user selects a country with a name like Cote d'Ivoire
Some other things to note to tidy your code up:
SqlDataAdapter can take a string SQL and a string connection-string. You don't need to make a SqlCommand for it. You don't need to open and close conenctions for it; it knows how to do all this itself. I only used a SqlCommand because I was building the parameters collection as I went. Ordinarily I'd do using(var da = SqlDataAdapter("SELECT...", "Server=..") because it makes things nice and tidy.
This means e.g. your constructor can be simply:
//put this here once
private string _connStr = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
public Form1()
{
InitializeComponent();
var dt = new DataTable();
using(var da = new SqlDataAdapter("SELECT DISTINCT RatingProvider FROM Bonds", _connStr))
adapter.Fill(dt);
this.CS_Bonds_listBox.DataSource = dt;
this.CS_Bonds_listBox.DisplayMember = "RatingProvider";
}
I'm trying to reflect the changes being made in the DataGrid to my local database (SQL Server Compact Edition, in this case) but it fails. Here is the code:
SqlCeConnection conn;
SqlCeDataAdapter dataAdapter;
public MainWindow()
{
InitializeComponent();
Init();
}
public void Init()
{
try
{
conn = new SqlCeConnection(#"Data Source = DataModel.sdf");
dataAdapter = new SqlCeDataAdapter("Select * from Members", conn);
SqlCeCommandBuilder commandBuilder = new SqlCeCommandBuilder(dataAdapter);
DataTable dataTable = new DataTable();
dataAdapter.Fill(dataTable);
dataTable.RowChanged += dataTable_RowChanged;
dataTable.RowDeleted += dataTable_RowDeleted;
membersDataGrid.ItemsSource = dataTable.DefaultView;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void dataTable_RowDeleted(object sender, DataRowChangeEventArgs e)
{
dataAdapter.Update(sender as DataTable);
}
void dataTable_RowChanged(object sender, DataRowChangeEventArgs e)
{
dataAdapter.Update(sender as DataTable);
}
membersDataGrid is the name of the DataGrid view in the UI. Have I done anything wrong?
Thanks in advance :-)
This is the code that worked for me. It is similar to yours, except that uses my localDB database (not CE). Also, make sure to test your code outside VS, otherwise the database file may get over-written in your compile/execute cycle and you will never be able to see your changes reflected in the database.
private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{
string connstr = ConfigurationManager.ConnectionStrings["WpfApplication14.Properties.Settings.NorthwindConnectionString"].ToString();
SqlConnection conn = new SqlConnection(connstr);
CustomersTableAdapter adapter = new CustomersTableAdapter();
NorthwindDataSet.CustomersDataTable table = new NorthwindDataSet.CustomersDataTable();
adapter.Fill(table);
dataGrid1.ItemsSource = table.DefaultView;
table.RowChanged += table_RowChanged;
}
void table_RowChanged(object sender, System.Data.DataRowChangeEventArgs e)
{
using (CustomersTableAdapter adapter = new CustomersTableAdapter())
{
adapter.Update(sender as NorthwindDataSet.CustomersDataTable);
}
}
I have retrieved data from Mysql database into a DataGridView1. Let us suppose I am in Row 0. When I change the contents of Row 0, Cell 1 and press enter key or a button, the Update query should modify that row, but I am unable to modify the value of the cell. The cell maintains its previous value when i reload data and the database is not modified. For example, if I change the contents of a cell under column Client_Name from "Acs" to "Gmt", how can I change the value of the cell from "Acs" to "Gmt"? and to have it updated into Mysql database, I am using c# in Vs 2012. below is my code that retrieves my database into datagridview1 any help is welcomed thanks.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySql.Data;
using MySql.Data.MySqlClient;
using System.Configuration;
using System.Data.SqlClient;
namespace PI.Gen
{
public partial class frmMain : Form
{
MySqlConnection Conn;
public frmMain()
{
InitializeComponent();
btnDisconnect.Enabled = true;
btnLoadData.Enabled = false;
btnLoadClients.Enabled = false;
}
private void btnConnect_Click(object sender, EventArgs e)
{
string strConnect = "server=" + txtServer.Text + ";uid=" + txtUsername.Text + ";pwd=" + txtPassword.Text + ";database=" + txtDatabase.Text;
try
{
if (txtServer.TextLength <= 0 || txtUsername.TextLength <= 0 || txtDatabase.TextLength <= 0)
{
MessageBox.Show("You have an empty database connection field. Please supply a valid value.");
return;
}
Conn = new MySqlConnection(strConnect);
Conn.Open();
if (Conn.State.ToString() != "Open")
{
MessageBox.Show("Could not open database connection");
return;
}
btnDisconnect.Enabled = true;
btnConnect.Enabled = false;
btnLoadData.Enabled = true;
btnLoadClients.Enabled = true;
// btnSubmitClient.Enabled = true;
}
catch (Exception ex) // catch on general exceptions, not specific
{
MessageBox.Show(ex.Message);
return;
}
}
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (Conn != null)
{
Conn.Close();
}
}
private void btnDisconnect_Click(object sender, EventArgs e)
{
try
{
Conn.Close();
Conn = null;
btnDisconnect.Enabled = false;
btnConnect.Enabled = true;
btnLoadData.Enabled = false;
btnLoadClients.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
private void btnLoadData_Click(object sender, EventArgs e)
{
try
{
string CmdString = "SELECT * FROM t_receipients";
MySqlDataAdapter sda = new MySqlDataAdapter(CmdString, Conn);
DataSet ds = new DataSet();
sda.Fill(ds);
dataGridView1.DataSource = ds.Tables[0].DefaultView;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
private void btnLoadClients_Click(object sender, EventArgs e)
{
try
{
string CmdString = "SELECT * FROM t_clients";
MySqlDataAdapter sda = new MySqlDataAdapter(CmdString, Conn);
DataSet ds = new DataSet();
sda.Fill(ds);
dataGridView1.DataSource = ds.Tables[0].DefaultView;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
After series of trials and error, i finally found what i was looking for, thus being able to update database from datagridview below is my worked around code which works 100% hope it helps someone in future, and thanks #RageComplex for helping out, but one more thing does anyone know how to implement that i mean instead of hitting the enter button to take changes in the datagridview you rather click on a button ty
private void dataGridView1_RowValidated(object sender, DataGridViewCellEventArgs e)
{
try
{
DataTable changes = ((DataTable)dataGridView1.DataSource).GetChanges();
if (changes != null)
{
MySqlCommandBuilder mcb = new MySqlCommandBuilder(mySqlDataAdapter);
mySqlDataAdapter.UpdateCommand = mcb.GetUpdateCommand();
mySqlDataAdapter.Update(changes);
((DataTable)dataGridView1.DataSource).AcceptChanges();
MessageBox.Show("Cell Updated");
return;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
You are not updateing your changes to the database. While you keep your connection open doesn't mean that this will automatically update your data.
First of all, don't keep your connection open. In your app you have a connect button which is good for testing but not for really keeping the connection open, not with databases in my opinion.
The way you load data is correct.
You give the datagridview an DataSource which is a table from your DataSet. So changes made in the datagridview ARE saved to your DataSet but not to your database.
This is how you update your database
public void UpdateTable(DataSet ds)
{
using (MySqlConnection connect = new MySqlConnection(ConnString))
{
connect.Open();
MySqlDataAdapter adapt = new MySqlDataAdapter();
MySqlCommandBuilder commbuilder = new MySqlCommandBuilder(adapt);
adapt.SelectCommand = new MySqlCommand("SELECT * FROM t_receipients", connect);
adapt.Update(ds.Tables[0]);
}
}
Make sure, before you Update your database, you use datagridview1.EndEdit()
Also, you using, this will ensure a connection is closed again after completing that code, best is to always have it in a try-except.
You had struggles with connecting the database as it appears to be in the commends.
I've also forgot to include MySqlDataAdapter above, I used an adapter globally in that case.
I didn't want to report this question as duplicated, but now it kinda does look like this answer.
I would like to give code which I have tested in my application.I used it for button click event.
private void button3_Click(object sender, EventArgs e)
{
string StrQuery;
try
{
string MyConnection2 = "server=localhost;user id=root;password=;database=k";
using (MySqlConnection conn = new MySqlConnection(MyConnection2))
{
using (MySqlCommand comm = new MySqlCommand())
{
comm.Connection = conn;
conn.Open();
for (int i = 0; i < dataGridView3.Rows.Count; i++)
{
StrQuery = #"update s set Quantity='" + dataGridView3.Rows[i].Cells["Quantity"].Value.ToString() + "' where No='" + dataGridView3.Rows[i].Cells["Item No"].Value.ToString() + "';";
comm.CommandText = StrQuery;
comm.ExecuteNonQuery();
}
}
}
}
catch
{
}
}
I think it may help you