6

現在、プロジェクトを .NET のバージョン 3.5 からバージョン 4.5 に変換中です。

マルチ バインディング コンバーターを使用して、マルチ バインディングを使用して IsEnabled フラグが立てられたテキスト ボックスを設定します。各バインディングには、独自のコンバーターがあります。

すべてが .NET 3.5 でうまく機能しましたが、.NET 4.5 では、子コンバーターに渡されるターゲット型は bool ではなく object 型です。

これは既知の問題ですか? MS はマルチ バインディングをリファクタリングして、ターゲット タイプを子コンバーターに渡さないようにしました。

問題を示す単純なプロジェクトを作成しました。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;
        }
    }

}
4

1 に答える 1

1

targetType が bool であることをテストしている理由はありますか?

NonConverter がブール値からオブジェクトに変換されているため (MultiBinding は inout としてオブジェクトの配列を受け取るため)、3.5 で機能したことに驚いています。


リフレクターを使用して掘り下げたところ、基になるロジックが変更されました。

internal 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

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 が何に設定されているかはわかりませんが、MultiBinding のオブジェクトに設定されている理由がわかります。

参考までに、この変更は .NET 4.0 で発生したようです。

于 2013-10-01T20:25:52.880 に答える