Событие ComboBox- SelectionChanged имеет старое значение, а не новое.

C #, .NET 4.0, VS2010.

Впервые в WPF. У меня есть ComboBox на моем MainWindow. Я подключил событие SelectionChanged указанного поля со списком. Однако, если я проверю значение поля со списком в обработчике событий, оно будет иметь старое значение. Это больше похоже на событие SelectionChanging, чем на событие SelectionChanged.

Как мне получить новое значение ComboBox после того, как выбор действительно произошел?

В настоящее время:

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

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

Обратите внимание: я получаю такое же поведение, если использую объект, передаваемый в аргументах события, например. е.OriginalSource.


person Matt    schedule 02.06.2010    source источник
comment
Я наткнулся на ту же проблему - спасибо! Это на самом деле ошибка, и в первую очередь ее следовало назвать SelectionChanging?   -  person Jan    schedule 17.01.2012


Ответы (17)


Согласно MSDN, e.AddedItems:

Получает список, содержащий выбранные элементы.

Итак, вы можете использовать:

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

Вы также можете использовать SelectedItem, если используете string значения для Items из sender:

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

or

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

Поскольку и Content, и SelectedItem являются объектами, более безопасным подходом было бы использовать .ToString() вместо as string

person SwDevMan81    schedule 02.06.2010
comment
интересно ... это новое значение. А в RemovedItems есть старый. Это название события немного, если неправильно, по крайней мере, ИМХО. Когда я вижу SelectionChanged, я ожидаю, что состояние объекта изменилось. Я вижу, как это дает нам немного больше информации. - person Matt; 03.06.2010
comment
Да, я думаю, это потому, что изменение произошло, но не было зафиксировано? Это всего лишь предположение. Возможно, вы сможете получить текст выбранного элемента, см. Мое редактирование. - person SwDevMan81; 03.06.2010
comment
ComboBox.SelectedItem не имеет свойства под названием Text, но вы можете сделать ComboBox.SelectedItem as string (хотя это может работать только в том случае, если вы используете string для Items - ничего другого не проверял) - person musefan; 19.12.2013
comment
Просто строка text = (строка) e.AddedItems [0]; - person Igor Semin; 13.03.2015
comment
Не усложняйте вещи без причины. Используя свойство SelectedValue, вы можете легко получить выбранное значение ComboBox, например: YourComboBoxName.SelectedValue.ToString (). За сценой свойство SelectedValue определяется как: SelectedValue {get; set;} это означает, что вы можете использовать его для получения или установки значения ComboBox. Использование SelectedItem не является эффективным способом получения значения ComboBox, поскольку требует множества ответвлений. - person Sam Tomashi; 07.01.2019
comment
Хотел бы я отказаться от двух апокалипсисов, ваш ответ помог мне дважды в двух разных случаях - person Upulie Han; 22.09.2020
comment
Почему я получаю исключение NullReference, когда использую третий подход? - person krobelusmeetsyndra; 23.09.2020

Правильное значение для проверки здесь - свойство SelectedItem.

ComboBox - это составной элемент управления, две части которого:

  1. Текстовая часть: значение в этой части соответствует свойству Текст поля со списком.
  2. Часть селектора (т. е. «раскрывающаяся» часть): выбранный элемент в этой части соответствует свойству SelectedItem.

Расширенные части ComboBox

Изображение выше было снято сразу после того, как ComboBox был развернут (т.е. перед выбором нового значения). На этом этапе и Text, и SelectedItem являются «Info», если элементы ComboBox были строками. Если бы элементами ComboBox были все значения Enum с именем "LogLevel", SelectedItem в настоящее время был бы LogLevel.Info.

При щелчке по элементу в раскрывающемся списке значение SelectedItem изменяется и возникает событие SelectionChanged. Однако свойство Text еще не обновляется, поскольку текстовая часть обновляется только после SelectionChanged Обработчик готов. Это можно увидеть, установив точку останова в обработчике и посмотрев на элемент управления:

«Поле

Поскольку текстовая часть на этом этапе не обновлялась, свойство Текст возвращает ранее выбранное значение.

person Dave Kidder    schedule 22.07.2015
comment
Полное расширение, и это помогло понять, что моя привязка была в свойстве Text вместо правильного SelectedItem. - person cmousset; 20.10.2015
comment
@DaveKidder Отличный пример! +1 - person Ryan Wilson; 07.12.2018

Используйте событие DropDownClosed вместо selectionChanged, если вам нужно текущее значение поля со списком.

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

Все действительно так просто.

person hidden    schedule 26.04.2011
comment
@jvelez Думаю, при использовании клавиатуры он не срабатывает. - person NoviceProgrammer; 19.08.2011
comment
это отстой. Начинающий программист, который знал ...! - person hidden; 11.04.2013

Это сработало для меня:

