WPF OneTime databinding gets detached when UI Element data changes
I am trying to set up a data binding between the value property of a NumericUpDown and a property of a cs object. The NumericUpDown is in a Modal dialog box so I only want the databinding to be updated when the user presses the OK button. This NumericUpDown is in a PropertyGrid which works fine in a non Modal dialog box situation, so I don't want to modify the XAML which originally created the databinding. I also don't want to duplicate the XAML just to change the databinding. So, I am trying to copy and modify the databinding in the Loaded event handler for the Modal dialog box.
Here I copy and modify the databinding originally created in XAML.
void OnLoad(object sender, RoutedEventArgs e)
{
GetBindings(DialogPropPanel);
}
private void GetBindings(FrameworkElement root)
{
FieldInfo[] infos = root.GetType().GetFields(BindingFlags.Public | BindingFlags.FlattenHierarchy |
BindingFlags.Instance | BindingFlags.Static);
foreach(FieldInfo field in infos)
{
if(field.FieldType == typeof(DependencyProperty))
{
DependencyProperty dp = (DependencyProperty)field.GetValue(null);
BindingExpression ex = root.GetBindingExpression(dp);
if(ex != null)
{
PropertyElement elem = FindBoundElement(ex.DataItem, GroupContainer.PropertyGroups);
if(elem != null)
{
Binding bd = ex.ParentBinding;
if(bd.Mode == BindingMode.Default || bd.Mode == BindingMode.TwoWay)
{
// Copy the binding an change mode.
Binding newBinding = CreateOneTimeBinding(bd, ex.DataItem);
BindingOperations.ClearBinding(root, dp);
BindingOperations.SetBinding(root, dp, newBinding);
BindingExpression nuExp = root.GetBindingExpression(dp);
m_bindings.Add(nuExp);
}
}
}
}
}
int children = VisualTreeHelper.GetChildrenCount(root);
for(int i = 0; i < children; i++)
{
FrameworkElement child = VisualTreeHelper.GetChild(root, i) as FrameworkElement;
if(child != null)
GetBindings(child);
}
}
Here I change the mode to OneTime, and the UpdateSourceTrigger to Explicit.
public static Binding CreateOneTimeBinding(Binding binding, object source)
{
var result = new Binding
{
Source = source,
AsyncState = binding.AsyncState,
BindingGroupName = binding.BindingGroupName,
BindsDirectlyToSource = binding.BindsDirectlyToSource,
Converter = binding.Converter,
ConverterCulture = binding.ConverterCulture,
ConverterParameter = binding.ConverterCulture,
//ElementName = binding.ElementName,
FallbackValue = binding.FallbackValue,
IsAsync = binding.IsAsync,
开发者_JAVA百科 Mode = BindingMode.OneWay,
NotifyOnSourceUpdated = binding.NotifyOnSourceUpdated,
NotifyOnTargetUpdated = binding.NotifyOnTargetUpdated,
NotifyOnValidationError = binding.NotifyOnValidationError,
Path = binding.Path,
//RelativeSource = binding.RelativeSource,
StringFormat = binding.StringFormat,
TargetNullValue = binding.TargetNullValue,
UpdateSourceExceptionFilter = binding.UpdateSourceExceptionFilter,
UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
ValidatesOnDataErrors = binding.ValidatesOnDataErrors,
ValidatesOnExceptions = binding.ValidatesOnExceptions,
XPath = binding.XPath,
};
foreach(var validationRule in binding.ValidationRules)
result.ValidationRules.Add(validationRule);
return result;
}
When the user changes the target value through the NumericUpDown the DataItem property of the BindingExpression gets set to null. Then when I call UpdateSource() below on that BindingExpression an exception is thrown which says: "Cannot perform this operation when binding is detached."
void ApplyClicked(object sender, RoutedEventArgs e)
{
foreach(BindingExpression express in m_bindings)
express.UpdateSource();
}
What am I doing wrong?
I found the problem. The databinding needs to have a mode of TwoWay(or OneWayToSource) in order to update the source. So in the code above the only changed needed is to change OneWay to TwoWay.
精彩评论