wpf - .NET 3.5 和 .NET 4.5 之间的多重绑定(bind)发生了什么?

标签 wpf converters multibinding imultivalueconverter

我们目前正在将项目从 .NET 版本 3.5 转换为版本 4.5。

我们使用多重绑定(bind)和多重绑定(bind)转换器设置了一个文本框 IsEnabled 标记。每个绑定(bind)都有自己的转换器。

所有这些在 .NET 3.5 中都运行良好,但在 .NET 4.5 中,传递给子转换器的目标类型是 object 类型而不是 bool 类型。

这是一个已知问题吗? MS 是否重构了多重绑定(bind),以不将目标类型传递给子转换器。

我创建了一个简化的项目来演示该问题。我在 VS2008 中创建了该项目,然后将其转换为 VS2012 和 .NET 4.5。

窗口 XAML:

<Window x:Class="TestMultiBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestMultiBinding"        
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:NotConverter x:Key="NotConverter"/>
        <local:MultiBoolConverter x:Key="MultiBoolConverter"/>
    </Window.Resources>
    <StackPanel>

        <TextBox>
            <TextBox.IsEnabled>
                <MultiBinding Converter="{StaticResource MultiBoolConverter}">
                    <Binding Path="ConditionOne" />
                    <Binding Path="ConditionTwo" Converter="{StaticResource NotConverter}"/>
                </MultiBinding>
            </TextBox.IsEnabled>
        </TextBox>


    </StackPanel>
</Window>

c#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Globalization;

namespace TestMultiBinding
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            DataContext = new ViewModel();
        }
    }

    public class ViewModel
    {
        public bool ConditionOne { get { return true; } }
        public bool ConditionTwo { get { return false; } }
    }

    /// <summary>
    /// Converts a boolean to its inverse (useful for radio buttons).
    /// </summary>
    [ValueConversion(typeof(bool), typeof(bool))]
    public class NotConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(bool) && targetType != typeof(bool?)) { throw new ArgumentException("Can only convert booleans.", "targetType"); }

            //return !(bool)value;
            return !true.Equals(value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Convert(value, targetType, parameter, culture);
        }
    }

    /// <summary>
    /// Converts multiple boolean values to one. Uses AND by default. Possible extension: Pass the desired operation as parameter
    /// </summary>
    [ValueConversion(typeof(bool), typeof(bool))]
    public class MultiBoolConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                // todo: support other operations like OR, XOR
                return values.Cast<bool>().Aggregate(true, (res, cur) => res && cur);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.TraceError("MultiBoolConverter({0}): {1}", parameter, ex.Message);
                return DependencyProperty.UnsetValue;
            }
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            System.Diagnostics.Trace.TraceError("MultiBoolConverter: does not support TwoWay or OneWayToSource bindings.");
            return null;
        }
    }

}

最佳答案

您测试 targetType 为 bool 是否有原因?

我很惊讶它在 3.5 中的工作原理,因为 NonConverter 正在从 bool 转换为对象(因为 MultiBinding 将对象数组作为输入输出)。

<小时/>

我使用反射器进行了一些挖掘,底层逻辑确实发生了变化。

这来自 BindingExpression内部 void TransferValue(object newValue, bool isASubPropertyChange) 方法

在 3.5 中:

internal void TransferValue(object newValue, bool isASubPropertyChange)
{
  DependencyObject targetElement = this.TargetElement;
  if (targetElement == null || this.Worker == null)
    return;
  Type propertyType = this.TargetProperty.PropertyType;

在 4.5 中,对 propertyType 的所有调用均替换为以下 effectiveTargetType 定义:

internal void TransferValue(object newValue, bool isASubPropertyChange)
{
  DependencyObject targetElement = this.TargetElement;
  if (targetElement == null || this.Worker == null)
    return;
  Type effectiveTargetType = this.GetEffectiveTargetType();
...
}

internal Type GetEffectiveTargetType()
{
  Type type = this.TargetProperty.PropertyType;
  for (BindingExpressionBase bindingExpressionBase = this.ParentBindingExpressionBase; bindingExpressionBase != null; bindingExpressionBase = bindingExpressionBase.ParentBindingExpressionBase)
  {
    if (bindingExpressionBase is MultiBindingExpression)
    {
      type = typeof (object);
      break;
    }
  }
  return type;
}

我不确定在这种情况下 TargetProperty 设置为什么,但您可以明白为什么它现在被设置为 MultiBindings 的对象。

而且,仅供引用,此更改似乎发生在 .NET 4.0 中。

关于wpf - .NET 3.5 和 .NET 4.5 之间的多重绑定(bind)发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19086116/

相关文章:

wpf - 您可以使用Powershell和WPF使用PowerBoots来实现Model-View-ViewModel吗?

c# - 带有进度条 WPF 的异步 Google 文件上传

spring-mvc - 将 Play 框架应用程序转换为 Spring MVC

c# - MVVM WPF Multibinding 不适用于命令参数

wpf - 为什么带有转换器的多重绑定(bind)在工具提示中不起作用?

wpf - 从 WIX 安装程序 : Fail on STAThread issue 启动使用 WPF 编写的 CustomAction UI

wpf - mvvm 中 crud 逻辑应该在哪里实现?

delphi - 当以任意位长度定位时,从字节数组中读取变量

c# - 在应用程序设置中保存字典并在启动时加载它