We are currently in the process of converting a project from version 3.5 to version 4.5 of .NET.
We set a text box IsEnabled flagged using a multi binding with a multi binding converter. Each of the bindings has their own converter.
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.
Is this a known issue? has MS refactored the multi binding to not pass the target type to child converters.
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 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;
}
}
}