Reputation: 3135
I have a situation where I am using a multi-value converter. The values passed to it are themselves being converted.
<MenuItem>
<MenuItem.IsEnabled>
<MultiBinding Converter="{StaticResource BooleanAndConverter}">
<Binding Path="Prop1" Converter="{StaticResource Converter1}" />
<Binding Path="Prop2" Converter="{StaticResource Converter1}" />
</MultiBinding>
</MenuItem.IsEnabled>
</MenuItem
Converter1 contains some error checking to confirm that it is called with a valid target type. It throws an exception if not, as this is a developer error and the situation should be fixed.
The problem is that when Converter1 is used in this context the target type is System.Object. Now the BooleanAndConverter requires values of a certain type (Boolean), so how can I get that type passed as the target type of Converter1?
As requested here is the BooleanAndConverter code:
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object value in values)
{
if (value.GetType() != typeof(bool))
{
throw new ArgumentException("BooleanAndConverter can only be used to convert booleans."); // developer error
}
}
if (targetType != typeof(bool))
{
throw new ArgumentException("BooleanAndConverter can only convert to a boolean."); // developer error
}
foreach (object value in values)
{
if ((bool)value == false)
{
return false;
}
}
return true;
}
Let me restate the question as there seems to be some confusion. Converter1 knows what type it can convert from and to. It throws an exception when called with the wrong types. In this situation the targetType is not getting specified and an exception is being thrown. How do I get the targetType specified correctly? When not used in a multi-binding situation is does always get specified correctly based on what is being converted.
Upvotes: 1
Views: 10723
Reputation: 3439
Value converter implementations should do an appropriate default conversion if object
is the target type. You will get binding debug errors output if a bound converter is returning the wrong type and you can fix the problem accordingly. You also shouldn't be throwing errors in converters, you should output an informative message via Debug.WriteLine
and return DependencyProperty.UnsetValue
.
Because of situations like this it is generally not recommended to return more than one type of result based on the targetType
parameter and it should be obvious what type of value the converter will return. You can either ignore targetType
, or check that it is either the correct type or object
. In practice it doesn't really make a difference.
Upvotes: 1
Reputation: 86
An possible alternative to some comments using a CommandParameter could be a MarkupExtension. Then you could write your MultiBinding like:
<MultiBinding Converter="{StaticResource BooleanAndConverter}">
<Binding Path="Prop1" Converter="{conv:DebugTypeCheck, CheckType={x:Type sys:Boolean}" />
<Binding Path="Prop2" Converter="{StaticResource DebugTypeCheckConverter}" CommandParameters="{x:Type sys:Boolean}" />
</MultiBinding>
On StackOverflow you can find several posts about Markupextension-Converters like here.
Sample implementation for both ways:
public class DebugTypeCheck : MarkupExtension, IValueConverter
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public Type CheckType { get; set; }
[Conditional("DEBUG")]
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.GetType() != CheckType)
{
throw new ArgumentException(); // developer error
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class DebugTypeCheckConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.GetType() != (Type)parameter)
{
throw new ArgumentException(); // developer error
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Upvotes: 1
Reputation: 9141
Seems to me that the code in the converter should be casting the object to whatever type it expects.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var desired = value as desiredType;
if (desired != null)
//do stuff with 'desired' as a parameter
else
// error
}
I do not know of a way get WPF to pass it in as a specific type. If you want the converter to behave differently for different types you could include the type as a converter parameter, or you could use a multivalueconverter to cast each parameter differently
Upvotes: 0