2011-03-02 8 views
5

Encontré un problema interesante que encontré primero en WinForms, y lo encontré de nuevo en Silverlight, y más que probable WPF también cuando se trata de enlace de datos.La vinculación de datos queda atrás notificación de evento - discusión

Tengo un control de pestañas con varias pestañas. A medida que los usuarios hacen clic en las pestañas, cada vez debe ser válido antes de permitir que el usuario cambie de la pestaña.

Por ejemplo, el usuario está en un cuadro de texto que se actualiza. La vinculación de cuadros de texto no se vacía hasta que el control pierde el foco. La pérdida de foco ocurre cuando el cursor se mueve desde el control, y el foco se le da a otro control.

En este caso, las pestañas del usuario en un control (usemos el cuadro de texto para este ejemplo) y actualiza el cuadro de texto. En este punto, el enlace de datos no ha descargado el control y, por lo tanto, la VM aún no ha visto el cambio. El usuario luego usa su mouse para hacer clic en la siguiente pestaña del control.

En este punto las cosas se ponen interesantes. Utilicé PreviewSelectionChanged (Telerik RadTabControl), ya que quiero verificar las cosas antes de que ocurra el salto a la siguiente pestaña, y también me da la posibilidad de cancelar el evento.

Sin embargo, cuando miro la VM, en este caso, todavía no tiene los datos actualizados. Veo que la VM está limpia, y sigo adelante y permitiré el salto a la siguiente pestaña.

Sin embargo, tan pronto como finaliza este evento, las conexiones de datos se vacían y la VM se actualiza. ¿ahora que? ¡Los eventos no están sincronizados! Cuando se usó el mouse para hacer clic en la siguiente pestaña, el cuadro de texto debería haber perdido el foco, se ha enjuagado sus enlaces, ¡antes de hacer clic en la Vista previa de la pestaña! Es tarde para dar un salto atrás y decir uy, ¡no logramos atraparlo a tiempo!

Creo que encontré un trabajo interesante sobre este tema, pero no estoy 100% seguro de que funcione el 100% del tiempo. Cancelé el evento actual, pero luego utilizo Dispatcher y creo un delegado que apunta a otro método con la misma firma que el evento actual. El despachador añadirá este mensaje al suministro de mensajes, que para entonces será ahora (con suerte?) Estar detrás de los mensajes de la actualización VM ...

Code Snippet delaying the event

Mis dos preguntas son: 1) I Supongo que el control del cuadro de texto no se sonrojó cuando el mouse dejó el control, o el proceso que se activó fue demasiado lento y, por lo tanto, el mensaje de vista previa estaba en la bomba antes del enlace de datos. De cualquier forma, veo que es problema.

2) es la solución una buena solución?

Respuesta

0

Cambiar los enlaces de incluir UpdateSourceTrigger = "PropertyChanged".

Esto asegurará que sus fuentes de datos se actualizan en cada golpe de tecla, no sólo LostFocus.

+0

¡No es una opción en Silverlight! ¡Ojalá lo fuera, pero aún no se ha implementado! – codeputer

+1

Puede escribir su propio comportamiento adjunto para lograr la misma funcionalidad. –

+0

Estoy buscando entender cómo los eventos de perder enfoque desde el cuadro de texto, y el clic del control de tabulación son elevados/procesados ​​en un orden de línea de tiempo equivocado - el foco perdido ocurre primero, pero el evento click se levanta antes del punto perdido. – codeputer

1

Sólo una idea: ¿Por qué no hacer todo en caso PropertyChanged de la máquina virtual?

protected override void OnThisViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { 
      if(e.PropertyName == "WhateverProperty") { 
       //Do your magic here for whatever you want to set 
      } 
     } 

Tiene sus TabItems vinculados a una colección que controlará se está deshabilitando o no.

<sdk:TabControl> 
    <sdk:TabItem IsEnabled="{Binding SomeProperty, Converter={AmIDisabledOrWhatConverter}}" />  
</sdk:TabControl> 

De esta manera, todo se dispara cada vez que una propiedad se chaned en la máquina virtual. No más problemas de sincronización ya que todo está en la vm.

Sólo mis dos centavos.

+0

Probablemente funcionaría, pero en mi humilde opinión, una gran cantidad de tráfico estaría fluyendo a través de este fragmento de código. Trato de alejarme de sumergirme en este río de eventos, pero esa es una preferencia personal, y no he experimentado una degradación notable del rendimiento debido a esta suscripción. – codeputer

2

Ok, primero en responder a la pregunta 1:

hecho de que el ratón a la izquierda del área de texto, no quiere decir que el cuadro de texto pierde el foco. Solo pierde el enfoque una vez que algo más se enfoca. Por ejemplo, si sacaste el mouse del cuadro de texto y haces clic en otro control de tu página (puede ser cualquier cosa desde un visor de desplazamiento a otro cuadro de texto, etc.), tu cuadro de texto perderá el foco.

Ahora, en base a eso, los eventos no ocurren en el orden incorrecto. Lo que ocurre es; su evento de clic en la otra pestaña activa tanto el cuadro de texto para perder el foco (y el enlace de datos se llevará a cabo) como el siguiente cuadro, y basándonos en eso, básicamente se obtiene una condición de carrera donde se pasa a la siguiente pestaña antes de que tenga lugar el enlace de datos.

