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

91

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

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

Мэтт
источник
2
Я только что наткнулся на ту же проблему - спасибо! Это действительно ошибка, и ее нужно было назвать SelectionChangingв первую очередь?
Jan

Ответы:

110

Согласно 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;
}

или

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

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

SwDevMan81
источник
11
интересно ... это новое значение. А в RemovedItems есть старый. Это название события немного, если неправильно, по крайней мере, ИМХО. Когда я вижу SelectionChanged, я думаю, что состояние объекта изменилось. Я вижу, как это дает нам немного больше информации.
Мэтт
1
Да, я думаю, это потому, что изменение произошло, но не было зафиксировано? Это всего лишь предположение. Возможно, вы сможете получить текст выбранного элемента, см. Мое редактирование.
SwDevMan81 02
3
ComboBox.SelectedItemне имеет свойства с именем Text, но вы можете это сделать ComboBox.SelectedItem as string(хотя это может работать только в том случае, если вы используете stringдля Items- не проверял что-либо еще)
Musefan
1
Просто строка text = (строка) e.AddedItems [0];
Игорь Семин
1
Хотел бы я отказаться от двух апокалипсисов, ваш ответ помог мне дважды в двух разных случаях
Упули Хан
59

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

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

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

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

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

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

ComboBox в точке останова в обработчике SelectionChanged

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

Дэйв Киддер
источник
2
Полное расширение, и это помогло понять, что моя привязка была связана с свойством Text вместо правильного SelectedItem.
cmousset
1
@DaveKidder Отличный пример! +1
Райан Уилсон
47

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

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

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

скрытый
источник
10
@jvelez Я думаю, он не срабатывает при использовании клавиатуры.
NoviceProgrammer
это отстой. Начинающий программист, который знал ...!
скрыто
10

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

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

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

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;            
}
Бранко Пејић
источник
Это очень важно. В принятом ответе явно не указано, что он senderсодержит правильный SelectedItem.
Джесс
4

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

<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
Пожалуйста, не предоставляйте ответы, состоящие только из кода. Пожалуйста, объясните, почему ваше решение является ответом.
Ли Тейлор
1

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

string test = null;
foreach (ComboBoxItem item in e.AddedItems)
{
   test = item.Content.ToString();
   break;
}
Джош
источник
0

Мне нужно было решить это в 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
zzMzz
источник
0

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

прости миссджексон
источник
0

Если вам действительно нужно SelectionChangedмероприятие, лучший ответ - ответ SwDevMan81. Однако, если вы начинаете с WPF, вы можете узнать, как делать что-то способом WPF, который отличается от старых дней Windows Forms, которые использовали такие события, как SelectionChangedWPF и шаблон 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"); }
    }

}
Лазаро
источник
0
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 kProjectwhere kProject - это класс, который хранит данные, у меня сработало, так как по умолчанию использовался RemovedItems [0] до того, как я сделал это явное различие. Спасибо SwDevMan81 за первоначальную информацию, которая ответила за меня на этот вопрос.

киджот
источник
0

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

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

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

Сэм Томаши
источник
0

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

user7347514
источник
-2

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

int myInt= ((data)(((object[])(e.AddedItems))[0])).kid;
сулексит
источник
2
Вы можете объяснить, как это отвечает на вопрос?
Натан Тагги,
-3

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

user5028920
источник