I am using two combo boxes in one of my programs. The first combo box contains the products while the second contains the categories. I have a method which loads he categories on the second combo box from the database when ever a new item is selected on the first combo box "products". The first time i run the program and select an item it loads from the database but if i try it again nothing loads. Please help with what might be causing this.
private void load_schemes(object sender, EventArgs e)
{
DataTable subjects = new DataTable();
DBConnect con = new DBConnect();
using (SqlConnection CONN = con.getConnection())
{
try
{
schemename.Items.Clear();
SqlDataAdapter adapter = new SqlDataAdapter();
String schemeType = schemetype.Text;
firstname.Text = schemetype.Text;
String SQL = "";
if (schemeType == "Family Scheme")
{
SQL = "select schemeID,SCHEMENAME from registration.familyMedicalScheme";
}
else if (schemeType == "Insurance Scheme")
{
SQL = "select schemeID,SCHEMENAME from registration.insurancescheme";
}
else if (schemeType == "Company Scheme")
{
SQL = "select schemeID,SCHEMENAME from registration.companymedicalscheme";
}
adapter.SelectCommand = new SqlCommand(
SQL, CONN);
adapter.Fill(subjects);
schemename.DataSource = subjects;
schemename.DisplayMember = "SCHEMENAME";
//schemename.ValueMember = subjects.;
}
catch (Exception ex)
{
// Handle the error
}
finally
{
CONN.Close();
}
}
}
I changed the solution and used Items.Add instead of data binding method and it is now working
adapter.Fill(subjects);
foreach (DataRow da in subjects.Rows)
{
schemename.Items.Add(da[0].ToString());
}
Related
I am creating an airline booking system and I have 2 combo boxes. The first is for Departure City and the second is for Arrival City. I want to be able to eliminate the choice in the first combo box from the second, as I don't want the same city to be able to be submitted as both the departure and arrival city. I am querying the city names from a database.
Here is my code:
public partial class main : Form
{
public main()
{
InitializeComponent();
string connectionString = #"Base Schema Name=cyanair;data source=C:\Users\Client 0819\source\repos\Cyanair\cyanair.db";
//Departure ComboBox
SQLiteConnection conn = new SQLiteConnection(connectionString);
try
{
conn.Open();
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT * FROM CyanairAirports";
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
comboDeparture.DataSource = dt;
comboDeparture.ValueMember = "Descriptions";
comboDeparture.DisplayMember = "Descriptions";
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//Arrival ComboBox
private void comboDeparture_DisplayMemberChanged(object sender, EventArgs e)
{
string connectionString = #"Base Schema Name=cyanair;data source=C:\Users\Client 0819\source\repos\Cyanair\cyanair.db";
SQLiteConnection conn = new SQLiteConnection(connectionString);
**String city = comboDeparture.DisplayMember;**
try
{
conn.Open();
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT * FROM CyanairAirports WHERE Descriptions IS NOT '" + comboDeparture.SelectedValue.ToString() + "'";
richTextBox1.Text = "SELECT * FROM CyanairAirports WHERE Descriptions IS NOT '" + comboDeparture.SelectedValue + "'";
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
comboArrival.DataSource = dt;
comboArrival.ValueMember = "Descriptions";
comboArrival.DisplayMember = "Descriptions";
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks :)
It looks like you're handling the DisplayMemberChanged event on comboDeparture, and trying to update the values of comboArrival in that handler. However, DisplayMemberChanged only triggers when the DisplayMember property changes.
DisplayMember only tells the control which property to display on a data bound control. It isn't tied to the index or value selected in the ComboBox. So, the only time the code to populate comboArrival runs is in the constructor when you set comboDepartarture.DisplayMember. Instead, handle either ComboBox.SelectedIndexChanged or ComboBox.SelectedValueChanged and set the items of comboArrival.
A few other important things to note about your code.
First, you should use a parameterized query when running Sql Statements, rather than concatenating strings. Concatenating strings as you're doing opens you up to SQL Injection Attacks. I'm not familiar with SqlLite and can't provide you with an example of how to modify your code, but perhaps this question can help.
Second, you don't need to re-run the query every time you change the selected value in comboDeparture. Just add comboArrival's data source as a field on the Form and you can filter it. For example...
public partial class main : Form
{
// Your constructors...
private void comboDepartures_SelectedIndexChanged(object sender, EventArgs e)
{
if (_arrivalsDataSource == null)
{
_arrivalsDataSource = new System.Data.DataTable();
// Load _arrivalsDataSource from the database, basically how you're doing it now.
comboArrival.DataSource = _arrivalsDataSource.DefaultView;
comboArrival.DisplayMember = "Descriptions"
comboArribal.ValueMember = "Descriptions"
}
if (comboDeparture.SelectedIndex == -1)
{
_arrivalsDataSource.DefaultView.RowFilter = null; // Clear the filter.
}
else
{
// Set the filter.
_arrivalsDataSource.DefaultView.RowFilter = $"Description <> '{comboDeparture.SelectedValue}'";
}
}
private System.Data.DataTable _arrivalsDataSource = null;
}
I am trying to populate a combo box from SQL where when I select an Item from the first box the options get limited in the 2nd box. The fist box has a selected index change event, but I can't seem to figure out how to limit the results.
Here is what I have:
private void cb_college_SelectedIndexChanged(object sender, EventArgs e)
{
lb_allMajors.Items.Clear();
lb_allMajors.Items.Add(cb_college.SelectedIndex);
}
private void populateMajors()
{
try
{
string SQL;
SQL = "SELECT DISTINCT major_name FROM majors";
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(SQL, conn);
conn.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
lb_allMajors.Items.Add(reader.GetString(0));
}
}
}
catch (SqlException err)
{
MessageBox.Show(err.Message);
}
}
Each major in the majors table in the database has a college ID column that links to the colleges table. So when you select a college (e.g. Business) I want the major box to only show majors in the college of business.
I'm not 100% on exactly what you're after or what the example is showing, but I think you just need to supply your populateMajors() method with a parameter containing the college ID, or the SelectedIndex, whichever you want to use.
For example:
private void cb_college_SelectedIndexChanged(object sender, EventArgs e)
{
populateMajors(cb_college.SelectedIndex); // OR More likely Get College ID from Combobox
}
private void populateMajors(int CollegeId)
{
try
{
string SQL;
SQL = "SELECT DISTINCT major_name FROM majors WHERE <yourcollegeindexcol> = " + CollegeId;
using (SqlConnection conn = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(SQL, conn);
conn.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
lb_allMajors.Items.Add(reader.GetString(0));
}
}
}
catch (SqlException err)
{
MessageBox.Show(err.Message);
}
}
I doubt that SelectedIndex is the right parameter to send, but you get the picture.
You might find it better to use the ComboBox.DataSource property too rather than Items.Add - search for ComboBox.DataSource online to see it's usage.
I tried to get data from SQL Server (2 tables: Famille and Compte) into 2 comboboxes in the Form_Load().
But as you see the result, it works with the 1st combobox, but the 2nd it shows System.Data.SqlClient.SqlDataReader
This is the Code
private void Tresorerie_Load(object sender, EventArgs e)
{
conn = new SqlConnection(connstring);
conn.Open();
String queryCompte = "select NomCom from Compte";
String queryFamille = "select NomFam from Famille";
commCompte = new SqlCommand(queryCompte, conn);
commFamille = new SqlCommand(queryFamille, conn);
try
{
//Compte
commCompte.CommandType = CommandType.Text;
dreaderCompte = commCompte.ExecuteReader();
while (dreaderCompte.Read())
{
queryCompte = dreaderCompte[0].ToString();
TreComBoxCompte.Items.Add(queryCompte);
}
}
catch (Exception)
{
MessageBox.Show("Problem with load Compte");
}
finally
{
dreaderCompte.Close();
}
try
{
//Famille
commFamille.CommandType = CommandType.Text;
dreaderFamille = commFamille.ExecuteReader();
while (dreaderFamille.Read())
{
queryFamille = dreaderFamille[0].ToString();
TreComBoxFamille.Items.Add(dreaderFamille);
}
}
catch (Exception)
{
MessageBox.Show("Problem with load Famille");
}
finally
{
dreaderFamille.Close();
}
conn.Close();
}
For second combobox you are adding your datareader dreaderFamille:
TreComBoxFamille.Items.Add(dreaderFamille);
while you should add queryFamille:
queryFamille = dreaderFamille[0].ToString();
TreComBoxFamille.Items.Add(queryFamille);
If you pay attention to item texts in your ComboBox you will guess the problem and when you look at code, you will see your guess is true.
for 2nd comboxbox, you are using wrong object to add
TreComBoxFamille.Items.Add(queryFamille);
You should do it like this:
while (dreaderFamille.Read())
{
queryFamille = dreaderFamille[0].ToString();
TreComBoxFamille.Items.Add(queryFamille);
}
I'm loading a table from a database into a CheckedListBox, and now I need to check which items are checked any time the user changes the check status of an item in the first CheckedListBox, and then add the corresponding parts of another table from my database to the second CheckedListBox.
So for example, I have chlbMeal and chlbFood. Inside the chlbMeal there are "Breakfast", "Dinner" and "Lunch". Now when the user selects any of these, I want the corresponding food options to show up in the chlbFood - for example, if "Breakfast" is checked, inside chlbFood we have "Fried eggs", "Eggs and Bacon", etc.
My project is somewhat different but that's the main the idea I want to achieve in this part of it. Here is my code:
private void chlbRadovi_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
if (chlbRadovi.CheckedItems.Count > 0)
{
int[] niz = new int[chlbRadovi.CheckedIndices.Count];
chlbRadovi.CheckedIndices.CopyTo(niz, 0);
foreach (int x in niz)
{
this.tipradovaTableAdapter1.Fill(this.ignaDataSet1.tipradova);
SqlConnection con = new SqlConnection(Konekcija.con);
SqlCommand cmd = new SqlCommand("select IDTR, Naziv from tipradova where IDRad in #IDRad", con);
cmd.Parameters.AddWithValue("#IDRad", chlbRadovi.ValueMember[x]);
SqlDataReader reader;
chlbTipoviRadova.DataSource = ignaDataSet1.tipradova;
chlbTipoviRadova.DisplayMember = "Naziv";
chlbTipoviRadova.ValueMember = "IDTR";
con.Open();
reader = cmd.ExecuteReader();
con.Close();
}
}
else
{
chlbTipoviRadova.DataSource = null;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
How can I do this?
Ok, here we go. First, bind data to your first CheckedListbox:
private string connectionString = "Your connection string";
private void cbListFirst_SetDataSource()
{
// Using block will automatically close connection when it's not used anymore
using (var con = new SqlConnection(connectionString))
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"SELECT Id, Name
FROM dbo.FoodTypes";
try
{
con.Open();
var foodTypes = new List<FoodType>();
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Fill items for first CheckedListBox DataSource
while (reader.Read())
{
foodTypes.Add(new FoodType()
{
Id = (int)reader["Id"],
Name = reader["Name"] as string
});
}
}
// Set first CheckedListBox DataSource
cbListFirst.DataSource = foodTypes;
cbListFirst.DisplayMember = "Name";
cbListFirst.ValueMember = "Id";
}
catch (Exception ex)
{
// Clear DataSource and handle error (should be improved)
cbListFirst.DataSource = null;
MessageBox.Show("Error", ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
After you've done that, you should have ParentIds encapsulated inside your FoodType objects inside DataSource of your first CheckedListbox. Now, you shouldn't use SelectedIndexChanged event, but ItemCheck event instead. So every time user checks or unchecks one of the items event will be triggered. Only problem you have now is that inside this event, new CheckValue of clicked item is not yet applied, but it can be handled easy since we have information about new and old value inside EventArgs. Check this out:
private void cbListFirst_ItemCheck(object sender, ItemCheckEventArgs e)
{
// Clear second CheckedListbox DataSource
cbListSecond.DataSource = null;
var ingridients = new List<Ingridient>();
foreach (var item in cbListFirst.CheckedItems)
{
// If item was previously checked, we want to skip it because it's new value is
// unchecked and we shouldn't be adding it's child items to second CheckedListbox
if (cbListFirst.Items.IndexOf(item) != e.Index)
{
var foodType = (FoodType)item;
ingridients.AddRange(GetIngridientsForFoodType(foodType.Id));
}
}
// If item was previously unchecked, it's child items won't be caught in previous loop
// so we want to explicitly include them inside this if-block if new value is checked
if (e.NewValue == CheckState.Checked)
{
var foodType = (FoodType)cbListFirst.Items[e.Index];
ingridients.AddRange(GetIngridientsForFoodType(foodType.Id));
}
// Finally, bind new DataSource
cbListSecond.DataSource = ingridients;
cbListSecond.DisplayMember = "Name";
cbListSecond.ValueMember = "Id";
}
// This method returns list of Ingridients for single FoodType
private List<Ingridient> GetIngridientsForFoodType(int foodTypeId)
{
using (var con = new SqlConnection(connectionString))
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"SELECT Id, Name
FROM dbo.Ingridients
WHERE FoodTypeId = #FoodTypeId";
cmd.Parameters.AddWithValue("#FoodTypeId", foodTypeId);
try
{
con.Open();
var ingridients = new List<Ingridient>();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
ingridients.Add(new Ingridient()
{
Id = (int)reader["Id"],
Name = reader["Name"] as string
});
}
}
return ingridients;
}
catch (Exception ex)
{
// Handle error (should be improved) and return null
MessageBox.Show("Error", ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Error);
return null;
}
}
}
Now your second CheckedListbox should be filled with child values of items from first CheckedListbox.
I'm starting with C # and I meet some problems.
I would like to know how to refresh the data, when I save data in the second windows form (agregar_en_directorio)
and want to display the new data in the combo box of the first windows form (generar_tarjeta).
The Conexion: conectaraBD.cs
public static SqlConnection ObtenerCOnexion()
{
SqlConnection Conn = new SqlConnection(#"Data source=MY-PC\SQLEXPRESS; Initial Catalog=myDatabase; User Id=user; Password=xxxx");
Conn.Open();
return Conn;
}
The Combo:
public void fillCombo()
{
string SQL = "select id_persona as identificador, clave_de_identificacion +' '+clave_de_la_dependencia +' '+grado_o_titulo+' '+nombre+' '+ ap+' '+ am DetallesCompletos from directorio";
DataTable dt = new DataTable();
using (SqlConnection Conn2 = conectaraBD.ObtenerCOnexion())
{
using (var cmd = new SqlCommand(SQL, Conn2))
{
try
{
dt.Load(cmd.ExecuteReader());
}
catch (SqlException e)
{
MessageBox.Show("Error al Cargar los Datos" + e.ToString(), "Error SQL",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
comboDe.DataSource = dt;
comboDe.ValueMember = "identificador";
comboDe.DisplayMember = "DetallesCompletos";
}
Note: The used code for the combobox is the follow (used similars for the 3 combobox).
And would help me your opinion of the GUI
i solved, but I had to change some things:
public static DataTable dataFortheCombos()
{
DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection(#"Data source=SAMANIEGO-PC\SQLEXPRESS; Initial Catalog=banco_de_datos; User Id=user; Password=xxx");/
string query = "select id_person as identifier, identification_key +' '+dependence_key +' '+degree_or_title+' '+name+' '+ ap+' '+ am as completedetails from directory";
SqlCommand cmd = new SqlCommand(query, connection);
SqlDataAdapter adap = new SqlDataAdapter(cmd);
adap.Fill(dt);
return dt;
}
public static AutoCompleteStringCollection autocompleteCombos()
{
DataTable dt = dataFortheCombos();
AutoCompleteStringCollection coleccion = new AutoCompleteStringCollection();
foreach (DataRow row in dt.Rows)
{
coleccion.Add(Convert.ToString(row["completedetails"]));
}
return coleccion;
}
public void fillCombos()
{
comboFrom.DataSource = dataFortheCombos();
comboFrom.DisplayMember = "completedetails"; //This is the value shown on the combo for the user
comboFrom.ValueMember = "identifier"; // The selectedc value insert as identifier (is a number)
comboFrom.SelectedIndex = -1; //Clear the combo
//NOTE -> The others combos (urned over and sender) using the same data
}
The event --onfocus-- is used to call the refresh when the user is located in the combobox comboFrom
private void comboDe_Enter(object sender, EventArgs e)
{
comboFrom.DataSource = null //Clear the Combo Box
//NOTE -> The others combos (urned over and sender) using the same data
fillCombos();
}