ComboBox- El evento SelectionChanged tiene un valor antiguo, no un valor nuevo


90

C #, .NET 4.0, VS2010.

Nuevo en WPF. Tengo un ComboBox en mi MainWindow. Enganché el evento SelectionChanged de dicho cuadro combinado. Sin embargo, si examino el valor del cuadro combinado en el controlador de eventos, tiene el valor anterior. Esto suena más a un evento "SelectionChanging" que a un evento SelectionChanged.

¿Cómo obtengo el nuevo valor de ComboBox después de que la selección haya sucedido realmente?

Actualmente:

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

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

Tenga en cuenta que obtengo el mismo comportamiento si uso el objeto que se pasa en el evento args, egeOriginalSource.


2
Me encontré con el mismo problema, ¡gracias! ¿Es eso realmente un error y debería haber sido nombrado SelectionChangingen primer lugar?
Ene

Respuestas:


109

De acuerdo con MSDN, e.AddedItems:

Obtiene una lista que contiene los elementos seleccionados.

Entonces podrías usar:

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

También puede usar SelectedItemsi usa stringvalores para el Itemsde sender:

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

o

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

Dado que ambos Contenty SelectedItemson objetos, un enfoque más seguro sería utilizar en .ToString()lugar deas string


11
interesante ... tiene el nuevo valor. Y RemovedItems tiene el antiguo. El nombre del evento es un poco inapropiado, al menos en mi humilde opinión. Cuando veo SelectionChanged, espero que el estado del objeto, bueno, haya cambiado. Sin embargo, puedo ver cómo esto nos da un poco más de información.
Matt

1
Sí, creo que es porque se ha producido el cambio, pero no se ha comprometido. Eso es solo una suposición. Es posible que pueda obtener el texto del elemento seleccionado, consulte mi edición.
SwDevMan81

3
ComboBox.SelectedItemno tiene una propiedad llamada Text, pero puede hacerlo ComboBox.SelectedItem as string(aunque esto solo puede funcionar si lo usa stringpara Items- no probó nada más)
musefan

Solo texto de cadena = (cadena) e.AddedItems [0];
Igor Semin

No compliques las cosas sin motivo. Usando la propiedad SelectedValue, puede obtener fácilmente un valor ComboBox seleccionado como este: YourComboBoxName.SelectedValue.ToString (). Detrás de la escena, la propiedad SelectedValue se define como: SelectedValue {get; set;} esto significa que puede usarlo para obtener o establecer el valor de un ComboBox. El uso de SelectedItem no es una forma eficaz de obtener un valor ComboBox, ya que requiere muchas ramificaciones.
Sam Tomashi

59

El valor correcto para verificar aquí es la propiedad SelectedItem .

Un ComboBox es un control compuesto con dos de sus partes:

  1. La parte de texto : el valor en esta parte corresponde a la propiedad Text del ComboBox.
  2. La parte del selector (es decir, la parte "desplegable"): el elemento seleccionado en esta parte corresponde a la propiedad SelectedItem .

Piezas de ComboBox ampliadas

La imagen de arriba se tomó inmediatamente después de que se expandió el ComboBox (es decir, antes de seleccionar un nuevo valor). En este punto, tanto Text como SelectedItem son "Info", asumiendo que los elementos ComboBox son cadenas. Si los elementos de ComboBox fueran todos los valores de un Enum llamado "LogLevel", SelectedItem actualmente sería LogLevel.Info .

Cuando se hace clic en un elemento del menú desplegable, se cambia el valor de SelectedItem y se genera el evento SelectionChanged . Sin embargo, la propiedad Text no se ha actualizado todavía, ya que la parte de texto no se actualiza hasta que finaliza el controlador SelectionChanged . Esto se puede observar poniendo un punto de interrupción en el controlador y mirando el control:

ComboBox en el punto de interrupción en el controlador SelectionChanged

Dado que la parte de texto no se ha actualizado en este momento, la propiedad de texto devuelve el valor seleccionado anteriormente.


2
Completó la expansión y ayudó a darme cuenta de que mi enlace estaba en la propiedad Text en lugar del SelectedItem correcto.
cmousset

1
@DaveKidder ¡Gran ejemplo! +1
Ryan Wilson

46

Utilice el evento DropDownClosed en lugar de selectionChanged si desea el valor actual del cuadro combinado.

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

Es así de simple.


10
@jvelez Creo que no se disparará al usar un teclado.
NoviceProgrammer

eso apesta. Programador novato que sabía ...!
oculto el

10

Esto funcionó para mí:

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

de alguna manera, solo SelectedItem se completa con el nuevo elemento, no SelectedValue.
mauris

7

Esto funcionó para mí:

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

Esto es muy importante. La respuesta aceptada no muestra explícitamente que sendercontiene la correcta SelectedItem.
Jess

3

El evento siguiente se activa para cualquier cambio del texto en el ComboBox (cuando se cambia el índice seleccionado y cuando se cambia el texto también editando).

<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
No proporcione respuestas de solo código. Por favor, explique por qué su solución es la respuesta.
Lee Taylor

1

La segunda opción no me funcionó porque el elemento .Text estaba fuera de alcance (C # 4.0 VS2008). Esta fue mi solución ...

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

0

Necesitaba resolver esto en VB.NET. Esto es lo que tengo que parece funcionar:

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

Es extraño que SelectedItem contenga los datos nuevos, mientras que SelectedValue no. Me suena como un error. Si sus elementos en el Combobox son objetos que no sean ComboBoxItems, necesitará algo como esto: (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.SelectedItempuede ser nulo, mientras que Visual Studio me sigue diciendo que KeyValuePairno puede ser nulo. Es por eso que lanzo el SelectedItemto a nullable KeyValuePair<string, string>?. Luego verifico si selectedItemtiene un valor diferente a null. Este enfoque debería ser aplicable a cualquier tipo de artículo seleccionado.


0

Si realmente necesita el SelectionChangedevento, la mejor respuesta es la de SwDevMan81. Sin embargo, si está comenzando con WPF, es posible que desee aprender cómo hacer las cosas de la manera WPF, que es diferente a los viejos días de Windows Forms que solían depender de eventos como SelectionChanged, con WPF y el patrón Model View ViewModel, debe utilizar enlaces. Aquí hay un ejemplo de código:

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

El uso de e.AddedItems[0] as kProjectwhere kProject es una clase que contiene los datos que funcionó para mí, ya que estaba por defecto en RemovedItems [0] antes de hacer esta distinción explícita. Gracias SwDevMan81 por la información inicial que me respondió esta pregunta.


0

No compliques las cosas sin motivo. Usando la propiedad SelectedValue, puede obtener fácilmente un valor ComboBox seleccionado como este: YourComboBoxName.SelectedValue.ToString ().

Detrás de la escena, la propiedad SelectedValue se define como: SelectedValue {get; set;} esto significa que puede usarlo para obtener o establecer el valor de un ComboBox.

El uso de SelectedItem no es una forma eficaz de obtener un valor ComboBox, ya que requiere muchas ramificaciones.


0

Puede comprobar la propiedad SelectedIndex o SelectedValue o SelectedItem en el evento SelectionChanged del control Combobox.


-2

Esto debería funcionar para ti ...

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

2
¿Puede explicar cómo esto responde a la pregunta?
Nathan Tuggy

-3

Resolví esto usando el evento DropDownClosed porque esto se activa ligeramente después de que se cambia el valor.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.