I have a combobox in winform which gets data by calling a stored procedure in MySQL.
My stored proc:
CREATE PROCEDURE `GetCourses`()
BEGIN
SELECT course_name FROM my_db.courses where group_id=1;
END
Now the course names are bind with the Combobox(ComboBox2) as below - on selection of another Combobox(ComboBox1):
private void Form_Load(object sender, EventArgs e)
{
var connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
conn = new MySqlConnection(connectionString);
conn.Open();
MySqlCommand cmd1 = new MySqlCommand();
cmd1.Connection = conn;
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.CommandText = "GetCourses";
DataTable dt1 = new DataTable();
MySqlDataAdapter adp1 = new MySqlDataAdapter(cmd1);
adp1.Fill(dt1);
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 3)
{
comboBox2.ValueMember = "course_name";
comboBox2.DisplayMember = "course_name";
comboBox2.DataSource = dt1;
}
}
But when I run the form, the ComboBox is filled with the values as 'system.data.datarowview'
Could anyone please help me with this.
NOTE: I don't want to achieve this by using 'MySqlDataReader'
Thanks in advance.
This is solved simply by below two lines of code.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 3)
{
foreach (DataRow row in dt1.Rows)
comboBox2.Items.Add(row["course_name"]);
}
}
You could project the data into a collection that has named fields to prevent the default ToString()ing of the datarow objects:
if (comboBox1.SelectedIndex == 3)
{
comboBox2.ValueMember = "course_name_value";
comboBox2.DisplayMember = "course_name";
comboBox2.DataSource = dt1.AsEnumerable().Select
(n => new { course_name = n["course_name"], course_name_value = n["course_name"]}).ToList();
}
EDIT
I think you should put these lines in the Load event. You don't need to set them more than once, and it could be the reason for the combobox display getting the object's ToString() result instead of individual properties.
comboBox2.ValueMember = "course_name";
comboBox2.DisplayMember = "course_name";
I ran a mock test, and I think it's disposing of your dataset(when it finished the OnLoad event) before you can get to the selectedIndex changed event. Try having your SelectedIndexChanged event raise a function to populate the second box. PS, don't mind I used an SQLite database to test.
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
If (ComboBox1.SelectedIndex = 3) Then
Select3()
End If
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim range() As String = {"0", "1", "2", "3 - Fire Combo2", "4", "5", "6"}
ComboBox1.Items.AddRange(range)
End Sub
Private Sub Select3()
Dim connectionString As String = MyStandAloneDB.DBConnStr
Dim conn As New System.Data.SQLite.SQLiteConnection(connectionString)
conn.Open()
Dim cmd1 As New System.Data.SQLite.SQLiteCommand
cmd1.Connection = conn
cmd1.CommandType = CommandType.Text
cmd1.CommandText = "SELECT * FROM Foo"
Dim dt1 As New DataTable()
Dim adp1 As New System.Data.SQLite.SQLiteDataAdapter(cmd1)
adp1.Fill(dt1)
ComboBox2.DataSource = dt1
ComboBox2.ValueMember = dt1.Columns(1).ToString
ComboBox2.DisplayMember = dt1.Columns(0).ToString
End Sub
Related
I have imported an Excel spreadsheet into a datagridview for a Windows Form Application in C#. However I need to then filter the data by 2 conditions, these conditions are that 2 separate text boxes are equal to a certain value inputted by the user. I have attached my code and screenshot of my form. I need the filter to go in the "btnFetch" click event: i.stack.imgur.com/GA6SX.png
I need the data to be filtered by those codes in the data, e.g) Departure Airport = BIKF and Arrival Airport = to EGGW and it will only bring those rows up.
Also is there a way that I can make it so the user selects the location of the Excel file to import through a pop-up window?
Code:
public class frmMain : Form{
public frmMain()
{
InitializeComponent();
}
private void frmMain_Load(object sender, EventArgs e)
{
dg1.Visible = true;
pb1.ImageLocation = “C:/…abc.png;
pb1.SizeMode = PictureBoxSizeMode.Zoom;
}
private void btnOpen_Click(object sender, EventArgs e)
{
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source = C:….abc.xlsx” + #";Extended Properties=""Excel 8.0; HDR=Yes; IMEX=1; ImportMixedTypes=Text;TypeGuessRows=0""";
OleDbCommand command = new OleDbCommand("SELECT * FROM [Sheet1$]",conn);
DataSet ds = new DataSet();
OleDbDataAdapter adpt = new OleDbDataAdapter(command);
adpt.Fill(ds);
dg1.DataSource = ds.Tables[0];
}
private void btnFetch_Click(object sender, EventArgs e)
{
}
private void btnClear_Click(object sender, EventArgs e)
{
txtDepAir.Text = "";`enter code here`
txtDestAir.Text = "";
}
}
Is there a way to let the user choose the excel file?
Yes there is a way,just use an OpenFileDialog.
using (OpenFileDialog OFPD = new OpenFileDialog)
{
if (OPD.ShowDialog== DialogResult.OK) {
OleDbConnection con = new OleDbConnection("DataSource =" + OPD.FileName + "......");
{
}}}
TIP : If retrieved a single table,a dataset is useless.
filter the data by 2 conditions, these conditions are that 2 separate text boxes
You can do that too.As suggested above,either you use a DataTable only or a DataReader.
Filter using DataTable
using (SqlCommand command = new SqlCommand("SELECT * FROM [Sheet1$] WHERE [ONE COLUMN NAME]=#col1 AND [2nd COLUMN NAME]=#col2",conn)
{
command.Parameters.Add("#col1",OledbType.VarChar).Value = txtbx1.Text;
command.Parameters.Add("#col2",OledbType.VarChar).Value = txtbx2.Text;
DataTable dt = new DataTable;
SqlDataAdapter ada = new SqlDataAdapter(command);
ada.Fill(dt)
DataGrdView1.DataSource = dt;
}}
Filter using dataReader
using (SqlCommand command = new SqlCommand("SELECT * FROM [Sheet1$] WHERE [ONE COLUMN NAME]=#col1 AND [2nd COLUMN NAME]=#col2",conn)
{
command.Parameters.Add("#col1",OledbType.VarChar).Value = txtbx1.Text;
command.Parameters.Add("#col2",OledbType.VarChar).Value = txtbx2.Text;
SqlDataReader dr = command.ExecuteReader;
DataGridView1.Rows.Clear();
while (dr.read)
{
DataGridViewRow row = (DataGridViewRow)yourDataGridView.Rows[0].Clone();
row.Cells[0].Value = "XYZ";
row.Cells[1].Value = 50.2;
DataGridView1.Rows.Add(row);
}}}
Hope this helps you :)
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 have an ComboBox1 which is bounded by EmpId which is an primary key also..
when i used the code
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
label5.Text = comboBox1.DisplayMember;
}
it gives an error-
Column 'EmpId' is constrained to be unique. Value 'Emp008' is already
present.
My question is How to select that bounded value and display it into an Label text..
You can use this code comboBox1.SelectedValue to get selected value or for text you can use this code comboBox1.SelectedText
private void bind()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["AttendanceManagmentSystem.Properties.Settings.Cons1"].ConnectionString);
con.Open();
SqlDataAdapter da = new SqlDataAdapter("Select EmpId from EmpDetail", con);
DataTable dt = new DataTable();
da.Fill(dt);
comboBox1.DisplayMember = "EmpId";
comboBox1.ValueMember = "EmpId";
comboBox1.DataSource = dt;
con.Close();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
label5.Text = comboBox1.Text;
}
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'm new developing and I need a detailed answered, I'm sorry for my bad english...
I will try to explain myself the best I can..
I've 2 tables in Mysql
table1: id_ticket , ticket_description, ticket_status(id_status)
table2 : id_statu , status_name
In my application I use all the information inside table1 to fill a DataGridView, also I've added a comboBox column, the combobox displays "status_name" from table2, I want to modify ticket_status with the information contained in the comboBox, how can I do that?
this is my code:
public void CreateAssignedToMe(string ConnString)
{
string assignedTo = textBoxUid.Text;
string query = "SELECT * FROM reports WHERE ticket_assignee='"+assignedTo+"' AND ticket_resolution < 3;";
AssignToMe = new AssignedToMe();
AssignToMe.ConnString = ConnString;
DataGridView dgvReports = AssignToMe.dataGridViewAssignedToMe;
try
{
MySqlConnection conn = new MySqlConnection(ConnString);
conn.Open();
MySqlDataAdapter daUsers = new MySqlDataAdapter(query,ConnString);
DataSet dsUsers = new DataSet();
daUsers.Fill(dsUsers,"report");
dgvReports.DataSource = dsUsers;
dgvReports.DataMember = "report";
dgvReports.AllowUserToAddRows = false;
dgvReports.AllowUserToDeleteRows = false;
dgvReports.Columns["ticket_departmentResponsive"].Visible = false;
dgvReports.Columns["ticket_assignee"].Visible = false;
string queryStatus = "SELECT * FROM status";
MySqlDataAdapter daStatus = new MySqlDataAdapter(queryStatus, ConnString);
DataSet dsStatus = new DataSet();
MySqlCommandBuilder builder = new MySqlCommandBuilder(daStatus);
daStatus.Fill(dsStatus, "Resolution");
daStatus.UpdateCommand = builder.GetUpdateCommand();
DataGridViewComboBoxColumn cbbox = new DataGridViewComboBoxColumn();
BindingSource StatusBindingSource = new BindingSource();
StatusBindingSource.DataSource = dsStatus;
StatusBindingSource.DataMember = "Resolution";
cbbox.HeaderText = "Resolution";
cbbox.DropDownWidth = 90;
cbbox.DataSource = StatusBindingSource;
cbbox.DisplayMember = "status_name";
dgvReports.Columns.Add(cbbox);
AssignToMe.ShowDialog();
}
catch(MySqlException ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
I'm not able to post Images :(
You have to add DataGridView.CellValueChanged Event. Function assigned to that event will be executed when you change any cell value.
// adding event handler (somewhere after dgvReports initialization)
dgvReports.CellValueChanged += new DataGridViewCellEventHandler(dgvReports_CellValueChanged);
// function that handles event
private void dgvReports_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// `e` argument will contain e.RowIndex and e.ColumnIndex properties
// they may be used to determine which particular cell was changed
}
In event handler you should check what column/cell was changed (row and cell index should be passed thru DataGridViewCellEventArgs e argument to your method that handles CellValueChanged event).
After that check - you should "do your update".