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


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

Примечание., Я получаю такое же поведение, если я использую объект, передаваемый в событии args, например E. OriginalSource.

14 74

14 ответов:

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

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

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

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

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

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

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

Expanded ComboBox Parts

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

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

ComboBox at breakpoint in SelectionChanged handler

с Текстовая Часть не был обновлен на данный момент,текст свойство возвращает ранее выбранное значение.

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

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

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

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

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

<ComboBox IsEditable="True" TextBoxBase.TextChanged="cbx_TextChanged" />
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    string newItem = ((DataRowView) e.AddedItems[0]).Row.ItemArray[0].ToString();
}

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

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

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

странно, что для selecteditem содержит свежие данные, в то время как SelectedValue не. Звучит как ошибка для меня. Если ваши элементы в Combobox являются объектами, отличными от ComboBoxItems, вам понадобится что-то вроде этого: (my ComboBox содержит KeyValuePair s)

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 может быть null, в то время как Visual Studio продолжает говорить мне, что a KeyValuePair не может быть null. Вот почему я бросил SelectedItem к нам!--6-->. Тогда я проверю, если selectedItem имеет значение null. Этот подход должен быть применим к любому типу выбранного элемента на самом деле.

Если вам действительно нужен 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"); }
    }

}
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 за первоначальную информацию, которая ответила на этот вопрос для меня.

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

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

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