llenar and c# wpf combobox selectionchanged

c# - llenar - wpf combobox add items value and text



¿Cómo cancelar un evento ComboBox SelectionChanged? (6)

¿Existe un método fácil para solicitar al usuario que confirme un cambio en la selección del cuadro combinado y que no procese el cambio si el usuario seleccionó no?

Tenemos un cuadro combinado donde cambiar la selección causará la pérdida de datos. Básicamente, el usuario selecciona un tipo, luego puede ingresar atributos de ese tipo. Si cambian el tipo, eliminamos todos los atributos, ya que pueden dejar de aplicarse. El problema es que para debajo de la selección levanta de nuevo el evento SelectionChanged .

Aquí hay un fragmento de código:

if (e.RemovedItems.Count > 0) { result = MessageBox.Show("Do you wish to continue?", "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.No) { if (e.RemovedItems.Count > 0) ((ComboBox)sender).SelectedItem = e.RemovedItems[0]; else ((ComboBox)sender).SelectedItem = null; } }

Tengo dos soluciones, ninguna de las cuales me gusta.

  1. Después de que el usuario seleccione ''No'' , elimine el controlador de eventos SelectionChanged , cambie el elemento seleccionado y luego vuelva a registrar el controlador de eventos SelectionChanged . Esto significa que debe conservar una referencia del controlador de eventos en la clase para poder agregarla y eliminarla.

  2. Cree un ProcessSelectionChanged boolean como parte de la clase. Verifíquelo siempre al inicio del controlador de eventos. Establézcalo en falso antes de que volvamos a cambiar la selección y luego restablézcalo en verdadero después. Esto funcionará, pero no me gusta usar indicadores para anular básicamente un controlador de eventos.

¿Alguien tiene una solución alternativa o una mejora en las que menciono?


En WPF establecer dinámicamente el objeto con

if (sender.IsMouseCaptured) { //perform operation }


Encontré esta buena implementación.

private bool handleSelection=true; private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (handleSelection) { MessageBoxResult result = MessageBox.Show ("Continue change?", MessageBoxButton.YesNo); if (result == MessageBoxResult.No) { ComboBox combo = (ComboBox)sender; handleSelection = false; combo.SelectedItem = e.RemovedItems[0]; return; } } handleSelection = true; }

fuente: http://www.amazedsaint.com/2008/06/wpf-combo-box-cancelling-selection.html


La validación dentro del controlador de eventos SelectionChanged permite cancelar su lógica si la selección no es válida, pero no conozco una manera fácil de cancelar la selección de eventos o elementos.

Mi solución fue subdividir el cuadro combinado de WPF y agregar un controlador interno para el evento SelectionChanged . Cada vez que se activa el evento, mi controlador interno privado genera un evento SelectionChanging personalizado.

Si la propiedad Cancel se establece en el SelectionChangingEventArgs correspondiente, el evento no se activa y el SelectedIndex se revierte a su valor anterior. De lo contrario, se genera un nuevo SelectionChanged que sombrea el evento base. Esperemos que esto ayude!

EventArgs y el controlador delegado para el evento SelectionChanging:

public class SelectionChangingEventArgs : RoutedEventArgs { public bool Cancel { get; set; } } public delegate void SelectionChangingEventHandler(Object sender, SelectionChangingEventArgs e);

Cambiando la implementación de la clase ComboBox:

public class ChangingComboBox : ComboBox { private int _index; private int _lastIndex; private bool _suppress; public event SelectionChangingEventHandler SelectionChanging; public new event SelectionChangedEventHandler SelectionChanged; public ChangingComboBox() { _index = -1; _lastIndex = 0; _suppress = false; base.SelectionChanged += InternalSelectionChanged; } private void InternalSelectionChanged(Object s, SelectionChangedEventArgs e) { var args = new SelectionChangingEventArgs(); OnSelectionChanging(args); if(args.Cancel) { return; } OnSelectionChanged(e); } public new void OnSelectionChanged(SelectionChangedEventArgs e) { if (_suppress) return; // The selection has changed, so _index must be updated _index = SelectedIndex; if (SelectionChanged != null) { SelectionChanged(this, e); } } public void OnSelectionChanging(SelectionChangingEventArgs e) { if (_suppress) return; // Recall the last SelectedIndex before raising SelectionChanging _lastIndex = (_index >= 0) ? _index : SelectedIndex; if(SelectionChanging == null) return; // Invoke user event handler and revert to last // selected index if user cancels the change SelectionChanging(this, e); if (e.Cancel) { _suppress = true; SelectedIndex = _lastIndex; _suppress = false; } } }


No creo que usar el despachador para publicar (o retrasar) una actualización de la propiedad sea una buena solución, es más una solución que no es realmente necesaria. La siguiente solución es completamente mvvm y no requiere un despachador.

  • Primero vincule el artículo seleccionado con un modo de enlace explícito. // esto nos permite decidir si confirmar con el método UpdateSource () los cambios en la máquina virtual o Revertir con el método UpdateTarget () en la interfaz de usuario.
  • A continuación, agregue un método a la VM que confirme si el cambio está permitido (este método puede contener un servicio que solicita la confirmación del usuario y devuelve un bool).

En el código de la vista detrás del enganche al evento SelectionChanged y actualice la Fuente (es decir, la VM) o el Objetivo (es decir, la V) de acuerdo con si el método VM.ConfirmChange (...) devolvió el valor de la siguiente manera:

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if(e.AddedItems.Count != 0) { var selectedItem = e.AddedItems[0]; if (e.AddedItems[0] != _ViewModel.SelectedFormatType) { var comboBoxSelectedItemBinder = _TypesComboBox.GetBindingExpression(Selector.SelectedItemProperty); //_TypesComboBox is the name of the ComboBox control if (_ViewModel.ConfirmChange(selectedItem)) { // Update the VM.SelectedItem property if the user confirms the change. comboBoxSelectedItemBinder.UpdateSource(); } else { //otherwise update the view in accordance to the VM.SelectedItem property comboBoxSelectedItemBinder.UpdateTarget(); } } } }


Recuerdo haber necesitado hacer esto hace un tiempo. Me tomó cerca de una semana de investigación e intentos antes de encontrar una buena solución. Lo publiqué aquí:

WPF: ¿Cancelar una selección de usuario en un cuadro de datos ListBox?

Para su información, es una solución basada en MV-VM (si no está utilizando el patrón MV-VM, ¡debería hacerlo!)


Tal vez cree una clase derivada de ComboBox y anule el OnSelectedItemChanged (o OnSelectionChangeCommitted ).