private void AppName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
   ComboBoxItem cbi = (ComboBoxItem)AppName.SelectedItem;
   string selectedText = cbi.Content.ToString();
}
person Ramon    schedule 17.11.2010
comment
каким-то образом только SelectedItem заполняется новым элементом, а не SelectedValue. - person mauris; 23.08.2013

Это сработало для меня:

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;            
}
person Бранко Пејић    schedule 13.10.2015
comment
Это очень важно. Принятый ответ явно не показывает, что sender содержит правильный SelectedItem. - person Jess; 21.03.2016
comment
это вызывает у меня исключение: System.NullReferenceException: «Ссылка на объект не установлена ​​на экземпляр объекта». (... как System.Windows.Controls.ComboBoxItem) вернул null. - person Ali Safari; 04.12.2020
comment
@Jess - Я на 100% согласен. Принятый ответ у меня не сработал. Этот сделал. - person BoundForGlory; 22.12.2020

Следующее событие запускается для любого изменения текста в ComboBox (когда изменяется выбранный индекс и когда текст также изменяется путем редактирования).

<ComboBox IsEditable="True" TextBoxBase.TextChanged="cbx_TextChanged" />
person Petr Voborník    schedule 27.03.2017
comment
Работает только для редактируемого ComboBox - person DrKoch; 08.03.2021

Второй вариант у меня не сработал, потому что элемент .Text был вне области видимости (C # 4.0 VS2008). Это было мое решение ...

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

Если вам действительно нужно событие SelectionChanged, лучший ответ - это ответ SwDevMan81. Однако, если вы начинаете с WPF, вы можете узнать, как делать что-то способом WPF, который отличается от старых дней Windows Forms, которые использовались, чтобы полагаться на такие события, как SelectionChanged, с шаблоном WPF и Model View ViewModel, вы следует использовать привязки. Вот пример кода:

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

}
person Lazaro    schedule 06.07.2015

Мне нужно было решить это в VB.NET. Вот что у меня вроде работает:

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
person zzMzz    schedule 22.11.2010

Странно, что SelectedItem хранит свежие данные, а SelectedValue - нет. Для меня это похоже на ошибку. Если ваши элементы в Combobox являются объектами, отличными от ComboBoxItems, вам понадобится что-то вроде этого: (мой ComboBox содержит 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.SelectedItem может быть нулевым, тогда как Visual Studio постоянно говорит мне, что KeyValuePair не может быть нулевым. Вот почему я преобразовал SelectedItem в KeyValuePair<string, string>?, допускающий значение NULL. Затем я проверяю, имеет ли selectedItem значение, отличное от null. Этот подход должен быть применим к любому типу выбранного вами элемента.

person sorrymissjackson    schedule 01.07.2014

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

Использование e.AddedItems[0] as kProject, где kProject - это класс, содержащий данные, сработало для меня, так как по умолчанию использовался RemovedItems [0] до того, как я сделал это явное различие. Спасибо SwDevMan81 за первоначальную информацию, которая ответила на этот вопрос для меня.

person kyjote    schedule 21.04.2016

Не усложняйте вещи без причины. Используя свойство SelectedValue, вы можете легко получить выбранное значение ComboBox, например: YourComboBoxName.SelectedValue.ToString ().

За сценой свойство SelectedValue определяется как: SelectedValue {get; set;} это означает, что вы можете использовать его для получения или установки значения ComboBox.

Использование SelectedItem не является эффективным способом получения значения ComboBox, поскольку требует множества ответвлений.

person Community    schedule 07.01.2019

Вы можете проверить свойство SelectedIndex, SelectedValue или SelectedItem в событии SelectionChanged элемента управления Combobox.

person Hieu - 7347514    schedule 27.11.2019

Из события SelectionChanged поля со списком вы можете получить текст выбранного элемента следующим образом:

        private void myComboBox_SelectionChanged (object sender, SelectionChangedEventArgs e)
        {
        ComboBoxItem comboBoxItem = (ComboBoxItem) e.AddedItems[0];
        string selectedItemText = comboBoxItem.Content.ToString();
        }
person Ali Safari    schedule 04.12.2020

Это должно сработать для вас ...

int myInt= ((data)(((object[])(e.AddedItems))[0])).kid;
person soulexit    schedule 24.10.2013
comment
Вы можете объяснить, как это отвечает на вопрос? - person Nathan Tuggy; 30.03.2015

Я решил это с помощью события DropDownClosed, потому что оно немного срабатывает после изменения значения.

person user5028920    schedule 19.06.2015

person    schedule
comment
Пожалуйста, не предоставляйте ответы, состоящие только из кода. Пожалуйста, объясните, почему ваше решение является ответом. - person Lee Taylor; 24.11.2012
comment
System.InvalidCastException: 'Невозможно привести объект типа' System.String 'к типу' System.Data.DataRowView '.' - person Ali Safari; 04.12.2020