问题描述
我们目前正在将项目从.NET的3.5版转换为4.5版。
We are currently in the process of converting a project from version 3.5 to version 4.5 of .NET.
我们设置了一个文本框IsEnabled,该文本框使用带有多重绑定转换器的多重绑定来标记。每个绑定都有自己的转换器。
We set a text box IsEnabled flagged using a multi binding with a multi binding converter. Each of the bindings has their own converter.
在.NET 3.5中一切正常,但在.NET 4.5中,传递给子转换器的目标类型是对象类型,而不是布尔类型。
All worked well in .NET 3.5 but in .NET 4.5 the target type that is passed to the child converter is of type object instead of bool.
这是一个已知问题吗? MS已将多重绑定重构为不将目标类型传递给子转换器。
Is this a known issue? has MS refactored the multi binding to not pass the target type to child converters.
我创建了一个简化的项目来演示该问题。我在VS2008中创建了该项目,然后将其转换为VS2012和.NET 4.5。
I created a simplified project that demonstrates the issue. I created the project in VS2008 and then converted it to VS2012 and .NET 4.5.
Window XAML:
Window 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?
Is there a reason you are testing that the targetType is bool?
我很惊讶它在3.5中工作,因为NonConverter正在转换从bool到对象(因为MultiBinding在进入时就接受对象数组)。
I'm surprised it worked in 3.5, as the NonConverter is converting from bool to object (as the MultiBinding takes an array of object as it's inout).
我使用反射器进行了一些挖掘,并且底层逻辑确实发生了变化。
I did some digging using reflector, and the underlying logic did change.
这是来自内部void TransferValue(object newValue,bool isASubPropertyChange)
BindingExpression
在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
的定义:
In 4.5, all calls to propertyType
are replaced by the below definition of 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的对象。
I'm not sure what TargetProperty is set to in this case, but you can see why it's now being set to object for MultiBindings.
而且,仅供参考,此更改似乎发生在.NET 4.0中。
And, FYI, it appears this change occurred in .NET 4.0.
这篇关于.NET 3.5和.NET 4.5之间的MultiBinding发生了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!