L'événement ComboBox- SelectionChanged a une ancienne valeur, pas une nouvelle valeur


90

C #, .NET 4.0, VS2010.

Nouveau sur WPF. J'ai un ComboBox sur ma MainWindow. J'ai accroché l'événement SelectionChanged de ladite zone de liste déroulante. Cependant, si j'examine la valeur de la zone de liste déroulante dans le gestionnaire d'événements, elle a l'ancienne valeur. Cela ressemble plus à un événement "SelectionChanging" qu'à un événement SelectionChanged.

Comment puis-je obtenir la nouvelle valeur de la zone de liste déroulante une fois la sélection effectuée?

Actuellement:

this.MyComboBox.SelectionChanged += new SelectionChangedEventHandler(OnMyComboBoxChanged);

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

Remarque, j'obtiens le même comportement si j'utilise l'objet passé dans l'événement args, egeOriginalSource.


2
Je viens de trébucher sur le même problème - merci! Est-ce vraiment un bogue, et il aurait dû être nommé SelectionChangingen premier lieu?
Jan

Réponses:


109

Selon MSDN, e.AddedItems:

Obtient une liste qui contient les éléments sélectionnés.

Vous pouvez donc utiliser:

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

Vous pouvez également utiliser SelectedItemsi vous utilisez des stringvaleurs pour le Itemsde sender:

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

ou

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

Puisque les deux Contentet SelectedItemsont des objets, une approche plus sûre consisterait à utiliser .ToString()au lieu deas string


11
intéressant ... il a la nouvelle valeur. Et RemovedItems a l'ancien. Ce nom d'événement est un peu si un abus de langage, du moins à mon humble avis. Quand je vois SelectionChanged, je m'attends à ce que l'état de l'objet ait changé. Je peux voir comment cela nous donne un peu plus d'informations.
Matt

1
Ouais, je pense que c'est parce que le changement s'est produit, mais n'a pas été engagé? C'est juste une supposition. Vous pourrez peut-être obtenir le texte de l'élément sélectionné, voir ma modification.
SwDevMan81

3
ComboBox.SelectedItemn'a pas de propriété appelée Text, mais vous pouvez le faire ComboBox.SelectedItem as string(bien que cela ne fonctionne que si vous utilisez stringpour le Items- rien testé d'autre)
musefan

Just string text = (string) e.AddedItems [0];
Igor Semin

Ne compliquez pas les choses sans raison. En utilisant la propriété SelectedValue, vous pouvez facilement obtenir une valeur de ComboBox sélectionnée comme ceci: YourComboBoxName.SelectedValue.ToString (). Derrière la scène, la propriété SelectedValue est définie comme suit: SelectedValue {get; set;} cela signifie que vous pouvez l'utiliser pour obtenir ou définir la valeur d'un ComboBox. L'utilisation de SelectedItem n'est pas un moyen efficace d'obtenir une valeur ComboBox car elle nécessite beaucoup de ramifications.
Sam Tomashi

59

La valeur correcte à vérifier ici est la propriété SelectedItem .

