Search code examples
xamlxamarin.formsrefreshexpander

Refresh xaml page every x seconds and keep the current expander state


I have a xamarin project. There is a scrollview with a list of expanders.

I like to refresh the page every x seconds, but keep the state of my expanders (isExpanded boolean).

How do I check the state of my expanders (or label, button, whatever) and keep these values during a refresh every x seconds?

I feel like I have to add a parameter to my behindcode function, similar to the 'object sender' during a tap or click event.

In the behindcode I am trying to refresh the page every x seconds with

Device.StartTimer(TimeSpan.FromSeconds(x),Updatefunction);

Currently they all have their default isExpanded (false) state when the page refreshes.


Solution

  • You can add a bool property in the viewModel, then binding this property to IsExpanded="{Binding Expand1Opened}" in <Expander> tab. When user click the Expander, IsExpanded will depend on the value of Expand1Opened property. no matter the refresh the page every x seconds, it will keep the current expander state. And I add Command for Expander, if Expander is clicked, value of Expand1Opened property will be changed in the ViewModel.

     <RefreshView IsRefreshing="{Binding IsRefreshing}"
                         RefreshColor="Teal"
                         Command="{Binding RefreshCommand}">
                <ScrollView>
                    <StackLayout>
                        <Expander IsExpanded="{Binding Expand1Opened}" Command="{Binding Expand1OpenedCommand}">
                        <Expander.Header>
                            <Label Text="List1"
                   FontAttributes="Bold"
                   FontSize="Medium" />
                        </Expander.Header>
                        <Grid Padding="10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <FlexLayout Direction="Row"
                                Wrap="Wrap"
                                AlignItems="Center"
                                AlignContent="Center"
                                BindableLayout.ItemsSource="{Binding Items}"
                                BindableLayout.ItemTemplate="{StaticResource ColorItemTemplate}" />
                        </Grid>
                    </Expander>
    
                        <Expander IsExpanded="{Binding Expand2Opened}" Command="{Binding Expand2OpenedCommand}">
                        <Expander.Header>
                            <Label Text="List2"
                   FontAttributes="Bold"
                   FontSize="Medium" />
                        </Expander.Header>
                        <Grid Padding="10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <FlexLayout Direction="Row"
                                Wrap="Wrap"
                                AlignItems="Center"
                                AlignContent="Center"
                                BindableLayout.ItemsSource="{Binding Items}"
                                BindableLayout.ItemTemplate="{StaticResource ColorItemTemplate}" />
                        </Grid>
                    </Expander>
                    </StackLayout>
    
                </ScrollView>
            </RefreshView>
    

    Here is viewModel. I have two <Expander>, So I add two properties Expand1Opened and Expand2Opened, and add two Commands called Expand1OpenedCommand and Expand2OpenedCommand, if the <Expander> were clicked, Expand1OpenedCommand will be invoked, then value of Expand1Opened will be changed, If the refreshview was refreshed, value of Expand1Opened will not be changed, so expander's state wil be kept.

     public class MainPageViewModel : INotifyPropertyChanged
        {
            const int RefreshDuration = 2;
            int itemNumber = 1;
            readonly Random random;
            bool isRefreshing;
    
            public bool IsRefreshing
            {
                get { return isRefreshing; }
                set
                {
                    isRefreshing = value;
                    OnPropertyChanged();
                }
            }
    
            bool expand1Opened = false;
            public bool Expand1Opened
            {
                get { return expand1Opened; }
                set
                {
                    expand1Opened = value;
                    OnPropertyChanged();
                }
            }
    
            bool expand2Opened=false;
            public bool Expand2Opened
            {
                get { return expand2Opened; }
                set
                {
                    expand2Opened = value;
                    OnPropertyChanged();
                }
            }
            public ObservableCollection<Item> Items { get; private set; }
    
            public ICommand RefreshCommand => new Command(async () => await RefreshItemsAsync());
    
            public ICommand Expand1OpenedCommand { get; set; }
            public ICommand Expand2OpenedCommand { get; set; }
            public MainPageViewModel()
            {
                random = new Random();
                Items = new ObservableCollection<Item>();
    
                Expand1OpenedCommand = new Command((() =>
                {
                    expand1Opened = !expand1Opened;
                }));
                Expand2OpenedCommand = new Command((() =>
                {
                    expand2Opened = !expand2Opened;
                }));
    
    
                AddItems();
            }
    
            void AddItems()
            {
                for (int i = 0; i < 1; i++)
                {
                    Items.Add(new Item
                    {
                        Color = Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)),
                        Name = $"Item {itemNumber++}",
                        Isfavourite = false
    
                    }); 
                }
            }
    
            async Task RefreshItemsAsync()
            {
                IsRefreshing = true;
                await Task.Delay(TimeSpan.FromSeconds(RefreshDuration));
                AddItems();
                IsRefreshing = false;
            }
    
            #region INotifyPropertyChanged
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            #endregion
        }
    }
    

    Here is running GIF.

    enter image description here