I am working on xamarin.form cross-platform application , i want to navigate from one page to another on button click. As i cannot do Navigation.PushAsync(new Page2());
decided to add two ways to pass Page instance to viewmodel which you can use later for navigation, displaying alerts. closing page and so on.
1. if you can pass it with command parameter
in view model:
public ICommand cmdAddRecord { get; set; }
viewmodel constructor
cmdAddRecord = new Command<ContentPage>(AddRecord);
somewhere in viewmodel
void AddRecord(ContentPage parent)
{
parent.Navigation.Whatever
}
XAML
header
x:Name="thisPage"
usage
<ToolbarItem IconImageSource="{StaticResource icAdd}" Command="{Binding cmdAddRecord}" CommandParameter="{Binding ., Source={x:Reference thisPage}}" />
2. started using this in my base class for viewmodels
viewmodel
public class cMyBaseVm : BindableObject
...
public static BindableProperty ParentProperty = BindableProperty.Create("Parent", typeof(ContentPage), typeof(cMyBaseVm), null, BindingMode.OneWay);
...
public ContentPage Parent
{
get => (ContentPage)GetValue(ParentProperty);
set => SetValue(ParentProperty, value);
}
XAML
xmlns:viewModels="clr-namespace:yournamespace.ViewModels"
x:Name="thisPage"
and here we go
<ContentPage.BindingContext>
<viewModels:cPetEventsListVm Parent="{Binding ., Source={x:Reference thisPage}}" />
</ContentPage.BindingContext>
child viewmodel
public class cPetEventsListVm : cMyBaseVm
and now, all around child view model we can use Page like Parent.DisplayAlert , or Parent.Navigation.PushAsync etc we may even close page now from view model with Parent.PopAsync ();
my approach based on principle every View can navigate to VM context based places of the app only:
In ViewModel i declare INavigationHandler interfeces like that:
public class ItemsViewModel : ViewModelBase
{
public INavigationHandler NavigationHandler { private get; set; }
// some VM code here where in some place i'm invoking
RelayCommand<int> ItemSelectedCommand =>
new RelayCommand<int>((itemID) => { NavigationHandler.NavigateToItemDetail(itemID); });
public interface INavigationHandler
{
void NavigateToItemDetail(int itemID);
}
}
And assign code-behind class as INavigationHandler for ViewModel:
public class ItemsPage : ContentPage, ItemsViewModel.INavigationHandler
{
ItemsViewModel viewModel;
public ItemsPage()
{
viewModel = Container.Default.Get<ItemsViewModel>();
viewModel.NavigationHandler = this;
}
public async void NavigateToItemDetail(int itemID)
{
await Navigation.PushAsync(new ItemDetailPage(itemID));
}
}