Un ComboBox est un contrôle composite dont deux de ses parties sont:

  1. La partie texte : la valeur dans cette partie correspond à la propriété Text de la zone de liste déroulante.
  2. La partie de sélection (c'est-à-dire la partie "déroulante"): l'élément sélectionné dans cette partie correspond à la propriété SelectedItem .

Pièces ComboBox étendues

L'image ci-dessus a été prise immédiatement après l'agrandissement de la ComboBox (c'est-à-dire avant de sélectionner une nouvelle valeur). À ce stade, Text et SelectedItem sont tous deux "Info", en supposant que les éléments ComboBox étaient des chaînes. Si les éléments ComboBox étaient à la place toutes les valeurs d'un Enum appelé «LogLevel», SelectedItem serait actuellement LogLevel.Info .

Lorsqu'un élément de la liste déroulante est cliqué sur, la valeur de SelectedItem est modifiée et l' événement SelectionChanged est déclenché. La propriété Text n'est pas encore mise à jour, cependant, car la partie de texte n'est mise à jour qu'après le SelectionChanged gestionnaire est terminé. Cela peut être observé en mettant un point d'arrêt dans le gestionnaire et en regardant le contrôle:

ComboBox au point d'arrêt dans le gestionnaire SelectionChanged

Étant donné que le texte partie n'a pas été mis à jour à ce stade, le texte propriété renvoie la valeur précédemment sélectionnée.


2
Expanation complète et cela m'a aidé à réaliser que ma liaison était sur la propriété Text au lieu du SelectedItem correct.
cmousset

1
@DaveKidder Excellent exemple! +1
Ryan Wilson

46

Utilisez l'événement DropDownClosed au lieu de selectionChanged si vous voulez la valeur actuelle de la zone de liste déroulante.

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

Est-ce vraiment aussi simple que cela.


10
@jvelez Je pense qu'il ne se déclenchera pas lors de l'utilisation d'un clavier.
NoviceProgrammer

ça craint. Programmeur novice qui savait ...!
masqué le

10

Cela a fonctionné pour moi:

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

D'une manière ou d'une autre, seul SelectedItem est rempli avec le nouvel élément, pas SelectedValue.
mauris

7

Cela a fonctionné pour moi:

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

C'est très important. La réponse acceptée ne montre pas explicitement que sendercontient le correct SelectedItem.
Jess

3

L'événement suivant est déclenché pour toute modification du texte dans la zone de liste déroulante (lorsque l'index sélectionné est modifié et lorsque le texte est également modifié par l'édition).

<ComboBox IsEditable="True" TextBoxBase.TextChanged="cbx_TextChanged" />

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

5
Veuillez ne pas fournir de réponses par code uniquement. Veuillez expliquer pourquoi votre solution est la réponse.
Lee Taylor

1

La deuxième option n'a pas fonctionné pour moi car l'élément .Text était hors de portée (C # 4.0 VS2008). C'était ma solution ...

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

0

J'avais besoin de résoudre ce problème dans VB.NET. Voici ce que j'ai qui semble fonctionner:

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

0

Il est étrange que SelectedItem contienne les données fraîches, contrairement à SelectedValue. Cela me semble être un bug. Si vos éléments dans la liste déroulante sont des objets autres que ComboBoxItems, vous aurez besoin de quelque chose comme ceci: (my ComboBoxcontains KeyValuePairs)

var selectedItem = (KeyValuePair<string, string>?)(sender as ComboBox).SelectedItem;
if (!selectedItem.HasValue)
    return;

string selectedValue = selectedItem.Value.Value;  // first .Value gets ref to KVPair

ComboBox.SelectedItempeut être nul, alors que Visual Studio n'arrête pas de me dire que a KeyValuePairne peut pas être nul. C'est pourquoi j'ai converti le SelectedItemen nullable KeyValuePair<string, string>?. Ensuite, je vérifie si selectedItema une valeur autre que null. Cette approche doit être applicable à tout type d'élément sélectionné.


0

Si vous avez vraiment besoin de l' SelectionChangedévénement, la meilleure réponse est celle de SwDevMan81. Cependant, si vous commencez avec WPF, vous voudrez peut-être apprendre à faire les choses à la manière WPF, qui est différente des anciens jours Windows Forms qui SelectionChangedreposaient sur des événements tels que , avec WPF et modèle ViewModel, vous devez utilisez des liaisons. Voici un exemple de code:

// In the Views folder: /Views/MyWindow.xaml:
// ...
<ComboBox ItemsSource="{Binding MyViewModel.MyProperties, RelativeSource={RelativeSource AncestorType=Window}}"
         SelectedItem="{Binding MyViewModel.MyProperty  , RelativeSource={RelativeSource AncestorType=Window}}" />
// ...



// 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<string> _myProperties;
    public  List<string>  MyProperties {
        get { return _myProperties; }
        set { _myProperties = value; NotifyPropertyChanged("MyProperties"); }
    }

}

0
private void indBoxProject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    int NewProjID = (e.AddedItems[0] as kProject).ProjectID;
    this.MyProject = new kProject(NewProjID);
    LoadWorkPhase();
}

L'utilisation du e.AddedItems[0] as kProjectwhere kProject est une classe qui contient les données a fonctionné pour moi car il était par défaut le RemovedItems [0] avant que j'aie fait cette distinction explicite. Merci SwDevMan81 pour les informations initiales qui ont répondu à cette question pour moi.


0

Ne compliquez pas les choses sans raison. En utilisant la propriété SelectedValue, vous pouvez facilement obtenir une valeur ComboBox sélectionnée comme ceci: YourComboBoxName.SelectedValue.ToString ().

Derrière la scène, la propriété SelectedValue est définie comme suit: SelectedValue {get; set;} cela signifie que vous pouvez l'utiliser pour obtenir ou définir la valeur d'un ComboBox.

L'utilisation de SelectedItem n'est pas un moyen efficace d'obtenir une valeur ComboBox car elle nécessite beaucoup de ramifications.


0

Vous pouvez vérifier la propriété SelectedIndex ou SelectedValue ou SelectedItem dans l'événement SelectionChanged du contrôle Combobox.


-2

Cela devrait fonctionner pour vous ...

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

2
Pouvez-vous expliquer comment cela répond à la question?
Nathan Tuggy

-3

J'ai résolu ce problème en utilisant l'événement DropDownClosed, car il se déclenche légèrement après la modification de la valeur.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.