Skip to content

Instantly share code, notes, and snippets.

@zirkelc
Last active June 16, 2017 15:15
Show Gist options
  • Save zirkelc/c8b05dc12cf8eb0222b9ca3bfdebdd19 to your computer and use it in GitHub Desktop.
Save zirkelc/c8b05dc12cf8eb0222b9ca3bfdebdd19 to your computer and use it in GitHub Desktop.
public interface INavigationService
{
void RegisterViewModels(System.Reflection.Assembly asm);
void Register(Type viewModelType, Type viewType);
Task PopAsync();
Task PopModalAsync();
Task PushAsync<T>(T viewModel) where T : class, IViewModel;
Task PushAsync<T>(Action<T> initialize = null) where T : class, IViewModel;
Task PushModalAsync<T>(Action<T> initialize = null) where T : class, IViewModel;
Task PushModalAsync<T>(T viewModel) where T : class, IViewModel;
Task PopToRootAsync(bool animate);
void SwitchDetailPage<T>(Action<T> initialize = null) where T : class, IViewModel;
void SwitchDetailPage<T>(T viewModel) where T : class, IViewModel;
}
public interface IViewFor
{
//object ViewModel { get; set; }
}
public interface IViewFor<T> : IViewFor where T : IViewModel
{
T ViewModel { get; set; }
}
public interface IViewModel
{
}
public class NavigationService : INavigationService
{
static INavigationService instance;
public static INavigationService Instance => instance ?? (instance = new NavigationService());
INavigation FormsNavigation
{
get
{
var tabController = Application.Current.MainPage as TabbedPage;
var masterController = Application.Current.MainPage as MasterDetailPage;
// First check to see if we're on a tabbed page, then master detail, finally go to overall fallback
return tabController?.CurrentPage?.Navigation ??
(masterController?.Detail as TabbedPage)?.CurrentPage?.Navigation ?? // special consideration for a tabbed page inside master/detail
masterController?.Detail?.Navigation ??
Application.Current.MainPage.Navigation;
}
}
// View model to view lookup - making the assumption that view model to view will always be 1:1
readonly Dictionary<Type, Type> _viewModelViewDictionary = new Dictionary<Type, Type>();
#region Replace
// Because we're going to do a hard switch of the page, either return
// the detail page, or if that's null, then the current main page
Page DetailPage
{
get
{
var masterController = Application.Current.MainPage as MasterDetailPage;
return masterController?.Detail ?? Application.Current.MainPage;
}
set
{
var masterController = Application.Current.MainPage as MasterDetailPage;
if (masterController != null)
{
masterController.Detail = value;
masterController.IsPresented = false;
}
else
{
Application.Current.MainPage = value;
}
}
}
public void SwitchDetailPage<T>(T viewModel) where T : class, IViewModel
{
var view = InstantiateView<T>(viewModel);
Page newDetailPage;
// Tab pages shouldn't go into navigation pages
if (view is TabbedPage)
newDetailPage = (Page)view;
else
newDetailPage = new NavigationPage((Page)view);
DetailPage = newDetailPage;
}
public void SwitchDetailPage<T>(Action<T> initialize = null) where T : class, IViewModel
{
T viewModel;
// First instantiate the view model
viewModel = Activator.CreateInstance<T>();
initialize?.Invoke(viewModel);
// Actually switch the page
SwitchDetailPage(viewModel);
}
#endregion
#region Registration
public void RegisterViewModels(Application app)
{
}
public void RegisterViewModels(System.Reflection.Assembly asm)
{
// Loop through everything in the assembley that implements IViewFor<T>
foreach (var type in asm.DefinedTypes.Where(dt => !dt.IsAbstract &&
dt.ImplementedInterfaces.Any(ii => ii == typeof(IViewFor))))
{
// Get the IViewFor<T> portion of the type that implements it
var viewForType = type.ImplementedInterfaces.FirstOrDefault(
ii => ii.IsConstructedGenericType &&
ii.GetGenericTypeDefinition() == typeof(IViewFor<>));
// Register it, using the T as the key and the view as the value
Register(viewForType.GenericTypeArguments[0], type.AsType());
}
}
public void Register(Type viewModelType, Type viewType)
{
if(!_viewModelViewDictionary.ContainsKey(viewModelType))
_viewModelViewDictionary.Add(viewModelType, viewType);
}
#endregion
#region Pop
public async Task PopAsync()
{
await FormsNavigation.PopAsync(true);
}
public async Task PopModalAsync()
{
await FormsNavigation.PopModalAsync(true);
}
public async Task PopToRootAsync(bool animate)
{
await FormsNavigation.PopToRootAsync(animate);
}
#endregion
#region Push
public async Task PushAsync<T>(T viewModel) where T : class, IViewModel
{
var view = InstantiateView<T>(viewModel);
await FormsNavigation.PushAsync((Page)view);
}
public async Task PushModalAsync<T>(T viewModel) where T : class, IViewModel
{
var view = InstantiateView<T>(viewModel);
// Most likely we're going to want to put this into a navigation page so we can have a title bar on it
var nv = new NavigationPage((Page)view);
await FormsNavigation.PushModalAsync(nv);
}
public async Task PushAsync<T>(Action<T> initialize = null) where T : class, IViewModel
{
T viewModel;
// Instantiate the view model & invoke the initialize method, if any
viewModel = Activator.CreateInstance<T>();
initialize?.Invoke(viewModel);
await PushAsync(viewModel);
}
public async Task PushModalAsync<T>(Action<T> initialize = null) where T : class, IViewModel
{
T viewModel;
// Instantiate the view model & invoke the initialize method, if any
viewModel = Activator.CreateInstance<T>();
initialize?.Invoke(viewModel);
await PushModalAsync(viewModel);
}
#endregion
//IViewFor InstantiateView(IViewModel viewModel)
//{
// // Figure out what type the view model is
// var viewModelType = viewModel.GetType();
// // look up what type of view it corresponds to
// var viewType = _viewModelViewDictionary[viewModelType];
// // instantiate it
// var view = (IViewFor)Activator.CreateInstance(viewType);
// view.ViewModel = viewModel;
// return view;
//}
IViewFor<T> InstantiateView<T>(T viewModel) where T : class, IViewModel
{
// Figure out what type the view model is
var viewModelType = viewModel.GetType();
// look up what type of view it corresponds to
var viewType = _viewModelViewDictionary[viewModelType];
// instantiate it
var view = (IViewFor<T>)Activator.CreateInstance(viewType);
view.ViewModel = viewModel as T;
return view;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment