L’evento ComboBox- SelectionChanged ha un valore vecchio, non un nuovo valore

C #, .NET 4.0, VS2010.

Novità di WPF. Ho un ComboBox sulla mia MainWindow. Ho agganciato l’evento SelectionChanged di detta casella combinata. Tuttavia, se esamino il valore della casella combinata nel gestore eventi, ha il vecchio valore. Questo suona più come un evento “SelectionChanging” di un evento SelectionChanged.

Come ottengo il nuovo valore del ComboBox dopo che la selezione è effettivamente avvenuta?

Attualmente:

this.MyComboBox.SelectionChanged += new SelectionChangedEventHandler(OnMyComboBoxChanged); ... private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) { string text = this.MyComboBox.Text; } 

Nota, ottengo lo stesso comportamento se utilizzo l’object che viene passato nell’argomento dell’evento, egeOriginalSource.

Secondo MSDN, e.AddedItems :

Ottiene un elenco che contiene gli elementi che sono stati selezionati.

Quindi puoi usare:

 private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) { string text = (e.AddedItems[0] as ComboBoxItem).Content as string; } 

È anche ansible utilizzare SelectedItem se si utilizzano valori string per gli Items dal sender :

 private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) { string text = (sender as ComboBox).SelectedItem as string; } 

o

 private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) { string text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string; } 

Poiché Content e SelectedItem sono oggetti, un approccio più sicuro sarebbe utilizzare .ToString() anziché as string

Utilizzare l’evento DropDownClosed invece di selectionChanged se si desidera il valore corrente della casella combinata.

 private void comboBox_DropDownClosed(object sender, EventArgs e) { MessageBox.Show(comboBox.Text) } 

È davvero così semplice

Il valore corretto da verificare qui è la proprietà SelectedItem .

Un ComboBox è un controllo composito con due parti:

  1. La parte di testo : il valore in questa parte corrisponde alla proprietà Text di ComboBox.
  2. La parte del selettore (cioè la parte “a discesa”): l’elemento selezionato in questa parte corrisponde alla proprietà SelectedItem .

Parti ComboBox espanse

L’immagine sopra è stata scattata immediatamente dopo l’espansione del ComboBox (cioè prima di selezionare un nuovo valore). A questo punto sia Text che SelectedItem sono “Info”, presupponendo che gli elementi di ComboBox fossero stringhe. Se gli oggetti ComboBox erano invece tutti i valori di un Enum chiamato “LogLevel”, SelectedItem sarebbe attualmente LogLevel.Info .

Quando si fa clic su un elemento nel menu a discesa, il valore di SelectedItem viene modificato e viene generato l’evento SelectionChanged . La proprietà Text non è ancora stata aggiornata, tuttavia, poiché la parte di testo non viene aggiornata fino a quando non viene completato il gestore SelectionChanged . Ciò può essere osservato inserendo un punto di interruzione nel gestore e osservando il controllo:

ComboBox al punto di interruzione nel gestore SelectionChanged

Poiché la parte di testo non è stata aggiornata a questo punto, la proprietà Text restituisce il valore precedentemente selezionato.

Questo ha funzionato per me:

 private void AppName_SelectionChanged(object sender, SelectionChangedEventArgs e) { ComboBoxItem cbi = (ComboBoxItem)AppName.SelectedItem; string selectedText = cbi.Content.ToString(); } 

Questo ha funzionato per me:

 private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) { var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string; } 

L’evento seguente viene triggersto per qualsiasi modifica del testo nel ComboBox (quando l’indice selezionato viene modificato e quando il testo viene modificato anche con la modifica).

  
 private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) { string newItem = ((DataRowView) e.AddedItems[0]).Row.ItemArray[0].ToString(); } 

La seconda opzione non ha funzionato per me perché l’elemento .Text era fuori ambito (C # 4.0 VS2008). Questa era la mia soluzione …

 string test = null; foreach (ComboBoxItem item in e.AddedItems) { test = item.Content.ToString(); break; } 

Avevo bisogno di risolverlo in VB.NET. Ecco cosa ho che sembra funzionare:

 Private Sub ComboBox1_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles ComboBox_AllSites.SelectionChanged Dim cr As System.Windows.Controls.ComboBoxItem = ComboBox1.SelectedValue Dim currentText = cr.Content MessageBox.Show(currentText) End Sub 

È strano che SelectedItem contenga i nuovi dati, mentre SelectedValue no. Mi sembra un insetto. Se i tuoi elementi nella Combobox sono oggetti diversi da ComboBoxItems, avrai bisogno di qualcosa di simile: (il mio ComboBox contiene KeyValuePair s)

 var selectedItem = (KeyValuePair?)(sender as ComboBox).SelectedItem; if (!selectedItem.HasValue) return; string selectedValue = selectedItem.Value.Value; // first .Value gets ref to KVPair 

ComboBox.SelectedItem può essere nullo, mentre Visual Studio continua a dirmi che KeyValuePair non può essere nullo. Ecco perché lancio il SelectedItem su un valore KeyValuePair? . Quindi controllo se selectedItem ha un valore diverso da null . Questo approccio dovrebbe essere applicabile a qualunque tipo sia effettivamente l’object selezionato.

Se hai davvero bisogno dell’evento SelectionChanged , la risposta migliore è SwDevMan81. Tuttavia, se stai iniziando con WPF, allora potresti voler imparare come fare le cose con WPF, che è diverso dai vecchi Windows Form che usavano affidarsi a eventi come SelectionChanged , con WPF e Model View ViewModel, tu dovrebbe usare le associazioni Ecco un esempio di codice:

 // In the Views folder: /Views/MyWindow.xaml: // ...  // ... // In the Views folder: /Views/MyWindow.xaml.cs: public partial class MyWindow : Window { public MyViewModelClass MyViewModel { get { return _viewModel; } private set { _viewModel = value;} } public MyWindow() { MyViewModel.PropertyChanged += MyViewModel_PropertyChanged; } void MyViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (e.PropertyName == "MyProperty") { // Do Work // Put your logic here! } } } using System.ComponentModel; // In your ViewModel folder: /ViewModels/MyViewModelClass.cs: public class MyViewModelClass : INotifyPropertyChanged { // INotifyPropertyChanged implementation: private void NotifyPropertyChanged(string propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; // Selected option: private string _myProperty; public string MyProperty { get { return _myProperty; } set { _myProperty = value; NotifyPropertyChanged("MyProperty"); } } // Available options: private List _myProperties; public List MyProperties { get { return _myProperties; } set { _myProperties = value; NotifyPropertyChanged("MyProperties"); } } } 
 private void indBoxProject_SelectionChanged(object sender, SelectionChangedEventArgs e) { int NewProjID = (e.AddedItems[0] as kProject).ProjectID; this.MyProject = new kProject(NewProjID); LoadWorkPhase(); } 

L’uso di e.AddedItems[0] as kProject cui kProject è una class che contiene i dati ha funzionato per me poiché era predefinito per RemovedItems [0] prima di aver fatto questa distinzione esplicita. Grazie SwDevMan81 per le informazioni iniziali che hanno risposto a questa domanda per me.

Questo dovrebbe funzionare per te …

 int myInt= ((data)(((object[])(e.AddedItems))[0])).kid; 

Ho risolto questo problema utilizzando l’evento DropDownClosed perché si triggers leggermente dopo la modifica del valore.