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());
I racked my brains on this a few days hitting the same hurdle when I switched to Xamarin development.
So my answer is to put the Type of the page in the Model but not restricting the View or the ViewModel to work with it also if one so chooses. This keeps the system flexible in that it does not tie up the Navigation via hard-wiring in the view or in the code-behind and therefore it is far more portable. You can reuse your models across the projects and merely set the type of the Page it will navigate to when such circumstance arrive in the other project.
To this end I produce an IValueConverter
public class PageConverter : IValueConverter
{
internal static readonly Type PageType = typeof(Page);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Page rv = null;
var type = (Type)value;
if (PageConverter.PageType.IsAssignableFrom(type))
{
var instance = (Page)Activator.CreateInstance(type);
rv = instance;
}
return rv;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var page = (Page)value;
return page.GetType();
}
}
And an ICommand
public class NavigateCommand : ICommand
{
private static Lazy PageConverterInstance = new Lazy(true);
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var page = PageConverterInstance.Value.Convert(parameter, null, null, null) as Page;
if(page != null)
{
Application.Current.MainPage.Navigation.PushAsync(page);
}
}
}
Now the Model may have an assignable Type for a page, therefore it can change, and the page can be different between your device types (e.g Phone, Watch, Android, iOS). Example:
[Bindable(BindableSupport.Yes)]
public Type HelpPageType
{
get
{
return _helpPageType;
}
set
{
SetProperty(ref _helpPageType, value);
}
}
And an example of it's use then in Xaml.
And for the sake of completeness the resource as defined in App.xaml
P.S. While the Command pattern generally should use one instance for one operation, in this case I know it is very safe to reuse the same instance across all controls and since it is for a wearable I want to keep things lighter than normal hence defining a single instance of the NavigationCommand in the App.xaml.