使用WriteValue进行手动数据绑定

时间:2009-10-28 16:43:31

标签: .net vb.net winforms data-binding bindingsource

如果我通过设置DataSourceUpdateMode = Never来关闭绑定数据源的自动更新然后使用按钮来更新整个批次(使用binding.WriteValue),则会出现问题 - 即,只有第一个绑定控件的数据源是更新。所有其他控件将重置为原始值。

这是因为当前对象发生更改时(如上面的WriteValue之后),如果ControlUpdateMode = OnPropertyChange,则所有其他控件都会重新读取数据源中的值。

避免此问题的标准方法是什么?

一种方法是从BindingSource派生一个类并添加一个WriteAllValues方法。 此方法执行以下操作:

(1)对于每个Binding,保存ControlUpdateMode

(2)对于每个Binding,设置ControlUpdateMode = Never

(3)对于每个Binding,调用WriteValue方法

(4)对于每个Binding,将ControlUpdateMode重置为保存的值

(5)对于每个Binding,如果ControlUpdateMode = OnPropertyChange,则调用ReadValue方法。

你能看到这样做有什么问题吗?

如果使用自己的类,实现IEditableObject会解决问题吗?

在我正在研究的另一个控件中,我实现了自己的绑定。我解决这个问题的方法是使用以下代码。 (我已经把它放在最低限度,我希望你能遵循它!):

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

因此,当调用UpdateDataSourceFromControl时,将为同一BindingSource中的所有其他控件调用所有CurrentItemChanged事件。但是,由于设置了ControlDoingExplicitUpdate,它们不会重新读取数据源中的值,除非它们恰好是执行更新的控件。 所有这些事件完成后,ControlDoingExplicitUpdate设置为Nothing,以便恢复正常服务。

我希望你能够遵循这一点,并且 - 再次 - 我问,你能看到任何问题吗?

3 个答案:

答案 0 :(得分:4)

我对表单有类似的要求。在我的情况下,我只想在单击表单的“保存”按钮时发生所有表单控件的数据绑定。

我找到的最佳解决方案是将每个绑定的DataSourceUpdateMode设置为OnValidation,然后将包含表单的AutoValidate属性设置为Disable。当您在窗体上的控件之间更改焦点时,这可以防止绑定。然后在我的保存按钮的Click事件中,我手动验证表单的输入,如果没有问题,则调用表单的ValidateChildren方法来触发绑定。

此方法还具有让您完全控制验证输入的方法。默认情况下,WinForms没有包含这样做的好方法。

答案 1 :(得分:2)

我相信我最近阅读了stackoverflow,其中给出了答案: 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 ();
        }
    }
}

答案 2 :(得分:0)

我建议不要与数据绑定作斗争。保持DataSourceUpdateMode为OnValidation。然后选择以下2个选项之一。

1,在更改控件中的值之前,请备份当前值。如果用户单击“取消”按钮,则将备份的值复制回数据源。然后运行userBindingSource.ResetCurrentItem()将控件中的值刷新为原始值。

2,如果用户单击“取消”按钮,则按ID从数据库中拉出一个新对象。并使用新对象替换绑定源中的当前对象。代码可能是这样的:

MyObject myObject = myObjectBindingSource.Current as MyObject;
MyObject originalObject = myObjectRepository.GetOneObjectFromDatabase(myObject.ID);
int currentIndex = myObjectBindingSource.Position;
myObjectBindingSource.Insert(currentIndex, originalObject);
myObjectBindingSource.Position = currentIndex;
myObjectBindingSource.RemoveAt(currentIndex+1);

我个人喜欢第二个选项,因为它避免了复制对象的工作,它可能需要复制每个属性,并且如果将来更改属性,会使维护工作变得更加困难。它还会提取最新数据,从而使记录非常新鲜。同样,第一个选项仅保存该记录的1个副本。如果导航到其他记录并进行其他更改,则副本将丢失。但是,第二个选项从数据库中提取数据,因此您始终可以导航回任何先前修改但尚未保存的记录,然后单击“取消”按钮以恢复原始值。