Skip to content

Instantly share code, notes, and snippets.

@Henkoglobin
Created December 13, 2018 16:27
Show Gist options
  • Save Henkoglobin/9bdfc3607b92c2ff1db41287f663ecc0 to your computer and use it in GitHub Desktop.
Save Henkoglobin/9bdfc3607b92c2ff1db41287f663ecc0 to your computer and use it in GitHub Desktop.
public partial class App : Application, IAppNavigationResolver {
public App() {
InitializeComponent();
var container = new UnityDependencyContainer()
.Register<ISubViewModel, SubViewModel>()
.Register<IMainViewModel, MainViewModel>();
var navigationService = new NavigationService(this, container);
container.Register<INavigationService>(navigationService);
navigationService
.RegisterPage<IMainViewModel, MainPage>()
.RegisterPage<ISubViewModel, SubPage>();
var viewModel = container.Resolve<IMainViewModel>();
viewModel.ActivateAsync();
MainPage = new NavigationPage(new MainPage() {
BindingContext = viewModel
});
}
public async Task<IViewModel> GoBackAsync() {
await ((NavigationPage)this.MainPage).Navigation.PopAsync();
var newPage = ((NavigationPage)this.MainPage).CurrentPage;
return (IViewModel)newPage.BindingContext;
}
public async Task NavigateAsync<TViewModel>(Type pageType, TViewModel viewModel) where TViewModel : IViewModel {
var page = (Page)Activator.CreateInstance(pageType);
page.BindingContext = viewModel;
await ((NavigationPage)this.MainPage).Navigation.PushAsync(page);
}
public interface IAppNavigationResolver {
Task NavigateAsync<TViewModel>(Type pageType, TViewModel viewModel)
where TViewModel : IViewModel;
Task<IViewModel> GoBackAsync();
}
public interface IMainViewModel : IViewModel {
ICommand SubCommand { get; }
}
public interface INavigationService {
INavigationService RegisterPage<TViewModel, TPage>()
where TViewModel : IViewModel
where TPage : new();
Task<TViewModel> NavigateAsync<TViewModel>()
where TViewModel : IViewModel;
Task<IViewModel> GoBackAsync();
}
public interface ISubViewModel : IViewModel {
ICommand GoBackCommand { get; }
String Something { get; }
void Configure(string something);
}
public interface IViewModel {
Task ActivateAsync();
}
public class MainViewModel : IMainViewModel {
private INavigationService navigationService;
public ICommand SubCommand { get; }
public MainViewModel(INavigationService navigationService) {
this.navigationService = navigationService;
this.SubCommand = new RelayCommand(Navigate);
}
private async void Navigate() {
var viewModel = await this.navigationService.NavigateAsync<ISubViewModel>();
viewModel.configure("This is awesome!");
}
}
public class NavigationService : INavigationService {
private readonly IAppNavigationResolver appNavigationResolver;
private readonly IDependencyContainer dependencyContainer;
private readonly Dictionary<Type, Type> registeredPages = new Dictionary<Type, Type>();
public NavigationService(
IAppNavigationResolver appNavigationResolver,
IDependencyContainer dependencyContainer
) {
this.appNavigationResolver = appNavigationResolver;
this.dependencyContainer = dependencyContainer;
}
public async Task<IViewModel> GoBackAsync() {
var viewModel = await this.appNavigationResolver.GoBackAsync();
await viewModel.ActivateAsync();
return viewModel;
}
public async Task<TViewModel> NavigateAsync<TViewModel>()
where TViewModel : IViewModel {
Type pageType;
if(!registeredPages.TryGetValue(typeof(TViewModel), out pageType)) {
throw new InvalidOperationException($"No View registered for ViewModel type {typeof(TViewModel).Name}");
}
var viewModel = this.dependencyContainer.Resolve<TViewModel>();
await viewModel.ActivateAsync();
await this.appNavigationResolver.NavigateAsync(pageType, viewModel);
return viewModel;
}
public INavigationService RegisterPage<TViewModel, TPage>()
where TViewModel : IViewModel
where TPage : new() {
this.registeredPages.Add(typeof(TViewModel), typeof(TPage));
return this;
}
}
public class SubViewModel : ISubViewModel, INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private INavigationService navigationService;
public ICommand GoBackCommand { get; }
private string something;
public string Something {
get { return this.something; }
set {
this.something = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Something)));
}
}
public SubViewModel(INavigationService navigationService) {
this.navigationService = navigationService;
this.GoBackCommand = new RelayCommand(NavigateBack);
}
public void Configure(string something) {
this.Something = something;
}
private async void NavigateBack() {
await this.navigationService.GoBackAsync();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment