Friday, August 1, 2014

Changing a binding in code

If you have ever tried to modify a binding in code like this DetailsQty.Binding.StringFormat = "0" you have probably seen the following error...

Binding cannot be changed after it has been used

Previously I discovered this problem with styles and the solution there is to create a new style based on the original one, modify it, then assign it back to the UIElement replacing the original one. Not elegant, but it works.

Dim Style As System.Windows.Style Style = New System.Windows.Style(GetType(TextBox), DetailsQty.EditingElementStyle) Style.Setters.Add(New Setter(TextBox.TagProperty, "8N")) DetailsQty.EditingElementStyle = Style
Unfortunately there is no Binding constructor that takes an existing binding object so we are going to have to work harder. The Binding class does have a Clone method but it is private and we would have to use reflection to call it. I don't want to do that. I wrote a Clone method for bindings. It's very simple. The only tricky bit is that Source, RelativeSource and ElementName are mutually exclusive so I only copy them if they have values.
Public Shared Function CloneBinding(OldBinding As Binding) As Binding Dim NewBinding = New Binding If OldBinding.Source IsNot Nothing Then NewBinding.Source = OldBinding.Source NewBinding.AsyncState = OldBinding.AsyncState NewBinding.BindingGroupName = OldBinding.BindingGroupName NewBinding.BindsDirectlyToSource = OldBinding.BindsDirectlyToSource NewBinding.Converter = OldBinding.Converter NewBinding.ConverterCulture = OldBinding.ConverterCulture NewBinding.ConverterParameter = OldBinding.ConverterParameter If OldBinding.ElementName IsNot Nothing Then NewBinding.ElementName = OldBinding.ElementName NewBinding.FallbackValue = OldBinding.FallbackValue NewBinding.IsAsync = OldBinding.IsAsync NewBinding.Mode = OldBinding.Mode NewBinding.NotifyOnSourceUpdated = OldBinding.NotifyOnSourceUpdated NewBinding.NotifyOnTargetUpdated = OldBinding.NotifyOnTargetUpdated NewBinding.NotifyOnValidationError = OldBinding.NotifyOnValidationError NewBinding.Path = OldBinding.Path If OldBinding.RelativeSource IsNot Nothing Then NewBinding.RelativeSource = OldBinding.RelativeSource NewBinding.StringFormat = OldBinding.StringFormat NewBinding.TargetNullValue = OldBinding.TargetNullValue NewBinding.UpdateSourceExceptionFilter = OldBinding.UpdateSourceExceptionFilter NewBinding.UpdateSourceTrigger = OldBinding.UpdateSourceTrigger NewBinding.ValidatesOnDataErrors = OldBinding.ValidatesOnDataErrors NewBinding.ValidatesOnExceptions = OldBinding.ValidatesOnExceptions NewBinding.XPath = OldBinding.XPath Return NewBinding End Function
Now changing an active binding in code is much easier. To change the FormatString on a DataGridTextColumn called DetailsQty we would use this code...
Dim Binding As Binding Binding = CloneBinding(DetailsQty.Binding) Binding.StringFormat = "0" DetailsQty.Binding = Binding

No comments:

Post a Comment