1
votes

I am trying to update the visibility of a stacklayout of a tabbed page on user interaction and it the inverse boolean doesn't seem to work right away. i have to goto another page and come back again to see the inverse boolean converter work properly. Can anyone suggest if i am missing anything.

XAML:

<page:ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:page="clr-namespace:My.Pages"
                    x:Class="Home"
                    xmlns:converter="clr-namespace:My.Pages.ValueConverters"
.....//....>
    
        <StackLayout x:Name="stack1" Spacing="4" IsVisible="{Binding IsSomethingVisible, Converter={x:Static converter:InverseBoolConverter.Create}}">
            <Label Text="Hello" IsVisible="{Binding IsSomethingelseVisible}"/>
            <Label Text="Hi" IsVisible="{Binding IsSomethingelse2Visible}"/>
        </StackLayout>
        <StackLayout x:Name="stack2" Spacing="4" IsVisible="{Binding IsSomethingVisible}">
            <Label Text="Hello" IsVisible="{Binding IsSomethingelseVisible}"/>
            <Label Text="Hi" IsVisible="{Binding IsSomethingelse2Visible}"/>
        </StackLayout>

Converter:

public class InverseBoolConverter : IValueConverter
    {
        public static InverseBoolConverter Create {
            get {
                return new InverseBoolConverter();
            }
        }

        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 !((bool)value);
        }
    }

ViewModel:

private bool _isSomethingVisible;
        public bool IsSomethingVisible
        {
            get { return _isSomethingVisible; }
            set
            {
                _isSomethingVisible = value;
                RaisePropertyChanged(nameof(IsSomethingVisible));
            }
        }
    
Public Void OnUserInteractionCommand()
{
    DoSomething().ContinueWith((task) => {
        Device.BeginInvokeOnMainThread(() =>{ IsSomethingVisible = true;});
    });
}

Current scenario:

By default stack1 is visible but when OnUserInteractionCommand is called stack2 is visible and stack1 is also visible, user needs to go to different page and come back again then just stack2 is visible and stack1 is not visible.

Expected : When OnUserInteractionCommand is called stack2 should be visible and stack1 is not visible.

2
I don't see anything wrong with the converter. To make sure that is where the problem is, can you try the following test: Make a second property IsOneVisible, that is initialized to true. In OnUserInteractionCommand, also set IsOneVisible = false;. And change stack1 to use that IsVisible="{Binding IsOneVisible}". If this works, then that proves the problem is related to the converter. If this does not work, then it is a much subtler issue - from where is OnUserInteractionCommand called? A possible work-around is to invoke on UI with a 100 ms delay. - ToolmakerSteve

2 Answers

0
votes

Expected : When OnUserInteractionCommand is called stack2 should be visible and stack1 is not visible.

I modify your code about your Converter and create simple sample to test, having no problem.

<ContentPage
x:Class="FormsSample.simplecontrol.Page19"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converter="clr-namespace:FormsSample.converter">
<ContentPage.Resources>
    <converter:Visibleconverter x:Key="VisibleConverter" />
</ContentPage.Resources>
<ContentPage.Content>
    <StackLayout>
        <StackLayout x:Name="stack1" IsVisible="{Binding IsSomethingVisible, Converter={StaticResource VisibleConverter}}">
            <Label Text="Hello" />
            <Label Text="Hi" />
            <Label Text="stack1" />
        </StackLayout>
        <StackLayout x:Name="stack2" IsVisible="{Binding IsSomethingVisible}">
            <Label Text="Hello" />
            <Label Text="Hi" />
            <Label Text="stack2" />
        </StackLayout>

        <Button
            x:Name="btn1"
            Clicked="btn1_Clicked"
            Text="change visible" />
    </StackLayout>

</ContentPage.Content>

Visibleconverter.cs:

public class Visibleconverter : 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)
    {
        throw new NotImplementedException();
    }
}

I change isSomethingVisible value by button.click.

public partial class Page19 : ContentPage, INotifyPropertyChanged
{
    private bool _isSomethingVisible;
    public bool IsSomethingVisible
    {
        get { return _isSomethingVisible; }
        set
        {
            _isSomethingVisible = value;
            RaisePropertyChanged(nameof(IsSomethingVisible));
        }
    }
    public Page19()
    {
        InitializeComponent();
        this.BindingContext = this;
    }

   
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private void btn1_Clicked(object sender, EventArgs e)
    {
        Device.BeginInvokeOnMainThread(() => { IsSomethingVisible = !IsSomethingVisible; });
    }
}
0
votes

I have no idea what you're trying to do with this line of code.

<StackLayout x:Name="stack1" Spacing="4" IsVisible="{Binding IsSomethingVisible, Converter={x:Static converter:InverseBoolConverter.Create}}">

Typically, you would register it in App.xaml so that it can be used throughout the app. That won't be the last time you need an inverse bool converter. Yoiu could also register it in the page resources.

<ContentPage.Resources>
    <converter:Visibleconverter x:Key="VisibleConverter" />
</ContentPage.Resources>

Then just access the converter as a static resource:

<StackLayout x:Name="stack1" IsVisible="{Binding IsSomethingVisible, Converter={StaticResource VisibleConverter}}">