Подія ComboBox- SelectionChanged має старе, а не нове значення


90

C #, .NET 4.0, VS2010.

Нове у WPF. У мене є головне вікно ComboBox. Я підключив подію 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

Відповіді:


109

Відповідно до 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


11
цікаво ... воно має нове значення. А RemovedItems має старий. Ця назва події є дещо неправильним, принаймні IMHO. Коли я бачу SelectionChanged, я очікую, що стан об'єкта змінився. Я бачу, як це дає нам трохи більше інформації.
Метт,

1
Так, я думаю, це тому, що зміни відбулися, але не були скоєні? Це лише здогадки. Можливо, ви зможете отримати текст вибраного елемента, див. Мою редакцію.
SwDevMan81

3
ComboBox.SelectedItemне має властивості під назвою Text, але ви можете це зробити ComboBox.SelectedItem as string(хоча це може спрацювати, лише якщо ви використовуєте stringдля Items- не перевіряли нічого іншого)
musefan

Просто рядок text = (string) e.AddedItems [0];
Ігор Семін

Не ускладнюйте справи без причини. Використовуючи властивість SelectedValue, ви можете легко отримати вибране значення ComboBox наступним чином: YourComboBoxName.SelectedValue.ToString (). За сценою властивість SelectedValue визначається як: SelectedValue {get; set;} це означає, що ви можете використовувати його для отримання або встановлення значення ComboBox. Використання SelectedItem не є ефективним способом отримати значення ComboBox, оскільки воно вимагає великих розгалужень.
Сем Томаші

59

Правильним значенням для перевірки тут є властивість SelectedItem .

ComboBox - це складене управління, яке складається з двох його частин:

  1. Текстова частина : значення в цій частині відповідає властивості Text ComboBox.
  2. Частина селектора (тобто "випадаюча" частина): вибраний елемент у цій частині відповідає властивості SelectedItem .

Розширені деталі ComboBox

Зображення вище було зроблено відразу після розширення ComboBox (тобто перед вибором нового значення). На даний момент і Text, і SelectedItem є "Інформацією", припускаючи, що елементи ComboBox були рядками. Якби елементи ComboBox були замість усіх значень Enum з назвою "LogLevel", SelectedItem наразі буде LogLevel.Info .

При натисканні на елемент у спадному меню значення SelectedItem змінюється і піднімається подія SelectionChanged . Текст властивість ще не оновлюється, хоча, як частина тексту не оновлюється до тих пір , після того , як SelectionChanged обробник завершення. Це можна спостерігати, помістивши точку зупинки в обробник і подивившись на елемент керування:

ComboBox у точці зупинку в обробнику SelectionChanged

Оскільки текстова частина на даний момент не оновлена, властивість Text повертає раніше вибране значення.


2
Повне розширення, і це допомогло зрозуміти, що моє Прив’язування було до властивості Text замість правильного SelectedItem.
cmousset

1
@DaveKidder Чудовий приклад! +1
Райан Вільсон

46

Використовуйте подію 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.
Джесс

3

Наступна подія запускається за будь-яку зміну тексту в 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();
}

5
Будь ласка, не вказуйте відповіді лише на код. Дайте пояснення, чому саме ваше рішення є відповіддю.
Lee Taylor

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

0

Дивно, що 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>?. Потім я перевіряю, чи selectedItemмає значення, відмінне від null. Цей підхід повинен застосовуватися до будь-якого типу обраного вами предмета насправді.


0

Якщо вам дійсно потрібна 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"); }
    }

}

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 kProjectде kProject - це клас, який зберігає дані, що працювали для мене, оскільки вони були за замовчуванням для RemovedItems [0], перш ніж я зробив це явне розрізнення. Дякую SwDevMan81 за початкову інформацію, яка відповіла мені на це запитання.


0

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

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

Використання SelectedItem не є ефективним способом отримати значення ComboBox, оскільки воно вимагає великих розгалужень.


0

Ви можете перевірити властивість SelectedIndex або SelectedValue або SelectedItem у події SelectionChanged елемента керування Combobox.



-3

Я вирішив це за допомогою події DropDownClosed, оскільки це трохи спрацьовує після зміни значення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.