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.
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 Command
s 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.