我们目前正在将项目从 .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/