Acerca de la pregunta 2:

Lo que puede hacer es, establecer el UpdateSourceTrigger a explícita, que sin embargo se verá obligado a continuación, tienen algún tipo de evento text_changed y actualizar manualmente la unión.

Puede leer más sobre eso here. Puede que no sea la explicación más completa, pero es un buen lugar para comenzar.

Por otro lado, puede asociar algunos eventos al cuadro de texto y forzar al cuadro de texto a perder el foco en esos eventos (por ejemplo, salir del mouse).

+0

Con respecto a la pregunta 1: Eso es lo que entiendo que está ocurriendo, pero mantendría que la integridad de los eventos debe permanecer intacta. Tomando esto al nivel de bomba de mensaje del sistema operativo Windows: antes de que se presione el mensaje de evento de clic en la pila, debe enviar el mensaje de enfoque perdido y, por lo tanto, eliminar el enlace de datos. Sin embargo, trajo una idea interesante, ¿qué pasa si el clic debe registrarse primero, y porque eso ocurrió, se pierde el foco debido al clic. codeputer

+0

Estaba asumiendo que cuando se cambiaba el foco, el sistema operativo arrojaría el mensaje de enfoque perdido, antes de enfocar el siguiente control. Si mi suposición es correcta, la "ganancia" de enfoque siempre debe ocurrir antes de la "pérdida" de enfoque. Tendrá que intentarlo para ver si eso siempre ocurre, o de hecho es la condición de la carrera y el momento en que entran en juego. – codeputer

+0

Recibo un correo electrónico en el que tengo menos de 24 horas para liberar la recompensa. Aunque todavía no creo tener mi respuesta, me has dado algo de reflexión, y por eso te estoy otorgando la recompensa ... ¡Gracias por tu aporte! – codeputer

0
MyOwnTextBox() 
    { 
     this.TextChanged += (s, e) => UpdateText(); 
    } 

    private void UpdateText() 
    { 
     BindingExpression be = GetBindingExpression(TextProperty); 
     if (be != null && be.ParentBinding.Mode == BindingModes.TwoWay) 
     { 
      be.UpdateSource(); 
     } 
    } 

estoy usando esta clase se actualiza mi vinculante sobre la marcha, sin embargo no hay problema con los valores de cadena y nulos vacíos, si su propiedad es una cadena de destino anulable entonces esto va a actualizar cadena vacía en su propiedad de destino. Puede obtener una solución mediante el uso de algún tipo de convertidor de cadenas que utilizará null en lugar de cadena vacía en el caso de cadenas con nulos.

+0

Encontré un trabajo alternativo, estoy buscando entender por qué la infraestructura que rodea el enlace de datos está reaccionando de la manera en que lo hace. Gracias por la entrada sin embargo. – codeputer

+0

¿Cuál es su solución? –

+0

Ver el párrafo de mi pregunta que comienza con: "Creo que encontré un trabajo interesante sobre este tema, pero no estoy 100% seguro de que funcione el 100% del tiempo". – codeputer

1

Aquí hay un defecto de diseño, y está tratando de evitar el defecto en lugar de solucionarlo. No debería tener que averiguar cómo cancelar el evento Click en la pestaña. La pestaña no debería procesar eventos Click en primer lugar.

En general, si no es legal que el usuario haga clic en un control, el control no debe habilitarse. La pestaña debe estar deshabilitada hasta que el estado del modelo de vista sea válido.

Su modelo de vista debe exponer un comando para navegar a la siguiente pestaña, y la pestaña debe estar vinculada al comando. El método del comando CanExecute solo debe devolver verdadero cuando el estado del modelo de vista en la pestaña actual es válido.

Esto no soluciona el otro problema, que es que Silverlight no admite UpdateSourceTrigger="PropertyChanged" de fábrica. Pero ese es un problema resuelto (here es un ejemplo).

Tenga en cuenta que si implementa comandos para manejar esta navegación tipo asistente en su aplicación, puede cambiar la vista para usar algo que no sea un control de pestañas (por ejemplo, usar botones de navegación como un asistente real, o algo así como Telerik's PanelBar) sin tener que meterse con los controladores de eventos.

+0

Estoy de acuerdo con usted en que esto es un error de diseño, pero el cliente especificó que cuando se hace clic en una pestaña, la pestaña actual debe guardar automáticamente los cambios y luego proceder a navegar fuera de la pestaña actual. Este no es un buen diseño, y les dije, ¡pero ustedes que son dueños de las reglas de oro! – codeputer

+0

Si esa es la especificación, entonces ya la está violando cancelando la navegación si el usuario hace clic en la pestaña y el estado no es válido. A menos que el cliente también especifique ese comportamiento, en cuyo caso, ¿qué diablos le pasa a su cliente? –

+0

Una vez más, estoy de acuerdo contigo ... :) Si la pestaña no es válida, no tengo más remedio que dejar al cliente en la pestaña actual y hacer que solucione el problema, o simplemente abandonar silenciosamente los cambios y proceder, fue el mal menor. – codeputer

Cuestiones relacionadas