Example :
Navigation to Other Page.
Navigating to another Page From App.xaml.cs (Start Up)
var navigationService = DependencyService.Resolve<INavigationService>();
navigationService.NavigateToAsync<LoginViewModel>(isRootPage: true);
Navigating to another Page From ViewModel
NavigationService.NavigateToAsync<LoginViewModel>(isRootPage: true);
Navigating to another Page With Parameter
var obj = new { firstName="Hello", age = 26 }
NavigationService.NavigateToAsync<LoginViewModel>(obj,isRootPage: false);
Accessing Passed Parameter
All ViewModels are inherited BaseViewModel and it contains Initialize method that you just need to override in All ViewModels.
protected internal override void Initialize(object navigationData, Page uiRef = null) { base.Initialize(navigationData); string firstName = TryGetValue(navigationData,nameof(firstName)); int age = TryGetValue<int>(navigationData,nameof(age)); }
Naming Convention of Page & ViewModel
ViewModel: Same as page Name Append With Model.
Example: LoginView is page name and LoginViewModel is ViewModel Name.
TestView is page name and TestViewModel is ViewModel Name.
Now Create INavigationService Interface that Includes the following methods.
INavigationService.cs
public interface INavigationService
{
T GetPageViewModel<T>() where T : new();
//T GetPageView<T>() where T : Page, new();
Task RemovePages<T>() where T : new();
Task NavigateToAsync<TViewModel>(object parameter = null, bool isRootPage = false, bool isPopupPage = false, bool isSubscribeOnAppear = false, bool isFetchUI = false) where TViewModel : BaseViewModel;
void InsertPageBeforeLastPage<TViewModel>(object parameter = null, bool isSubscribeOnAppear = false, bool isFetchUI = false) where TViewModel : BaseViewModel;
}
Usage:
Task RemovePages<T>() where T : new();
This method will removed all pages till it reach the specified ViewModel Name.
Task NavigateToAsync<TViewModel>(object parameter = null, bool isRootPage = false, bool isSubscribeOnAppear = false, bool isFetchUI = false) where TViewModel : BaseViewModel;
This method used for navigating from one page to another page.
parameter: It will accept any type of object that you want to bring to another page.
isRootPage: It will set the page as a root page, like App.Current.MainPage = new NavigationPage(Page Name)
isSubscribeOnAppear: This Will Subscribe OnAppear() Method of page.
isFetchUI: This flag used for getting view reference in ViewModel.
TViewModel: BaseViewModel: Create BaseViewModel Class that contains Some Common Property and INavigationService Declaration.
BaseViewModel.cs
public class BaseViewModel : INotifyPropertyChanged
{
#region Properties
private string _title;
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
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);
}
public bool IsRefreshData { get; set; }
#endregion
#region Services
protected readonly INavigationService NavigationService;
#endregion
#region Commands
public ICommand ItemSelectedCommand { get; protected set; }
public ICommand RefreshCommand { get; protected set; }
#endregion
#region Construtor
public BaseViewModel()
{
NavigationService = DependencyService.Resolve<INavigationService>();
}
#endregion
#region Methods
protected internal virtual void Initialize(object navigationData, Page uiRef = null) { }
protected internal virtual void OnAppearing() { }
public static T TryGetValue<T>(object navigationData, string propertyName = "") where T : new()
{
var returnValue = new T();
try
{
if (navigationData != null)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
returnValue = (T)navigationData;
}
else
{
returnValue = (T)navigationData.GetType().GetProperty(propertyName).GetValue(navigationData);
}
}
}
catch (Exception ex)
{
}
return returnValue;
}
public static string TryGetValue(object navigationData, string propertyName = "")
{
var returnValue = string.Empty;
try
{
if (navigationData != null)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
returnValue = (string)navigationData;
}
else
{
returnValue = (string)navigationData.GetType().GetProperty(propertyName).GetValue(navigationData);
}
}
}
catch (Exception ex)
{
}
return returnValue;
}
#endregion
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
}
Create NavigationService class that Implement INavigationService.cs Interface.
NavigationService.cs
public class NavigationService : INavigationService
{
public async Task NavigateToAsync<TViewModel>(object parameter = null, bool isRootPage = false, bool isPopupPage = false, bool isSubscribeOnAppear = false, bool isFetchUI = false) where TViewModel : BaseViewModel
{
Type viewModelType = typeof(TViewModel);
Type pageType = GetPageTypeForViewModel(viewModelType);
if (pageType == null)
throw new Exception($"Cannot locate page type for {viewModelType}");
try
{
BaseViewModel viewModel = Activator.CreateInstance(viewModelType) as BaseViewModel;
ContentPage page = Activator.CreateInstance(pageType) as ContentPage;
page.BindingContext = viewModel;
if (isRootPage)
Application.Current.MainPage = new NavigationPage(page);
else
{
var navigationPage = Application.Current.MainPage as NavigationPage;
if (navigationPage != null)
await navigationPage.PushAsync(page, true);
else
Application.Current.MainPage = new NavigationPage(page);
}
if (!isFetchUI)
viewModel.Initialize(parameter);
else
viewModel.Initialize(parameter, page);
if (isSubscribeOnAppear)
{
page.Appearing -= new EventHandler(OnAppearing);
page.Appearing += new EventHandler(OnAppearing);
}
}
catch (Exception ex)
{
}
}
private void OnAppearing(object sender, EventArgs e)
{
var viewModel = ((Page)(sender)).BindingContext as BaseViewModel;
if (viewModel.IsRefreshData) viewModel.OnAppearing();
}
private Type GetPageTypeForViewModel(Type viewModelType)
{
var viewModelAssemblyName = viewModelType.GetTypeInfo().Assembly.FullName;
var viewName = viewModelType.FullName.Replace("ViewModel", "View");
var viewAssemblyName = string.Format(
CultureInfo.InvariantCulture, "{0}, {1}", viewName, viewModelAssemblyName);
var viewType = Type.GetType(viewAssemblyName);
return viewType;
}
public T GetPageViewModel<T>() where T : new()
{
var mainPage = Application.Current.MainPage as NavigationPage;
var pageNeedToReturn = mainPage.Navigation.NavigationStack.Where(f => f.BindingContext.GetType() == typeof(T)).FirstOrDefault();
if (pageNeedToReturn != null)
{
return (T)pageNeedToReturn.BindingContext;
}
return default(T);
}
//public T GetPageView<T>() where T : Page, new()
//{
// var mainPage = Application.Current.MainPage as NavigationPage;
// var pageNeedToReturn = mainPage.Navigation.NavigationStack.Where(f => f.GetType() == typeof(T)).FirstOrDefault();
// if (pageNeedToReturn != null)
// {
// return (T)pageNeedToReturn;
// }
// return default(T);
//}
public void InsertPageBeforeLastPage<TViewModel>(object parameter = null, bool isSubscribeOnAppear = false, bool isFetchUI = false) where TViewModel : BaseViewModel
{
Type viewModelType = typeof(TViewModel);
Type pageType = GetPageTypeForViewModel(viewModelType);
if (pageType == null)
throw new Exception($"Cannot locate page type for {viewModelType}");
try
{
BaseViewModel viewModel = Activator.CreateInstance(viewModelType) as BaseViewModel;
Page page = Activator.CreateInstance(pageType) as Page;
page.BindingContext = viewModel;
var lastPage = App.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
if (!isFetchUI)
viewModel.Initialize(parameter);
else
viewModel.Initialize(parameter, page);
if (isSubscribeOnAppear)
{
page.Appearing -= new EventHandler(OnAppearing);
page.Appearing += new EventHandler(OnAppearing);
}
App.Current.MainPage.Navigation.InsertPageBefore(page, lastPage);
}
catch (Exception ex)
{
}
}
/// <summary>
/// Specified the page name (it will remove pages till specified page name)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public async Task RemovePages<T>() where T : new()
{
var returnValue = new T();
var pages = App.Current.MainPage.Navigation.NavigationStack.ToList();
for (int maxPageIndex = pages.Count - 1; maxPageIndex >= 0; maxPageIndex--)
{
var currnetPage = pages[maxPageIndex];
if (currnetPage != null)
{
if (currnetPage.BindingContext.GetType() == returnValue.GetType())
{
break;
}
else
{
App.Current.MainPage.Navigation.RemovePage(currnetPage);
}
}
}
await App.Current.MainPage.Navigation.PopAsync();
}
Registration of NavigationService on App.xaml.cs
No comments:
Post a Comment