Search code examples
c#.netxamlmaui

How to set a xaml elements IsVisible property to true if a bound boolean property is false?


I'm wondering if or how I can set the IsVisible property of a xaml element to true if the boolean value of a bound property is false?

Depending on the value of a boolean property I want to conditionally render different elements in the view.

This is my code:

<ContentPage ...
  x:Name="page">

  <ListView BindingContext="{x:Reference page}" ItemSource="digitalInputs">
    <ListView.ItemTemplate>
      <DataTemplate x:DataType="services:DigitalInput">
        <ViewCell>
          <HorizontalStackLayout>
            <!-- This seems to be working. Render a green ball, if boolean value is true -->
            <Image Source="ballgreen" IsVisible="{Binding value}"/>
            <!-- Doesn't work. I want to render a red ball if the boolean value is false. -->
            <Image Source="ballred" IsVisible="{Binding !value}"/>
            <Label Text="{Binding valueText}" />
          </HorizontalStackLayout>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

I have thought about adding another boolean property to the DigitalInput class and set it's value to the opposite of value, but on the other hand I don't want to touch that class as it models 1:1 how I retrieve data from a web-service.

I have also thought about adding a converter, but I don't know how to do it in regards of BindingContext. I hope someone can help and shed some light on this issue for me.

Kind regards.


Solution

  • There is multiple ways to do this as you already mention yourself. The easiest being: add an inverted property to your model. Not the most elegant option.

    In XAML itself you can't have any logic, so the ! operator won't work. A converter is indeed the way to go.

    Implementing a InverseBoolConverter

    To implement a IValueConverter which is the thing you need in this case, create a class that implements this interface. When you do, there is a couple of methods that you need to implement. In this case those are pretty straight-forward as it just inverts the boolean value.

    However, since it's XAML and all based on strings, to make it really rock solid you might want to take into account some error handling. In this case, I'm going to assume the happy path. Find a sample implementation below:

    public class InverseBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return !((bool)value);
        }
        
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
    
            // Converting back rarely happens, a lot of the converters will throw an exception
            //throw new NotImplementedException();
        }
    }
    

    This code is taken from this SO question.

    To now use it in your XAML, do this: <Image Source="ballred" IsVisible="{Binding value, Converter={converters:InverseBoolConverter}}"/>

    And you'll need to add a xmlns entry to the root of your page like so: xmlns:converters="clr-namespace:YourProject.Namespace". Make sure that YourProject.Namespace matches the namespace of the InverseBoolConverter above.

    Using the .NET MAUI Community Toolkit

    The good news is, you don't need to do any of this! The .NET MAUI Community Toolkit has this built-in. You can just install the NuGet package, consume this converter and you're on your way.

    Find the documentation for that on this page.