I have a WPF Browserapplication which gets data stored on a SQL Server, stores it in a DataTable and displays it in a DataGrid. Now I want to have a TextBox where you can search entries in the DataTable but when I load the Application I'm getting an error telling me, that the row [Company] cannot be found.
I think the problem is, that the DataTable isn't yet filled when the filter is being applied to the DataTable. Can someone please give me a hint how to make this working?
DataTable dt = new DataTable();
public Page1()
{
InitializeComponent();
showSQLData();
}
private void showSQLData()
{
string sqlConnectionString = #"blabla";
string sqlCommandString = "SELECT * FROM Excel_import";
using (SqlConnection sqlConnection = new SqlConnection(sqlConnectionString))
{
SqlCommand cmd = new SqlCommand(sqlCommandString, sqlConnection);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(dt);
dataGridSQLData.ItemsSource = dt.DefaultView;
}
}
private void textBoxSearch_TextChanged(object sender, TextChangedEventArgs e)
{
dt.DefaultView.RowFilter = string.Format("Company LIKE '%{0}%'", textBoxSearch.Text);
}
Based on you latest comment I would guess that textBoxSearch_TextChanged is being fired from within the InitializeComponent() call. You could check that dt.Rows.Count > 0 in textBoxSearch_TextChanged and return if that condition is not met.
Related
The search method is here:
private void textBox1_TextChanged(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("Data Source=DESKTOP-HNR3NJB\\mysql;Initial Catalog=stock;Integrated Security=True");
SqlDataAdapter sda = new SqlDataAdapter("SELECT ProductName FROM [stock].[dbo].[Products]", con);
sda.Fill(dt);
dataGridView1.DataSource = dt;
dt.DefaultView.RowFilter = string.Format("ProductName LIKE '%{0}%'", textBox1.Text);
}
Now that does filter out the results in the table, but it adds columns like the picture below:
Search Results
Load data function (gets called as soon as the form is loaded:
public void LoadData()
{
SqlConnection con = new SqlConnection(#"Data Source=DESKTOP-HNR3NJB\mysql;Initial Catalog=stock;Integrated Security=True");
con.Open();
//reading data from sql
SqlDataAdapter sda = new SqlDataAdapter("SELECT * FROM [stock].[dbo].[Products]", con);
dt = new DataTable();
sda.Fill(dt);
dataGridView1.Rows.Clear();
foreach (DataRow item in dt.Rows)
{
int n = dataGridView1.Rows.Add();
dataGridView1.Rows[n].Cells[0].Value = item["ProductID"].ToString();
dataGridView1.Rows[n].Cells[1].Value = item["ProductName"].ToString();
if ((bool)item["ProductStatus"])
{
dataGridView1.Rows[n].Cells[2].Value = "Active";
}
else
{
dataGridView1.Rows[n].Cells[2].Value = "Inactive";
}
dataGridView1.Rows[n].Cells[3].Value = item["Employee"].ToString();
dataGridView1.Rows[n].Cells[4].Value = item["CPU"].ToString();
dataGridView1.Rows[n].Cells[5].Value = item["RAM"].ToString();
dataGridView1.Rows[n].Cells[6].Value = item["SSD"].ToString();
dataGridView1.Rows[n].Cells[7].Value = item["HDD"].ToString();
dataGridView1.Rows[n].Cells[8].Value = item["WindowsVersion"].ToString();
dataGridView1.Rows[n].Cells[9].Value = item["Description"].ToString();
dataGridView1.Rows[n].Cells[10].Value = item["Type"].ToString();
}
con.Close();
}
Thanks
OK, so you're filling the datagridview elsewhere. You would just need to apply the rowfilter to the view to in the textbox_textchanged event
Where you're populating your current datagridview, ensure that you have your dt instantiated in a wider scope so that the textbox event can access it and then all you should have to do in your textchanged event is the following line:
dt.DefaultView.RowFilter = string.Format("ProductName LIKE '%{0}%'", textBox1.text);
This should then limit the rows to what is currently found. Here's an example of a demo database (you will have to change this to suit your needs)
DataTable dt; //declared outside a method so that multiple methods have access to it object.
private void Form1_Load(object sender, EventArgs e)
{
//Some other area where the datagridview is populated with more information
SqlConnection con = new SqlConnection(#"MyConnectionString");
con.Open();
SqlDataAdapter sda = new SqlDataAdapter("SELECT FirstName, LastName, Address, State FROM Employee", con);
dt = new DataTable();
sda.Fill(dt);
dataGridView1.DataSource = dt;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
//all that should be needed to filter the datagridview to your condition
dt.DefaultView.RowFilter = string.Format("FirstName LIKE '%{0}%'", textBox1.Text);
}
Of course, you really need to switch to using statements so that the objects used are disposed of properly but this is to show more that the basic reason your grid is doing this is that you are applying another datasource into the grid and it doesn't know that you still want all the information you had prior just limited to rows that match your filter.
EDIT - FOR CLARIFICATION
Let's do this. In your loaddata code, remark out the entire for each loop. Add the following lines
datagridview1.columns.clear();
datagridview1.datasoure = dt;
This will hide your pre-existing columns for now without you having to do it manually.
And should show the grid with all the information from the query.
Then in your textchanged event remark all your code and replace it with the line I showed above that uses the DefaultView of the datatable (dt)
That should get you up and running. Once that's done, we can make a change to the query that will allow you to show 'Active'/'InActive' instead of the checkbox for the bit field.
I use visual studio 2012: c# winform. I have a datagridview in which 2 columns(Id and society) are created. the datagridview contains 25 records fetched my database.
I also added a button named "Action" to each row in datagridview
Note: In my phpmyadmin database, each society contains many service category and service types
My problem is:
I want that when a button "action" is pressed, all the service category and service type related to that society appear in the same or another datagridview.
Could you help me?
Try somthing like that, you must initiate this function with your main DataGridView, and you will have your "Cloned" DataGridView.
public DataGridView CloneDataGrid(DataGridView mainDataGridView)
{
DataGridView cloneDataGridView = new DataGridView();
if (cloneDataGridView.Columns.Count == 0)
{
foreach (DataGridViewColumn datagrid in mainDataGridView.Columns)
{
cloneDataGridView.Columns.Add(datagrid.Clone() as DataGridViewColumn);
}
}
DataGridViewRow dataRow = new DataGridViewRow();
for (int i = 0; i < mainDataGridView.Rows.Count; i++)
{
dataRow = (DataGridViewRow)mainDataGridView.Rows[i].Clone();
int Index = 0;
foreach (DataGridViewCell cell in mainDataGridView.Rows[i].Cells)
{
dataRow.Cells[Index].Value = cell.Value;
Index++;
}
cloneDataGridView.Rows.Add(dataRow);
}
cloneDataGridView.AllowUserToAddRows = false;
cloneDataGridView.Refresh();
return cloneDataGridView;
}
Hope This Help
If i understand your question correctly, you could use a cell content click event to refill your datatable with the filtered results.
I've done this on one of my forms (see below), however I havent used a phpmyadmin database, only sql, but the logic might be the same.
I should also note that I have the default cell selection as full row select.
For arguments sake, let's say the form shows products, so ProductID, ProductName and ProductType. When we click the button in the grid we want it to filter by the selected row's ProductType.
//First we declare a static string that can be accessed by the whole form
//and blank it so the form doesnt use a previous value.
public static string product_type = ""
//In the form load event, the gridview is populated - this could be moved to anywhere.
private void Form1_Load(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection("DB connection string");
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Products", conn);
SqlDataAdapter sqlDataAdap = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sqlDataAdap.Fill(ds);
DataTable dt = new DataTable();
sqlDataAdap.Fill(dt);
conn.Close();
}
//In the cell contect click event we give it the ProductType
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
//Here we declare a var to identify that we're looking at the row
var row = dataGridView1.CurrentRow.Cells;
//Now we set the string we declared earlier
product_type = Convert.ToString(row["ProductType"].Value);
//Now we repeat the grid script with a parameter which uses our string from above
SqlConnection conn = new SqlConnection("DB connection string");
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Products WHERE ProductType = #ProductType", conn);
sc.Parameters.Add("#ProductType", SqlDbType.Int).Value = product_type;
SqlDataAdapter sqlDataAdap = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
sqlDataAdap.Fill(ds);
DataTable dt = new DataTable();
sqlDataAdap.Fill(dt);
conn.Close();
}
You could then just add a button which repeats the script from the form load event when clicked to return the grid to it's non-filtered state.
Hope this helps.
Two comboBox and a table called MAINCATE is created.
I have a code , but stuck to determine what SQLQuery should i use to get the second combo box filled , determined by the first combo box.
I just need a little help on how to fill in the second combobox based on mainCate picked by the first combobox..
i need to do something like.. if combobox 1 mainCate is "Food" , then combo box 2 should show "Raw , cooked , fruits and vegetables"
This is what is inside of the MAINCATE table -
(http://i.imgur.com/qR90Z2B.png)
And this is my code :-
DataSet ds1;
DataSet ds2;
public User()
{
InitializeComponent();
}
private void User_Load(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=PEWPEWDIEPIE\\SQLEXPRESS;Initial Catalog=master;Integrated Security=True";
conn.Open();
SqlDataAdapter daMain = new SqlDataAdapter("SELECT * FROM MAINCATE", conn);
ds1 = new DataSet();
daMain.Fill(ds1, "Maincate");
mainCatU.DisplayMember = "mainCate";
mainCatU.ValueMember = "mainCate";
mainCatU.DataSource = ds1.Tables["MAINCATE"];
mainCatU.DropDownStyle = ComboBoxStyle.DropDownList;
mainCatU.Enabled = true;
SqlDataAdapter daSub = new SqlDataAdapter("SELECT >What should i do here?<", conn);
ds2 = new DataSet();
daSub.Fill(ds2, "Subcate");
subCatU.DisplayMember = "Subcat1";
subCatU.ValueMember = "Subcat";
subCatU.DataSource = ds2.Tables["MAINCATE"];
subCatU.DropDownStyle = ComboBoxStyle.DropDownList;
subCatU.Enabled = true;
conn.Close();
}
private void mainCatU_SelectionChangeCommitted(object sender, EventArgs e)
{
//have no idea if a code should be here..
}
or should i do something like this?
SqlCommand cmd = new SqlCommand("select Subcat1,Subcat2,Subcat3,Subcat4 from MAINCATE where mainCate=#mainCate;", con);
=========================================
#philip -
putting this on page load repalcing my code above - it didnt work..
string result = mainCatU.SelectedItem.ToString();
SqlDataAdapter daSub = new SqlDataAdapter("SELECT * FROM MAINCATE where mainCate = " + result , conn);
ds2 = new DataSet();
daSub.Fill(ds2, "Subcate");
subCatU.DisplayMember = "Subcat1";
subCatU.ValueMember = "Subcat1";
subCatU.DataSource = ds1.Tables["MAINCATE"];
subCatU.DropDownStyle = ComboBoxStyle.DropDownList;
subCatU.Enabled = true;
even tried
SqlDataAdapter daSub = new SqlDataAdapter("SELECT * FROM MAINCATE where mainCate=#result", conn);
Actually, you don't need another sql query,because you already get all maincate records from database.You can simply use dictionary to store this records.
First define a Dictionary<string,List<string>>
Define it here(!)
DataSet ds1;
DataSet ds2;
Dictionary<string,List<string>> allRecords = new Dictionary<string,List<string>>();
Then: (i edit your code)
SqlDataAdapter daMain = new SqlDataAdapter("SELECT * FROM MAINCATE", conn);
ds1 = new DataSet();
daMain.Fill(ds1, "Maincate");
DataTable dt = ds1.Tables["MAINCATE"];
foreach (DataRow dr in dt.Rows)
{
List<string> SubCats = new List<string> {
dr["Subcat1"].ToString(),
dr["Subcat2"].ToString(),
dr["Subcat3"].ToString(),
dr["Subcat4"].ToString()
};
allRecords.Add(dr["mainCate"].ToString(),SubCats);
mainCatU.Items.Add(dr["mainCate"].ToString());
}
mainCatU.DropDownStyle = ComboBoxStyle.DropDownList;
mainCatU.Enabled = true;
Then you need to handle mainCatU selectionchanged like this:
if(allRecords.ContainsKey(mainCatU.SelectedItem.ToString())) {
subCatU.DataSource = allRecords[mainCatU.SelectedItem.ToString()];
}
I think this is what your looking for:
Fill the first combo box with your current code.
Then to fill the second combo box you need to hook up the first combo box selectionchangecommitted. However why not just use the standard event?
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//Here use if statements to capture what value is set
if (comboBox1.SelectedIndex = 1)
//If selected value is Vehicles
{
//Then SELECT * FROM MainCate WHERE MainCate = 'Vehicles'
//This is possibly incorrect as I don't know how your DBTable is structured
//Same code as before
//Set this data to the second combobox
}
}
OK? So look into implementing this, if you want to refactor this you could, rather than using IF statements you could parametrise -
string result = comboBox1.SelectedItem.ToString();
SELECT * FROM MainCate WHERE MainCate = result
Obviously this won't compile so don't copy then paste it, then come back saying it doesn't work. It needs to be implemented like you did before, but rather than hardcode the result each time, use the parameter.
Personally I wouldn't have this all in one class, however you may prefer this way.
ComboBox1, ComboBox2 -- you just want to populate ComboBox2 using ComboBox1 Select change. So, At first bind your ComboBox1. Then cretae an event for ComboBox1:
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string value1 = ComboBox1 .SelectedValue.ToString();
LoadComboBox2 ();
}
And Get your ComboBox1 selected value and use it to populate ComboBox2 .
private void LoadComboBox2 ()
{
DataRow dr;
SqlConnection con = new SqlConnection(#"Data Source=name;Initial Catalog=dbName;User ID=sa;Password=sa123");
con.Open();
SqlCommand cmd = new SqlCommand("select id,name from table where id=#ID", con);
SqlDataAdapter sda = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sda.Fill(dt);
dr = dt.NewRow();
dr.ItemArray = new object[] { 0, "--Select--" };
dt.Rows.InsertAt(dr, 0);
ComboBox2 .ValueMember = "ID";
ComboBox2 .DisplayMember = "Name";
ComboBox2 .DataSource = dt;
con.Close();
}
I am a newbie in C# so I don't know if I will address my problem correctly so please bear with me. I have 3 DataGridViews (datagridview1, datagridview2, datagridview3). All are located in the same window but they are in a different tab (I have a tab control).
The purpose of each DataGridView is to display data for three tables from database. So every time I click a button, it retrieves data. But here is my problem, when datagridview1 displays the data after clicking the button, then I go to the next tab and click again the retrieve button, the datagridview2 shows the data that was displayed to datagridview1. Same thing to datagridview3.
I'm using DataTable as the data source for those DataGridViews. And somewhere in my script the query will change so I think there's no problem with the query. What I found is that the DataTable does not clear it's data even when the query already changed.
I'm using WinForms, please help me. Thanks.
Here is the code I used in binding the datagridview to a datasource:
currentdatagrid.DataSource = execute.InitConn2(query, CompleteTablename);
Note: "execute.InitConn2(query, CompleteTablename)" will return a datatable.
Try doing something like the following example and see if it works for you. The static method GetData returns a new data table each time. You need to update the SqlConnection with your own connection string.
public static void Main(string[] args)
{
DataGrid dg1 = new DataGrid();
DataGrid dg2 = new DataGrid();
DataGrid dg3 = new DataGrid();
dg1.DataSource = GetData("select * from table1");
dg1.DataBind();
dg2.DataSource = GetData("select * from table2");
dg2.DataBind();
dg3.DataSource = GetData("select * from table3");
dg3.DataBind();
}
public static DataTable GetData(string sqlQuery) {
try
{
DataTable dt = new DataTable();
// set your connection here
SqlConnection conn = new SqlConnection("");
// execute query with your connection
SqlDataAdapter adapt = new SqlDataAdapter(sqlQuery, conn);
// open connection, fill data and close
conn.Open();
adapt.Fill(dt);
conn.Close();
return dt;
}
catch (Exception ex) {
throw ex;
}
}
To use a dataset use the following:
public static void Main(string[] args)
{
DataGrid dg1 = new DataGrid();
DataGrid dg2 = new DataGrid();
DataGrid dg3 = new DataGrid();
DataSet ds = GetData(#"select * from table1;
select * from table2;
select * from table3");
dg1.DataSource = ds.Tables[0];
dg1.DataBind();
dg2.DataSource = ds.Tables[1];
dg2.DataBind();
dg3.DataSource = ds.Tables[2];
dg3.DataBind();
}
public static DataSet GetData(string sqlQuery) {
try
{
DataSet ds = new DataSet();
// set your connection here
SqlConnection conn = new SqlConnection("");
// execute query with your connection
SqlDataAdapter adapt = new SqlDataAdapter(sqlQuery, conn);
// open connection, fill data and close
conn.Open();
adapt.Fill(ds);
conn.Close();
return ds;
}
catch (Exception ex) {
throw ex;
}
}
I'm having some difficulties understanding how databases and SQL works. I'm trying to update a certain row in my database. I can remove a row, but when i use the InsertAt function, it is always appended to the end of my database. Also, it's assigned a new identifier key.
I would like to just edit what is already in there. No need for a new key, and I would like the edited row to stay where it was.
I've tried to strip down the code to show the the problem.
public partial class MainWindow : Window
{
System.Data.SqlClient.SqlConnection con;
System.Data.SqlClient.SqlDataAdapter da;
DataSet sessions;
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
con = new System.Data.SqlClient.SqlConnection();
sessions = new DataSet();
con.ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFilename=C:\\Users\\md\\PokerDataBase.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True";
con.Open();
string sql = "SELECT * From Sessions";
da = new System.Data.SqlClient.SqlDataAdapter(sql, con);
da.Fill(sessions, "Sessions");
con.Close();
System.Data.SqlClient.SqlCommandBuilder cb;
cb = new System.Data.SqlClient.SqlCommandBuilder(da);
DataTable dt = sessions.Tables["Sessions"];
DataRow table = sessions.Tables["Sessions"].NewRow();
table[0] = "Some Data";
table[1] = "Some Data";
table[2] = "Some Data";
table[3] = 2;
table[4] = 3;
sessions.Tables["Sessions"].Rows[2].Delete();
sessions.Tables["Sessions"].Rows.InsertAt(table, 2);
da.Update(sessions, "Sessions");
}
}
Could anyone help me figure out what I'm doing wrong?
Error
You are creating a new row using
DataRow table = sessions.Tables["Sessions"].NewRow();
This will add new row to you database, it's not going to update a row.
Solution
To update a row you need to select that specific row, something like:
DataRow table = sessions.Tables["Sessions"].Rows[0];
then modify the row data and then update da.
This will the update existing row in your database.