Ручное связывание данных с использованием WriteValue - PullRequest
7 голосов
/ 28 октября 2009

Если я отключаю автоматическое обновление источника данных привязки, установив DataSourceUpdateMode = Never, а затем использую кнопку для обновления всего лота (используя binding.WriteValue), возникает проблема - а именно, источником данных является только первый связанный элемент управления обновлено. Все остальные элементы управления возвращаются к исходным значениям.

Это связано с тем, что при изменении текущего объекта (как это происходит после описанного выше WriteValue), если ControlUpdateMode = OnPropertyChange, все остальные элементы управления повторно считывают значение из источника данных.

Каков стандартный способ избежать этой проблемы?

Один из способов - извлечь класс из BindingSource и добавить метод WriteAllValues. Этот метод делает следующее:

(1) Для каждой привязки сохраните ControlUpdateMode

(2) Для каждой привязки установите ControlUpdateMode = Никогда

(3) Для каждой привязки вызовите метод WriteValue

(4) Для каждой привязки сбросьте ControlUpdateMode в сохраненное значение

(5) Для каждой привязки, если 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, все события CurrentItemChanged будут вызываться для всех других элементов управления в том же BindingSource. Однако, поскольку ControlDoingExplicitUpdate установлено, они не будут повторно считывать значение из источника данных, если только они не являются элементом управления, выполнившим обновление. ControlDoingExplicitUpdate устанавливается в Nothing после завершения всех этих событий, так что нормальная служба возобновляется.

Я надеюсь, что вы можете следить за этим, и - снова - я спрашиваю, вы можете увидеть какие-либо проблемы с этим?

Ответы [ 2 ]

4 голосов
/ 26 августа 2011

У меня были похожие требования к форме. В моем случае я хотел, чтобы привязка данных для всех элементов управления формы происходила только при нажатии кнопки «Сохранить» формы.

Лучшим решением, которое я нашел, было установить для DataSourceUpdateMode каждой привязки значение OnValidation, а затем для свойства AutoValidate содержащей формы установить значение Disable. Это предотвращает связывание при изменении фокуса между элементами управления в форме. Затем в событии Click для кнопки «Сохранить» я вручную проверяю ввод моей формы и, если все в порядке, вызываю метод ValidateChildren формы, чтобы вызвать привязку.

Этот метод также имеет то преимущество, что дает вам полный контроль над тем, как вы проверяете свои данные. WinForms не включают хороший способ сделать это по умолчанию.

2 голосов
/ 03 марта 2015

Я полагаю, что недавно прочитал на stackoverflow, где это было дано как ответ: Отключить двустороннюю привязку данных

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 ();
        }
    }
}
...