Reputation: 33
My issue is that when I use a converter on one of the multibinding's binding. It doesn't send the right thing to the converter. As per the DOC(https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-binding/multibinding?view=net-maui-7.0) in the Consume a IMultiValueConverter it should work, so I don't know what I'm doing wrong...
My multibinding class is the following:
public class BooleanAndConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || !targetType.IsAssignableFrom(typeof(bool)))
{
return false;
}
foreach (var value in values)
{
if (!(value is bool b))
{
return false;
}
else if (!b)
{
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
I have a Boolean inverter class which is the following:
public class InverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Then in my XAML I'm using it like so:
<Button Text="Passer à la ronde suivante" Command="{Binding NextRoundCommand}">
<Button.IsVisible>
<MultiBinding Converter="{StaticResource BooleanAndConverter}">
<Binding Path="isGameStarted"/>
<Binding Path="isPlayersPlaying" Converter="{StaticResource InvertedBoolConverter}"/>
</MultiBinding>
</Button.IsVisible>
</Button>
When the inverter converter gets called in the multibinding, instead of receiving a TagetType of bool, it receive a "System.object", so it throws the InvalidOperationException. Why when using normal bindings it receive a targettype of bool and in multibinding it doesn't?
Thanks
Upvotes: 1
Views: 4270
Reputation: 26179
This is one of the cases where DataTrigger
can be used to combine two conditions:
DataTrigger
, Binding
, Value
can be configured to setup the falsey caseSetter
can be configured to setup the secondary Binding<Button Text="Passer à la ronde suivante" Command="{Binding NextRoundCommand}" IsVisible="False">
<Button.Triggers>
<DataTrigger TargetType="Button" Binding="{Binding isPlayerPlaying}" Value="False">
<Setter Property="IsVisible" Value="{Binding isGameStarted}" />
</DataTrigger>
</Button.Triggers>
</Button>
Another variation of the DataTrigger
is you can use it with a MultiBinding
to merge your Bindings
into a single string and then trigger on that string, e.g.
<Button Text="Passer à la ronde suivante" Command="{Binding NextRoundCommand}" IsVisible="False">
<Button.Triggers>
<DataTrigger
Binding="{MultiBinding {Binding isPlayerPlaying},
{Binding isGameStarted},
StringFormat='Magic-{0}-{1}'}"
TargetType="Button"
Value="Magic-False-True">
<Setter Property="IsVisible" Value="True" />
</DataTrigger>
</Button.Triggers>
</Button>
Upvotes: 1
Reputation: 872
You can use MathConverter
to do this without a custom IValueConverter
. MathConverter doesn't support two-way bindings, but if all you need is a one-way binding, you don't need any custom C# converters for this.
https://www.nuget.org/packages/MathConverter.Maui
Here are a few ways you can do this binding:
&&
operator (but that makes for some ugly XAML):<Button IsVisible="{math:Convert 'x && !y',
x={Binding isGameStarted}, y={Binding isPlayersPlaying}}" ... />
And
function<Button IsVisible="{math:Convert 'And(x, !y)',
x={Binding isGameStarted}, y={Binding isPlayersPlaying}}" ... />
MathConverter
on a traditional MultiBinding
.<!-- Define a MathConverter resource: -->
<Application.Resources>
<math:MathConverter x:Key="Math" />
</Application.Resources>
<!-- Use the MathConverter in a MultiBinding: -->
<Button.IsVisible>
<MultiBinding ConverterParameter='And(x, !y)' Converter="{StaticResource Math}">
<Binding Path="isGameStarted"/>
<Binding Path="isPlayersPlaying"/>
</MultiBinding>
</Button.IsVisible>
Upvotes: 1
Reputation: 13889
I couldn't see other code, but I tested the sample code DataBindingDemos, it works on my side.
But I found that you didn't implement function ConvertBack
for both of your (BooleanAndConverter
and InverseBooleanConverter
).
And if I replace the code of ConvertBack
to yous as follows, the app will throw exception.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
You can refer to the following code:
public class InverterConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? b = value as bool?;
if (b == null)
{
return false;
}
return !b.Value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
public class AllTrueMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || !targetType.IsAssignableFrom(typeof(bool)))
{
return false;
// Alternatively, return BindableProperty.UnsetValue to use the binding FallbackValue
}
foreach (var value in values)
{
if (!(value is bool b))
{
return false;
// Alternatively, return BindableProperty.UnsetValue to use the binding FallbackValue
}
else if (!b)
{
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
if (!(value is bool b) || targetTypes.Any(t => !t.IsAssignableFrom(typeof(bool))))
{
// Return null to indicate conversion back is not possible
return null;
}
if (b)
{
return targetTypes.Select(t => (object)true).ToArray();
}
else
{
// Can't convert back from false because of ambiguity
return null;
}
}
}
For more information, you can check: AllTrueMultiConverter.cs and InverterConverter.cs
Upvotes: 0