Search This Blog

Tuesday, 24 May 2022

Implementing Pull To Refresh With Collection View In .NET MAUI (MVVM)


Youtube: https://youtu.be/XBuSVcBdYo4

Refresh View: Add any view Inside Refresh View to achieve pull to refresh functionality. Let's go through the following examples.


Model:
Employee.cs
namespace MauiApp1.Models
{
    public class Employee
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string Email { get; set; }
    }
}
 
Views:
EmployeeListView.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.Views.EmployeeListView"
             xmlns:viewModels="clr-namespace:MauiApp1.ViewModels"
             xmlns:models="clr-namespace:MauiApp1.Models"
             x:DataType="viewModels:EmployeeListViewModel"
             Title="Employee List">
    <ContentPage.BindingContext>
        <viewModels:EmployeeListViewModel />
    </ContentPage.BindingContext>
    <StackLayout Margin="10">
        <ActivityIndicator IsRunning="True" IsVisible="{Binding IsBusy}" HeightRequest="50" WidthRequest="50" HorizontalOptions="Center" />
        <RefreshView Command="{Binding PullToRefreshCommand}" IsRefreshing="{Binding IsRefreshing}">
            <CollectionView ItemsSource="{Binding Employees}" >
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="models:Employee">
                        <Grid RowDefinitions="5,Auto,5,1">
                            <StackLayout Grid.Row="1">
                                <Label Text="{Binding Name}" FontSize="18" FontAttributes="Bold" />
                                <Label Text="{Binding Email}" FontSize="16"  />
                                <Label Text="{Binding Address}" FontSize="16"  />
                            </StackLayout>
                            <BoxView Grid.Row="3" HeightRequest="1" BackgroundColor="Gray" />
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </RefreshView>
    </StackLayout>
</ContentPage>
 
ViewModels:
BaseViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
 
namespace MauiApp1.ViewModels
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        private bool _isBusy;
        public bool IsBusy
        {
            get => _isBusy;
            set => SetProperty(ref _isBusy, value);
        }
 
        private bool _isRefreshing;
        public bool IsRefreshing
        {
            get => _isRefreshing;
            set => SetProperty(ref _isRefreshing, value);
        }
 
        protected bool SetProperty<T>(ref T backingStore, T value,
       [CallerMemberName] string propertyName = "",
       Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;
 
            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }
 
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;
 
            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}
 
EmployeeListViewModel.cs
using MauiApp1.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
 
namespace MauiApp1.ViewModels
{
    public class EmployeeListViewModel : BaseViewModel
    {
        #region Properties
        public ObservableCollection<Employee> Employees { get; set; } = new ObservableCollection<Employee>();
        #endregion
 
 
        #region Constructor
        public EmployeeListViewModel()
        {
            AddDummyEmployeeList();
        }
        #endregion
 
        #region Methods
        private async void AddDummyEmployeeList()
        {
            IsBusy = true;
            await Task.Delay(500); // Write api call here and add that in list
            Employees.Clear();
            Employees.Add(new Employee { Name = "Pragnesh Mistry", Email = "test@gmail.com", Address = "India" });
            Employees.Add(new Employee { Name = "Janani", Email = "abc@gmail.com", Address = "India" });
            Employees.Add(new Employee { Name = "Rahul", Email = "xyz@gmail.com", Address = "India" });
            Employees.Add(new Employee { Name = "Ankit", Email = "test@gmail.com", Address = "India" });
            Employees.Add(new Employee { Name = "Vijay", Email = "test@gmail.com", Address = "India" });
            Employees.Add(new Employee { Name = "Jay", Email = "test@gmail.com", Address = "India" });
            IsBusy = false;
        }
        #endregion
 
 
        #region Commands
        public ICommand PullToRefreshCommand => new Command(() =>
        {
            IsRefreshing = false;
            AddDummyEmployeeList();
        });
        #endregion
 
 
    }
}
 


On App Start Navigate to EmployeeListView Page.
App.xaml.cs
using MauiApp1.Views;
 
namespace MauiApp1;
 
public partial class App: Application
{
    public App()
    {
	InitializeComponent();

        MainPage = new NavigationPage( new EmployeeListView());     } }  


Monday, 23 May 2022

How to display PopupPage In .NET MAUI / Xamarin (PushModalAsync)


 





Create a BasePopupPage Control In Your .NET MAUI Project.

BasePopupPage: these controls have default UI and one bindable property called PopupContent that you can use on any Page. I designed BasePopupPage UI as per my requirement you can modify it as per your usage.

BasePopupPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.Controls.BasePopupPage"
             x:Name="this"
             Title="BasePopupPage" >
    <ContentPage.Content>
        <StackLayout   VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
            <Frame VerticalOptions="EndAndExpand" CornerRadius="20" BackgroundColor="White">
                <StackLayout Padding="5,0,5,50"  >
                    <StackLayout  Padding="0,0,0,15">
                        <BoxView  BackgroundColor="LightGray" CornerRadius="5" WidthRequest="100" HeightRequest="10" />
                        <StackLayout.GestureRecognizers>
                            <SwipeGestureRecognizer  Command="{Binding Source={x:Reference this},Path=PopModelCommand}" Threshold="15" Direction="Down" />
                        </StackLayout.GestureRecognizers>
                    </StackLayout>
                    <ContentView   x:Name="ContentView"  />
                </StackLayout>
            </Frame>
            <StackLayout.GestureRecognizers>
                <TapGestureRecognizer Command="{Binding Source={x:Reference this},Path=PopModelCommand}" />
            </StackLayout.GestureRecognizers>
        </StackLayout>
    </ContentPage.Content>
 
</ContentPage>
 

BasePopupPage.xaml.cs
using System.Windows.Input;
 
namespace MauiApp1.Controls;
 
public partial class BasePopupPage : ContentPage
{
    public BasePopupPage()
    {
        InitializeComponent();
        this.BackgroundColor = Color.FromArgb("#80000000");
    }
 
    public static  readonly BindableProperty PopupContentProperty = BindableProperty.Create(
        propertyName: nameof(PopupContent),
        returnType: typeof(View),
        declaringType: typeof(BasePopupPage),
        defaultValue: null,
        defaultBindingMode: BindingMode.OneWay,
        propertyChanged: PopupContentPropertyChanged);
 
    private static void PopupContentPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var controls = (BasePopupPage)bindable;
        if (newValue != null)
            controls.ContentView.Content = (View)newValue;
    }
 
    public  View PopupContent
    {
        get => (View)GetValue(PopupContentProperty);
        set { SetValue(PopupContentProperty, value); }
    }
 
    public ICommand PopModelCommand => new Command(async() =>
    {
        await App.Current.MainPage.Navigation.PopModalAsync();
    });
}


How To Use BasePopupPage.
PopupPage1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<controls:BasePopupPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:controls="clr-namespace:MauiApp1.Controls"
    x:Class="MauiApp1.Views.PopupPage1">
    <controls:BasePopupPage.PopupContent>
        <StackLayout Spacing="15">
                <Label Text="Select An Option" FontSize="16" FontAttributes="Bold"   TextColor="Black"/>
 
                <Label Text="Navigate To Other Popup Page" >
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_NavigateToPoupPage1" />
                    </Label.GestureRecognizers>
                </Label>
                <BoxView BackgroundColor="Black" HeightRequest="1" />
                <Label Text="Navigate to Page" >
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_NavigateToNormalPage" />
                    </Label.GestureRecognizers>
                </Label>
                <BoxView BackgroundColor="Black" HeightRequest="1" />
            </StackLayout>
        </controls:BasePopupPage.PopupContent>
 </controls:BasePopupPage>
 
PopupPage.xaml.cs
using MauiApp1.Controls;
 
namespace MauiApp1.Views;
 
public partial class PopupPage1 : BasePopupPage
{
    public PopupPage1()
    {
        InitializeComponent();
    }
 
    private async void TapGestureRecognizer_Tapped_NavigateToPoupPage1(object sender, EventArgs e)
    {
        await App.Current.MainPage.Navigation.PushModalAsync(new PopupPage2());
    }
 
    private async void TapGestureRecognizer_Tapped_NavigateToNormalPage(object sender, EventArgs e)
    {
        await App.Current.MainPage.Navigation.PopModalAsync();
        await App.Current.MainPage.Navigation.PushAsync(new NewPage1());
    }
 
}

PopupPage2.xaml
<?xml version="1.0" encoding="utf-8" ?>
<controls:BasePopupPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:controls="clr-namespace:MauiApp1.Controls"
    x:Class="MauiApp1.Views.PopupPage2" >
    <controls:BasePopupPage.PopupContent>
        <StackLayout Spacing="15">
            <Label Text="Display Content Here" FontSize="16" FontAttributes="Bold"   TextColor="Black"/>
 
        </StackLayout>
    </controls:BasePopupPage.PopupContent>
</controls:BasePopupPage>
 

PopupPage2.xaml.cs
using MauiApp1.Controls;
 
namespace MauiApp1.Views;
 
public partial class PopupPage2 : BasePopupPage
{
    public PopupPage2()
    {
        InitializeComponent();
    }
}

Navigate To Main Page On App Start.
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.MainPage" Title="Main Page">
 
    <StackLayout 
            Spacing="25" 
            VerticalOptions="Center">
 
        <Button Text="Display PoupPage"
                Clicked="Button_Clicked" HorizontalOptions="Center" />
 
    </StackLayout>
 
</ContentPage>
 
MainPage.xaml.cs
using MauiApp1.Views;
 
namespace MauiApp1;
 
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }
 
    private async void Button_Clicked(object sender, EventArgs e)
    {
        await App.Current.MainPage.Navigation.PushModalAsync(new PopupPage1());
    }
}
 
 








Popular Posts