ComboBox- SelectionChanged Zdarzenie ma starą wartość, a nie nową wartość


92

C #, .NET 4.0, VS2010.

Nowość w WPF. Mam ComboBox w moim MainWindow. Podłączyłem zdarzenie SelectionChanged wspomnianego pola kombi. Jeśli jednak sprawdzę wartość pola kombi w module obsługi zdarzeń, ma on starą wartość. To brzmi bardziej jak zdarzenie „SelectionChanging” niż zdarzenie SelectionChanged.

Jak uzyskać nową wartość ComboBox po dokonaniu wyboru?

W tej chwili:

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

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

Uwaga: otrzymuję to samo zachowanie, jeśli używam przekazywanego obiektu w args zdarzenia, np. EOriginalSource.


2
Właśnie natknąłem się na ten sam problem - dzięki! Czy to faktycznie błąd i powinien zostać nazwany SelectionChangingw pierwszej kolejności?
Sty

Odpowiedzi:


110

Według MSDN e.AddedItems:

Pobiera listę zawierającą wybrane elementy.

Możesz więc użyć:

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

Możesz również użyć, SelectedItemjeśli używasz stringwartości dla Itemsz sender:

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

lub

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

Ponieważ oba obiekty Contenti SelectedItemsą obiektami, bezpieczniejszym podejściem byłoby użycie .ToString()zamiastas string


11
ciekawe ... ma nową wartość. A RemovedItems ma stary plik. Ta nazwa wydarzenia jest trochę myląca, przynajmniej IMHO. Kiedy widzę SelectionChanged, spodziewam się, że stan obiektu się zmienił. Widzę jednak, jak to daje nam nieco więcej informacji.
Matt

1
Tak, myślę, że to dlatego, że zmiana nastąpiła, ale nie została popełniona? To tylko przypuszczenie. Możesz uzyskać tekst wybranego elementu, zobacz moją edycję.
SwDevMan81

3
ComboBox.SelectedItemnie ma właściwość o nazwie Text, ale można to zrobić ComboBox.SelectedItem as string(chociaż to może działać tylko wtedy, gdy używasz stringdo Items- nie testowano cokolwiek innego)
musefan

1
Po prostu string text = (string) e.AddedItems [0];
Igor Semin

1
Chciałbym móc dać 2 ups, twoja odpowiedź pomogła mi dwukrotnie w 2 różnych okazjach
Upulie Han

59

Poprawną wartością do sprawdzenia w tym miejscu jest właściwość SelectedItem .

ComboBox to kontrolka złożona, której dwie części to:

  1. Część tekstowa : wartość w tej części odpowiada właściwości Text elementu ComboBox.
  2. Część selektora (tj. Część „rozwijana”): wybrany element w tej części odpowiada właściwości SelectedItem .

Rozszerzone części ComboBox

Powyższe zdjęcie zostało zrobione zaraz po rozwinięciu ComboBox (tj. Przed wybraniem nowej wartości). W tym momencie zarówno Text, jak i SelectedItem to „Info”, przy założeniu, że elementy ComboBox były ciągami. Gdyby elementy ComboBox były zamiast tego wszystkimi wartościami Enum o nazwie „LogLevel”, SelectedItem byłoby obecnie LogLevel.Info .

Kliknięcie elementu w menu rozwijanym powoduje zmianę wartości SelectedItem i wywołanie zdarzenia SelectionChanged . Właściwość Text nie została jeszcze zaktualizowana, ponieważ część tekstowa nie jest aktualizowana do momentu zakończenia obsługi SelectionChanged . Można to zaobserwować, umieszczając punkt przerwania w programie obsługi i patrząc na kontrolkę:

ComboBox w punkcie przerwania w programie obsługi SelectionChanged

Ponieważ część tekstowa nie została w tym momencie zaktualizowana, właściwość Text zwraca poprzednio wybraną wartość.


2
Całkowite rozszerzenie i pomogło to uświadomić sobie, że moje Binding znajdowało się we właściwości Text zamiast prawidłowego SelectedItem.
cmousset

1
@DaveKidder Świetny przykład! +1
Ryan Wilson

