You can wrap any content in a RefreshView
to add pull-to-refresh functionality. Yes, ANY!
While ListView
has this baked-in, newer controls such as CollectionView
don't. All you need to do is surround the control or layout, add a command and boolean indicator, and viola!
<RefreshView | |
Command="{Binding RefreshCommand}" | |
IsRefreshing="{Binding IsRefreshing}" | |
> | |
<CollectionView | |
ItemsSource="{Binding Items}" | |
SelectedItem="{Binding SelectedItem, Mode=TwoWay}" | |
SelectionChangedCommand="{Binding SelectCommand}" | |
SelectionMode="Single"> | |
<CollectionView.ItemsLayout> | |
<GridItemsLayout | |
Orientation="Vertical" | |
Span="2" /> | |
</CollectionView.ItemsLayout> | |
<CollectionView.ItemTemplate> | |
<DataTemplate | |
x:DataType="blog:BlogItem"> | |
<blog:BlogView /> | |
</DataTemplate> | |
</CollectionView.ItemTemplate> | |
<CollectionView.EmptyView> | |
<FlexLayout Padding="30" | |
Direction="Column" | |
JustifyContent="Center" | |
VerticalOptions="Fill" | |
BackgroundColor="AliceBlue" | |
> | |
<Label | |
Text="Oops, we don't have any blogs to show. Try refreshing." | |
FontSize="24" | |
Margin="0,0,0,20" | |
/> | |
<Button Text="Refresh" | |
Command="{Binding RefreshCommand}"/> | |
</FlexLayout> | |
</CollectionView.EmptyView> | |
</CollectionView> | |
</RefreshView> |
public class BlogViewModel : BaseViewModel | |
{ | |
private bool isRefreshing; | |
public bool IsRefreshing{ | |
get => isRefreshing; | |
set => SetProperty(ref isRefreshing, value); | |
} | |
public Command RefreshCommand { get; set; } | |
public ObservableCollection<BlogItem> Items { get; } = new ObservableCollection<BlogItem>(); | |
public BlogViewModel() | |
{ | |
SelectCommand = new Command(async () => await Selected()); | |
RefreshCommand = new Command(() => OnRefresh()); | |
Task.Run(LoadData); | |
} | |
private void OnRefresh() | |
{ | |
Task.Run(LoadData); | |
} | |
public ICommand SelectCommand { get; set; } | |
private async Task Selected() | |
{ | |
if (SelectedItem == null) | |
return; | |
var item = SelectedItem; | |
SelectedItem = null; | |
await Shell.Current.GoToAsync($"blogDetail?id={item.Id}"); | |
} | |
public BlogItem SelectedItem { get; set; } | |
public async Task LoadData() | |
{ | |
Items.Clear(); | |
var current = Connectivity.NetworkAccess; | |
if(current == NetworkAccess.Internet) | |
{ | |
IsRefreshing = true; | |
var dataProvider = new BlogDataProvider(); | |
var items = await dataProvider.GetItems(); | |
Device.BeginInvokeOnMainThread(() => | |
{ | |
var random = new Random(); | |
items = items.OrderByDescending(x => x.PublishDate).ToList(); | |
Items.Clear(); | |
items.ForEach(x => | |
{ | |
x.Height = 200 + random.Next(0, 2) * 60; | |
Items.Add(x); | |
}); | |
} | |
); | |
} | |
IsRefreshing = false; | |
} | |
} |
Top comments (0)