This question already has an answer here:
ComboBox SelectionChanged event fires late
(1 answer)
Closed 5 years ago.
I have 2 ComboBoxes. And the Second ComboBox will Enabled when i Choose/Change the Item in the first ComboBox. But the Second ComboBox always shows me the previous Items.
For example:
I change Item in ComboBox 1. And ComboBox2 don't show me any items.
I change Item in ComboBox 1 again. Now ComboBox2 shows me the items which should shown by first change.
Here is my Code:
private void categoryComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
subCategoryComboBox.Items.Clear();
subCategoryComboBox.IsEnabled = true;
string SelectedCategoryID = ConvertBackCategory(categoryComboBox.Text);
connection = new MySqlConnection(conf.connection_string);
if (this.OpenConnection() == true)
{
try
{
using (MySqlCommand cmd = new MySqlCommand())
{
cmd.Connection = connection;
cmd.CommandText = "SELECT name FROM auftrags_typ_childcategory WHERE category = #CategoryID";
cmd.Parameters.AddWithValue("#CategoryID", SelectedCategoryID);
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
subCategoryComboBox.Items.Add(reader["name"].ToString());
}
}
}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
How I can fix this? / Why it shows me not the current items?
The Text property of the WPF ComboBox is not updated until after the SelectionChanged event is raised. Don't ask me why, but it isn't. They seem to have intended the Text property only to be used for combo boxes with editable text.
Every other relevant property of the ComboBox is updated before SelectionChanged is raised.
SelectedItem, SelectedValue, and SelectedIndex will all be correct and current in your SelectionChanged handler. I answered this question yesterday; you should be able to adapt that answer to your needs without too much trouble, but let me know if you hit a snag.
Related
I have two user controls. One is to input data and another one has a combobox that displays data from my MySQL table.
The use types in data in the first user control and presses a button. This adds the data to a MySQL table. I want to add the data immediately / automatically into the combobox (the other user control).
I would prefer not doing it using an event. If it is not possible and I have to use an event, what event should I use? Can it be an event not associated to the button?
Here is the method that reads data from MySQL and adds it to the combobox :
private void LoadFromDatabase()
{
string query = "select name from country";
MySqlConnection conn = new MySqlConnection(connection);
MySqlCommand command = new MySqlCommand(query,conn);
MySqlDataReader Read;
conn.Open();
Read = command.ExecuteReader();
while(Read.Read())
{
metroComboBox1.Items.Add(Read.GetString("name"));
}
conn.Close();
}
The current result is that I must reload the windows form to load the new data into thecombobox. Without the reload, the combobox only displays the old data. I have put that method under InitializeComponent(); of the combobox user control.
You can use the event click on the comboBox itself, so whenever you click it to open the dropdown it will update the combobox. Make sure to clear the items at the top of the click event to prevent duplicates.
If you truly insist on having no events, you can use a background worker, however for what you're doing it seems like overkill to spawn a thread just for that.
This is an idea of what the final result should look like.
private void comboBox1_Click(object sender, EventArgs e)
{
if (comboBox1.Items.Count > 0)
comboBox1.Items.Clear();
LoadFromDatabase();
comboBox1.SelectedItem = 0;
comboBox1.Text = "Select Item";
}
I'm currently working on the following code.
public void CbParty_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
spPartijen.Children.Clear();
MySqlConnection conn = new MySqlConnection("Server=localhost; Database=imtenb; Uid=root; Pwd=");
conn.Open();
MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT * FROM kandidaten WHERE partij='" + ((DataRowView)cbParty.SelectedItem)["naam"].ToString() + "' ";
MySqlDataReader reader = command.ExecuteReader();
DataTable dtData = new DataTable();
dtData.Load(reader);
MySqlDataAdapter da = new MySqlDataAdapter(command);
da.Fill(dtData);
foreach (DataRow dr in dtData.Rows)
{
TextBox tbId = new TextBox();
tbId.Text = dr["id"].ToString();
tbId.Name = "tbId";
TextBox tb = new TextBox();
tb.Text = dr["kandidaat"].ToString();
tb.Name = "tb";
Button button = new Button();
button.Content = "wijzigen";
button.Click += ChangeKandidaat_Click;
spPartijen.Children.Add(tb);
spPartijen.Children.Add(button);
}
}
public void ChangeKandidaat_Click(object sender, RoutedEventArgs e)
{
conn.ChangeKandidaat(tbId.Text, tb.Text, ((DataRowView)cbParty.SelectedItem)["naam"].ToString());
}
public void ChangeKandidaat(string id, string kandidaat, string partij)
{
try
{
conn.Open();
MySqlCommand command = conn.CreateCommand();
command.CommandText = "UPDATE kandidaten SET kandidaat='kandiddddaat' WHERE partij='#partij' and id='#id'";
command.Parameters.AddWithValue("#id", id);
command.Parameters.AddWithValue("#kandidaat", kandidaat);
command.Parameters.AddWithValue("#partij", partij);
command.ExecuteNonQuery();
MessageBox.Show("De informatie is succesvol gewijzigd");
}
catch (Exception)
{
MessageBox.Show("Er is iets mis gegaan met het toevoegen van je standpunt, probeer het opnieuw.");
}
conn.Close();
}
My problem is that the ChangeKandidaat_Click cannot see the tbId.Text and tb.Text, because is isn't maked yet.
Maybe someone has a solution for me. Or am I doing this kind of thing wrong.
I'm pretty new to wpf and C#.
thank you in advance!
You should look into MVVM and WPF's templating system.
When you have UI with repetition then you should be thinking of an itemscontrol. Bind the itemssource to a List or observablecollection where t is a viewmodel. That would have public properties for each attribute in the thing you're repeating. Then associate the template with t via datatype or just using the itemtemplate property of the itemscontrol.
Let's call t a row viewmodel or rowvm.
That would expose a public icommand property. Bind that to the command of your button and when you click a button, the code you have in the command fires. That "knows" the associated value of Kandidaat because it would be a public property in the rowvm and hence this.Kandidaat.
Itemscontrol:
https://rachel53461.wordpress.com/2011/09/17/wpf-itemscontrol-example/
Instead of just a button you could have a bunch of stuff defined per "row":
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
…..
<TextBlock Text="{Binding Id}" />
<TextBlock Text="{Binding Kandidaat}"
Grid.Column="1"/>
<Button
Grid.Column="2"
Content="DoSomething"
Command="{DoSomethingCommand}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
Simple intro to mvvm and itemscontrol:
https://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx
That's just using a string as a rowvm, you would want a class with Id, Kandidaat and command properties.
Some simple to complicated examples:
https://www.dotnetcurry.com/wpf/1160/wpf-itemscontrol-fundamentals-part1
In order to line the columns of id, kandidaat and buttons up you could use a grid with columns and shared size scope.
https://wpf.2000things.com/tag/issharedsizescope/
Or
You could use a gridview in a listview, which has columns built in.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.listview?view=netframework-4.7.2
Your problem does not show exactly the whole problem. Would be nice to know is this WPF? Windows Forms?
I assume that spParijen is a table or grid which is populated with the tb and button data. These are the initial things I see are wrong and it is all dealing with context:
tbId, tb, and button are populated within the context of the foreach loop. If that collection was later displayed I'd imagine you'd see an empty list. That is because each object created within the context of that foreach loop gets destroyed once you leave the loop or shortly after creating a new instance or very shortly after. The only reason your button does not get destroyed is because you have a binding to your click delegate code.
The second issue is the name of your three variables. They don't tell the next developer what these fields actually represent. I assume that the button represents a chosen candidate so name it as such.
The third problem is that the first variable (tbId) will never exist because it is not saved anywhere.
And finally let's say you have 10 candidates. So if your code worked you would have a list of 10 candidates and 10 buttons. So your click handler will fail or (if they weren't destroyed) you would always process the last candidate you put in the list. You need the button to contain something unique so that you can find the Content of the button and thus the list that each textbox is in.
My suggestion is to populate the children with dr["id"], dr[candidate], button. The click handler logic will first cast sender as a button. Next get the identifier from the button (you could make the tooltip the identity if you are doing WPF). Then search your children until you find that ID. Now continue your process.
I have 1 textbox and 1 Combobox. Now what i want to do is that when user type in Textbox and then when he clicks on ComboxBox the combobox should automatically get filled from database. Below is my code.
public void BindComboBox3(ComboBox comboBox3)
{
SqlDataAdapter da = new SqlDataAdapter("Select batch_id FROM batch where product_id_fk='"+Convert.ToInt32(textBox2.Text)+"'", con);
DataSet ds = new DataSet();
da.Fill(ds, "batch");
comboBox3.ItemsSource = ds.Tables[0].DefaultView;
comboBox3.SelectedValuePath = ds.Tables[0].Columns["batch_id"].ToString();
}
private void comboBox3_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
BindComboBox3(comboBox3);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Enter Product ID " + ex.Message);
}
}
The selection changed event of the combo box should fire after the user click and select a different option. As if your combo box has nothing inside, the user have no way to change oneself the preference. That means the user have to do an extra clicking to fire it, or it just never fires.
You might consider other firing mechanism, such as MouseUp or MouseDown, MouseHover of the combox. You could set a breakpoint at the start of the event, so that you could know whether the event is fired from time to time, while you could separately ensure your code that update from the database does work.
Alternatively, you can trigger the combo box to change through the firing text changed event of the textbox.
Hope it helps.
I am having trouble with a particular situation. The values in my dropdownlist are as follows: 101, 102, 103, but at any point in time the use can add or deactivate items to the dropdown ex: 101, 104, 106.
I have this dropdownlist embedded into a listview edit item template. So if the user adds a record with value 102, then later on deletes this value they cannot edit this value because I get the above error.
So what I am trying to figure out is how I can handle this message to let the use know they cannot edit the record. What I have so far is the ListView_ItemEditing event handler:
protected void LV_Equipment_ItemEditing(object sender, ListViewEditEventArgs e)
{
LV_Equipment.EditIndex = e.NewEditIndex;
e.Cancel = true;
try
{
LV_Equipment.DataBind();
}
catch (Exception ex)
{
//This is telling the user they cannot edit the record.
AlertMessage("you cannot edit this record.");
}
DropDownList UnitIDDDL = (DropDownList)(LV_Equipment.EditItem.FindControl("DropDownList1"));
DropDownList DriverIDDDL = (DropDownList)(LV_Equipment.EditItem.FindControl("DDL_Insert_Drivers"));
//We need to get the driver for the selected unit in the listview.
int ID = DatabaseInteraction.GetUnitDriver(UnitIDDDL.SelectedValue);
//Now that we have the id we can set the ddl.
DriverIDDDL.SelectedValue = ID.ToString();
DriverIDDDL.DataBind();
}
So if the user tries to edit a valid item there is no problem. But if they try to edit a deactivated item from the listview they LV_Equipment.DataBind() method will fail, and the rest of the code will throw an error as the UnitIDDDL and DriverIDDDL are set as null.
Any ideas on how to make this workaround effective?
Ok, here's what you need to do.
Your data binding should be coming from a SQL query of some sort. Let's assume it looks something like this:
string query = "SELECT ItemNumber FROM TableName";
SqlConnection conn;
SqlDataAdapter da = new SqlDataAdapter(query,conn);
DataTable sqlTable = new DataTable("Test");
da.Fill(sqlTable);
LV_Equipment.DataSource = sqlTable;
What you'll want to do is change your query so that it looks something like this:
string query = "SELECT ItemNumber FROM TableName WHERE Active = 'True'";
That should solve your problem.
Add a return to your catch block:
try
{
LV_Equipment.DataBind();
}
catch (Exception ex)
{
//This is telling the user they cannot edit the record.
AlertMessage("you cannot edit this record.");
return; // don't continue to process
}
I've got a ComboBox on a winforms app with this code:
comboBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;
DataTable t = new DataTable();
t.Columns.Add("ID", typeof(int));
t.Columns.Add("Display", typeof(string));
for (int i = 1; i < 2000; i++)
{
t.Rows.Add(i, i.ToString("N0"));
}
comboBox1.DataSource = t;
comboBox1.ValueMember = "ID";
comboBox1.DisplayMember = "Display";
I then follow these steps when the window opens:
Click the ComboBox drop down button -- this displays the list of items and selects the text in the ComboBox
Type '5', '1' ... i.e. I'm looking to use autocomplete to search for 515, 516, etc.
You'll see that the autocomplete window now appears ON TOP of the drop down list. However if I mouse over, it's the obscured drop down window behind the autocomplete window that's receiving the mouse events, including the click. So I think I'm clicking on an autocomplete item but actually clicking on something totally random that I can't see.
Is this a bug in the ComboBox? I'm using Windows 7 if that matters. Am I configuring the ComboBoxwrong somehow?
Note also that using the KEYBOARD uses the autocomplete drop down. So up/down arrow keys are using the front window, but the mouse is using the back window.
Add a single line of code to your ComboBox KeyDown event and the problem is solved!
private void comboBox_NameAndID_KeyDown(object sender, KeyEventArgs e)
{
comboBox_NameAndID.DroppedDown = false;
}
Source
No problem getting a repro for this simply by setting the properties from the PropertyGrid. Behaves this way both in Win7 and Windows XP.
This is broken behavior documented in this feedback article. As indicated, Microsoft is not considering a fix. One possible workaround is to disable autocomplete in a DropDown event handler and re-enable it in a DropDownClosed event handler.
I'm a Brasilian student of encoding and I lose many hours seeking to fix it im my project. And here, I saw it in a few seconds!!!
My code seems like this:
private void populateCombos()
{
persist.ShowLst(dspMember, vlMember,varTable,lstBox,varWhere);
persist.ShowLst(dspMember, vlMember,varTable,ddlist1,varWhere);
persist.ShowLst(dspMember, vlMember,varTable, ddlist2,varWhere);
ddList1.Text = null;
ddList2.Text = null;
lstBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
lstBox.AutoCompleteSource = AutoCompleteSource.ListItems;
lstBox.Text = null;
}
Add to the/a keypress event.
Dim box As ComboBox = sender
box.DroppedDown = False
Select the ComboBox from the design view and set "Append" to the AutoCompleteMode property, this will suggest the item without apearing a window.
That's weired. Your code looks fine to me and I used this the AutoComplete feature a several times and it didn't show both the DropDown and the AutoComplete list.
My suggestion would be
Set the DataSource after the Display/Value Members. I can't remember why but the other caused some problems.
comboBox1.ValueMember = "ID";
comboBox1.DisplayMember = "Display";
comboBox1.DataSource = t;
Set the AutoCompleteSource at the end of your code (after adding the DataSouce)
Maybe that helps.
to only have one open at a time you can use comboBox1.Droppeddown = true open up the regular, false the AutoComplete will only appear
You simply add item in collection.
Now go properties option of combo box choose
AutoCompleteSource=ListItems
AutocompleteMode=suggest
note: autocomplete source have many option as per your requirement :)
WinForms ComboBox DropDown...the answer is this...
write below code in comboBox1 Enter event..
private void comboBox1_Enter(object sender, EventArgs e)
{
comboBox1.DroppedDown = true;
}
Now for comboBox1 AutoComplete...
write this AutoComplete() in page load event..so it work...
public void AutoComplete()
{
try
{
MySqlConnection conn = new
MySqlConnection("server=localhost;database=databasename;user
id=root;password=;charset=utf8;");
MySqlCommand cmd = new MySqlCommand("select distinct
(columnName) from tablename", conn);
DataSet ds = new DataSet();
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
da.Fill(ds, "tablename");
AutoCompleteStringCollection col = new
AutoCompleteStringCollection();
int i = 0;
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
col.Add(ds.Tables[0].Rows[i]["columnName"].ToString());
}
comboBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
comboBox1.AutoCompleteCustomSource = col;
comboBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
Select the ComboBox from the design view and set "None" to the AutoCompleteMode property.