Pregunta

¿Hay alguna manera de saber cómo el evento ComboBox_SelectionChanged fue levantado en WPF.

Es decir, fue el evento levantado como el resultado de una interacción del usuario, o como el resultado de un cambio en la propiedad que está obligado a?

¿Fue útil?

Solución

En el caso ComboBox.SelectionChanged, el remitente es siempre el cuadro combinado y no hay nada en SelectionChangedEventArgs que le ayudará.

Dos soluciones a este ocurren a mí. Se puede usar un convertidor en la unión, o se puede comprobar el seguimiento de la pila para ver si System.Windows.Controls.Primitives.Selector.OnSelectedItemsCollectionChanged (objeto, NotifyCollectionChangedArgs) está en la pila. La comprobación de pila es muy feo, una mala práctica, y no va a funcionar en entornos de confianza parcial. Por lo que sólo describiré el otro.

Uso de un convertidor en la unión para detectar las fuentes de cambio

Esta solución es relativamente limpio, pero requiere un cambio en la unión. Y también se le notifica cuando las cosas no han cambiado.

Paso 1: Crear un convertidor que no hace la conversión, pero tiene un evento "convertido" y un evento "ConvertedBack":

public EventingConverter : IValueConverter
{
  public event EventHandler Converted;
  public event EventHandler ConvertedBack;

  public object Convert(object value, ...)
  {
    if(Converted!=null) Converted(this, EventArgs.Empty);
    return value;
  }
  public object ConvertBack(object value, ...)
  {
    if(ConvertedBack!=null) ConvertedBack(this, EventArgs.Empty);
    return value;
  }
}

Paso 2: Establecer su unión a utilizar una nueva instancia de este convertidor (no comparta casos convertidor utilizando un diccionario de recursos o una propiedad estática como se hace normalmente)

<ComboBox ...>
  <ComboBox.SelectedValue>
    <Binding Path="..." ...>
      <Binding.Converter>
        <local:EventingConverter
          Converted="ComboBoxSelectedValue_Converted"
          ConvertedBack="ComboBoxSelectedValue_ConvertedBack" />
      </Binding.Converter>
    </Binding>
  </ComboBox.SelectedValue>
</ComboBox>

Ahora sus métodos ComboBoxSelectedValue_Converted y ComboBoxSelectedValue_ConvertedBack serán llamados desde dentro el proceso de unión.

Advertencia:. Si se lanza una excepción en estos eventos se va a romper la unión

Si no puede modificar el XAML que hace la unión

Si no tiene ningún control sobre el XAML que crea la unión (por ejemplo, usted está utilizando propiedades adjuntas) todavía se puede entrar y añadir el convertidor después de los hechos. En este caso la clase de convertidor necesitará cadena al convertidor declarada anteriormente, vas a tener que clonar la unión e instalar uno nuevo (que son inmutables, una vez que se han utilizado), y también tendrá que lidiar con MultiBindings (si quieres apoyarlos).

Nota final

La necesidad de determinar si el cambio fue realizado por el usuario o la propiedad de hecho puede ser un síntoma de un mal diseño de interfaz de usuario, generalmente como resultado de los usuarios que no entienden realmente sus propias necesidades.

he tenido varios proyectos que he trabajado en donde el usuario final especifica que tal y tal cosa iba a suceder "cuando cambio el cuadro combinado". En casi todos los casos se ha comprobado que la aplicación se habría comportado de forma inesperada en ciertos casos de uso y encontramos una mejor manera de lograr el objetivo. En muchos casos lo que el usuario realmente quería era "cuando este valor difiere de la primera en la que la base de datos" o "cuando este valor ya no es por defecto" o "siempre que este valor es de 5".

Otros consejos

Respuesta corta: no. No debería haber una diferencia, en ambos casos, la selección ha cambiado, eso es todo lo que importa. Para determinar si se trataba de una interacción con el usuario, se le tiene que supervisar una combinación de otros eventos, como DropDownOpened / cerrado y KeyDown / arriba, y la Stylus * queridos.

También encontré con este tipo de problema y lo resolvió mediante una variable booleana bInternalChange.

Imagínese una interfaz convertir ° C a ° F y la parte posterior con dos ComboBoxes. La selección de un valor en los primeros cambios a la selección de la segunda, y la selección de un valor en el segundo actualiza la primera. Se crea un bucle infinito si no distinguir los cambios de interfaz de usuario de cambios internos.

bool bInternalChange = false;
private void ComboBoxF_SelectionChanged(...)
{
    if (!bInternalChange)
    {
        bInternalChange = true;
        ComboBoxC.SelectedValue = ConvertFtoC(...);
        bInternalChange = false;
    }
}
private void ComboBoxC_SelectionChanged(...)
{
    if (!bInternalChange)
    {
        bInternalChange = true;
        ComboBoxF.SelectedValue = ConvertCtoF(...);
        bInternalChange = false;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top