简体   繁体   中英

ListView not displaying until I swipe the screen

I trying to implement StateContainer by Patrick McCurley in my .NET MAUI application. It works correctly when the ListView displayed for the first time. But ListView is not displaying when state changes again until I swipe the screen.

When I add any view element (label, button, etc.) to the view that contains the ListView, it does not show up. But ListView displayed correctly when I move StateContainer to Grid with any other view elements. ListView does not display correctly if the Grid contains no other elements than the StateContainer.

I can't figure out what's the problem here. Grid with other view elements is not a solution for me, because my page should not contain any other elements whan the StateContainer.

Here is an example that reproduces the problem:

PS I'm sorry for a lot of code:) I don't know where the problem could be.

States.cs

public enum States
{
    Loading, 
    Success
}

StateCondition.cs

[ContentProperty("Content")]
public class StateCondition : View
{
    public object State { get; set; }
    public View Content { get; set; }
}

StateContainer.cs

[ContentProperty("Conditions")]
public class StateContainer : ContentView
{
    public List<StateCondition> Conditions { get; set; } = new();

    public static readonly BindableProperty StateProperty = 
        BindableProperty.Create(nameof(State), typeof(object), typeof(StateContainer), null, BindingMode.Default, null, StateChanged);

    private static void StateChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var parent = bindable as StateContainer;
        if (parent != null)
            parent.ChooseStateProperty(newValue);
    }

    public object State
    {
        get { return GetValue(StateProperty); }
        set { SetValue(StateProperty, value); }
    }

    private void ChooseStateProperty(object newValue)
    {
        if (Conditions == null && Conditions?.Count == 0) return;

        var stateCondition = Conditions
            .FirstOrDefault(condition =>
                condition.State != null &&
                condition.State.ToString().Equals(newValue.ToString()));

        if (stateCondition == null) return;

        Content = stateCondition.Content;
    }
}

MainPage.xaml

<ContentPage ...>

    <state:StateContainer State="{Binding State}">

        <state:StateCondition State="Loading">
            <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
                <ActivityIndicator IsRunning="True" />
                <Label Text="Updating data..." />
            </StackLayout>
        </state:StateCondition>

        <state:StateCondition State="Success">
            <ListView ItemsSource="{Binding SomeData}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Label Text="{Binding . }" />
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </state:StateCondition>

    </state:StateContainer>

</ContentPage>

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    private States _state;
    private int[] _someData;

    public MainPage()
    {
        InitializeComponent();
        this.BindingContext = this;

        SomeData = new[] { 1, 2, 3, 4, 5 };
        State = States.Success;

        // it can be executed from outside the page
        _ = Task.Run(ExecuteSomeWorkAsync);
    }

    public States State
    {
        get => _state;
        private set
        {
            if (_state != value)
            {
                _state = value;
                OnPropertyChanged();
            }
        }
    }
    public int[] SomeData
    {
        get => _someData;
        private set
        {
            if (_someData != value)
            {
                _someData = value;
                OnPropertyChanged();
            }
        }
    }

    public async Task ExecuteSomeWorkAsync()
    {
        await Task.Delay(2000);

        State = States.Loading;

        await Task.Delay(2000);

        // generate new data for displaying
        Random rnd = new();
        var data = Enumerable.Range(0, 5).Select(n => rnd.Next(0, 5)).ToArray();

        SomeData = data;
        State = States.Success;
    }
}

I suspect Content = stateCondition.Content; won't update display correctly.

As an alternative solution, define public class StateContainer: StackLayout , and use IsVisible="True"/"False" on each child, to control what is shown. All the stateConditions continue to be children of stateContainer, but make only one visible at a time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM