当UI元素数据更改时,WPF一次性数据绑定将分离

当UI元素数据更改时,WPF一次性数据绑定将分离,wpf,data-binding,Wpf,Data Binding,我正在尝试在NumericUpDown的value属性和cs对象的属性之间设置数据绑定。NumericUpDown位于模式对话框中,因此我只希望在用户按下OK按钮时更新数据绑定。这个NumericUpDown位于PropertyGrid中,它在非模态对话框中工作良好,因此我不想修改最初创建数据绑定的XAML。我也不想为了改变数据绑定而复制XAML。因此,我试图复制和修改模态对话框的已加载事件处理程序中的数据绑定 在这里,我复制并修改最初在XAML中创建的数据绑定 void OnLoad(

我正在尝试在NumericUpDown的value属性和cs对象的属性之间设置数据绑定。NumericUpDown位于模式对话框中,因此我只希望在用户按下OK按钮时更新数据绑定。这个NumericUpDown位于PropertyGrid中,它在非模态对话框中工作良好,因此我不想修改最初创建数据绑定的XAML。我也不想为了改变数据绑定而复制XAML。因此,我试图复制和修改模态对话框的已加载事件处理程序中的数据绑定

在这里,我复制并修改最初在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);
      }
   }
当用户通过NumericUpDown更改目标值时,BindingExpression的DataItem属性将设置为null。然后,当我在下面对该BindingExpression调用UpdateSource()时,会引发一个异常,该异常表示:“分离绑定时无法执行此操作。”


我做错了什么

我发现了问题。数据绑定需要具有双向(或单向到源)模式才能更新源。因此,在上面的代码中,唯一需要更改的是将单向更改为双向。

每个贴子下面都需要有一个按钮,标签为“向我们展示该死的代码”。如果有“当我更改UI元素值时…”,我会立即按下它?如果明确修改元素的值,绑定将分离。你的意思是你正在更新绑定值吗?是的,当我说“我更改UI元素”时,我的意思是我正在通过UI元素修改绑定的目标值。
    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,
        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;
    }
void ApplyClicked(object sender, RoutedEventArgs e)
{
  foreach(BindingExpression express in m_bindings)
    express.UpdateSource();
}