47

Użyj zdarzenia DropDownClosed zamiast selectionChanged, jeśli chcesz uzyskać bieżącą wartość pola kombi.

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

To naprawdę takie proste.


10
@jvelez Myślę, że nie uruchomi się podczas korzystania z klawiatury.
NoviceProgrammer

to jest do bani. Nowicjusz, który wiedział ...!
ukryte

10

To zadziałało dla mnie:

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

w jakiś sposób tylko SelectedItem zostanie wypełnione nowym elementem, a nie SelectedValue.
mauris

7

To zadziałało dla mnie:

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

To jest bardzo ważne. Z zaakceptowanej odpowiedzi nie wynika jednoznacznie, że senderzawiera poprawną odpowiedź SelectedItem.
Jess

4

Następujące zdarzenie jest wyzwalane w przypadku dowolnej zmiany tekstu w ComboBox (gdy wybrany indeks zostanie zmieniony, a tekst również zostanie zmieniony przez edycję).

<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();
}

6
Nie udzielaj odpowiedzi zawierających tylko kod. Proszę wyjaśnić, dlaczego Twoje rozwiązanie jest odpowiedzią.
Lee Taylor

1

Druga opcja nie zadziałała dla mnie, ponieważ element .Text był poza zakresem (C # 4.0 VS2008). To było moje rozwiązanie ...

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

0

Musiałem rozwiązać ten problem w VB.NET. Oto, co mam, co wydaje się działać:

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

To dziwne, że SelectedItem przechowuje świeże dane, podczas gdy SelectedValue nie. Dla mnie brzmi to jak błąd. Jeśli twoje przedmioty w Combobox są obiektami innymi niż ComboBoxItems, będziesz potrzebować czegoś takiego: (moje ComboBoxzawiera 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.SelectedItemmoże być null, podczas gdy Visual Studio ciągle mówi mi, że a KeyValuePairnie może być null. Dlatego rzuciłem wartość SelectedItemnull KeyValuePair<string, string>?. Następnie sprawdzam, czy selectedItemma wartość inną niż null. To podejście powinno mieć zastosowanie do dowolnego typu wybranego przedmiotu.


0

Jeśli naprawdę potrzebujesz SelectionChangedwydarzenia, najlepszą odpowiedzią jest odpowiedź SwDevMan81. Jeśli jednak zaczynasz od WPF, możesz chcieć dowiedzieć się, jak robić rzeczy w sposób WPF, który różni się od starych dni Windows Forms, które wcześniej polegały na zdarzeniach, takich jak SelectionChangedWPF i wzorzec ViewModel widoku modelu, powinieneś użyj powiązań. Oto przykład kodu:

// 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();
}

Użycie e.AddedItems[0] as kProjectwhere kProject jest klasą, która przechowuje dane, działało dla mnie, ponieważ domyślnie korzystało z RemovedItems [0], zanim dokonałem tego wyraźnego rozróżnienia. Dzięki SwDevMan81 za wstępne informacje, które odpowiedziały mi na to pytanie.


0

Nie komplikuj rzeczy bez powodu. Używając właściwości SelectedValue, możesz łatwo pobrać wybraną wartość ComboBox, taką jak ta: YourComboBoxName.SelectedValue.ToString ().

Za sceną właściwość SelectedValue jest zdefiniowana jako: SelectedValue {get; set;} oznacza to, że możesz go użyć do pobrania lub ustawienia wartości ComboBox.

Używanie SelectedItem nie jest wydajnym sposobem na uzyskanie wartości ComboBox, ponieważ wymaga wielu konsekwencji.


0

Możesz sprawdzić SelectedIndex lub SelectedValue lub SelectedItem właściwość w zdarzeniu SelectionChanged kontrolki Combobox.


-2

To powinno działać dla Ciebie ...

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

2
Czy możesz wyjaśnić, jak to odpowiada na pytanie?
Nathan Tuggy,

-3

Rozwiązałem to za pomocą zdarzenia DropDownClosed, ponieważ jest ono uruchamiane nieco po zmianie wartości.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.