2009-10-28 12 views
7

Si desactivo la actualización automática de una fuente de datos de enlace configurando DataSourceUpdateMode = Never y luego uso un botón para actualizar todo el lote (usando binding.WriteValue), ocurre un problema - A saber, solo el primero la fuente de datos del control enlazado se actualiza. Todos los demás controles se restablecen a los valores originales.Enlace de datos manual usando WriteValue

Esto se debe a que cuando el objeto actual cambia (como ocurre después del WriteValue anterior), si ControlUpdateMode = OnPropertyChange, todos los demás controles vuelven a leer el valor de la fuente de datos.

¿Cuál es la forma estándar de evitar este problema?

Una forma es derivar una clase de BindingSource y agregar un método WriteAllValues. Este método hace lo siguiente:

(1) Para cada Binding, guardar el ControlUpdateMode

(2) Para cada vinculante, establece ControlUpdateMode = Nunca

(3) Para cada Encuadernación, llame a la WriteValue método

(4) para cada Binding, reset ControlUpdateMode al valor guardado

(5) para cada Encuadernación, si ControlUpdateMode = onPropertyChange, llame al método ReadValue.

¿Puedes ver algún problema al hacer esto?

Si está trabajando con sus propias clases, ¿la implementación de IEditableObject resolvería el problema?

En otro control en el que estoy trabajando, implemento mi propio enlace. La forma en que soluciono el problema es con el siguiente código. (He puesto en el mínimo, espero que pueda seguir!):

Private Shared ControlDoingExplicitUpdate As MyCustomControl = Nothing 

Private Sub UpdateDataSourceFromControl(ByVal item As Object, ByVal propertyName As String, ByVal value As Object) 
    Dim p As PropertyDescriptor = Me.props(propertyName) 
    Try 
    ControlDoingExplicitUpdate = Me 
    p.SetValue(item, value) 
    Catch ex As Exception 
    Throw 
    Finally 
    ControlDoingExplicitUpdate = Nothing 
    End Try 
End Sub 

Private Sub DataBindingSource_CurrentItemChanged(ByVal sender As Object, ByVal e As System.EventArgs) 
    If (ControlDoingExplicitUpdate IsNot Nothing) AndAlso (ControlDoingExplicitUpdate IsNot Me) Then Exit Sub 
    Me.UpdateControlFromDataSource() 'Uses ReadValue 
End Sub 

lo tanto, cuando se llama UpdateDataSourceFromControl, todos los eventos CurrentItemChanged serán llamados para todos los otros controles en el mismo BindingSource. Sin embargo, dado que ControlDoingExplicitUpdate está configurado, no volverán a leer en el valor de la fuente de datos a menos que resulte ser el control que realizó la actualización. ControlDoingExplicitUpdate se establece en Nothing después de que se hayan completado todos estos eventos, por lo que se reanuda el servicio normal.

Espero que pueda seguir esto y, nuevamente, pregunto, ¿puede ver algún problema con esto?

Respuesta

4

He tenido requisitos similares para un formulario. En mi caso, solo quería que el enlace de datos para todos los controles del formulario se produjera cuando hice clic en el botón Guardar del formulario.

La mejor solución que encontré fue establecer el DataSourceUpdateMode de cada enlace en OnValidation y luego establecer la propiedad AutoValidate del formulario que contiene en Disable. Esto evita la vinculación a medida que cambia el foco entre los controles en el formulario. Luego, en el evento Click para mi botón Guardar, valido manualmente la entrada de mi formulario y, si está bien, llamo al método ValidateChildren del formulario para activar el enlace.

Este método también tiene la ventaja de darle control total sobre cómo valida su entrada. WinForms no incluye una buena forma de hacerlo por defecto.

2

Creo Hace poco leí en StackOverflow donde esto se dio como una respuesta: Disable Two Way Databinding

public static class DataBindingUtils 
{ 
    public static void SuspendTwoWayBinding(BindingManagerBase bindingManager) 
    { 
     if(bindingManager == null) 
     { 
      throw new ArgumentNullException ("bindingManager"); 
     } 

     foreach(Binding b in bindingManager.Bindings) 
     { 
      b.DataSourceUpdateMode = DataSourceUpdateMode.Never; 
     } 
    } 

    public static void UpdateDataBoundObject(BindingManagerBase bindingManager) 
    { 
     if(bindingManager == null) 
     { 
      throw new ArgumentNullException ("bindingManager"); 
     } 

     foreach(Binding b in bindingManager.Bindings) 
     { 
      b.WriteValue(); 
     } 
    } 
}