public static void Init(SynchronizationContext uiContext, IPlatformOptions options) { ThreadHelper.Init(uiContext); PlatformOptions = options; }
/// <summary> /// Will initialize anything needed within the framework. /// </summary> /// <param name="uiContext">Example: Pass through SynchronizationContext.Current</param> public static void Init(SynchronizationContext uiContext) { ThreadHelper.Init(uiContext); }
public StackResult Navigate(IStackOptions options) { lock (_lock) { StackResult stackResult = StackResult.StackStarted; if (options.StackChoice == null) { throw new NullReferenceException($"{nameof(NavigationService)}.{nameof(Navigate)} can not accept a null {nameof(options.StackChoice)}"); } // Don't change to the same stack if (_currentStack != null && _currentStack.Equals(options.StackChoice)) { return(StackResult.None); } if (!_stacks.ContainsKey(options.StackChoice)) { throw new NullReferenceException($"{nameof(NavigationService)} does not contain a stack named {options.StackChoice.ToString()}"); } // Current / Previous Stack IStack oldStack = null; if (_currentStack != null) { oldStack = _stacks[_currentStack]; oldStack.StateChange(StackStatus.Background); // Schedules NoHistoryRemoval } var stack = _stacks[options.StackChoice]; _currentStack = options.StackChoice; // Set new status stack.Proxy.ViewStatus = VisualStatus.Visible; // Switch over services _displayService.Init(stack.Proxy); ThreadHelper.RunOnUIThread(async() => { if (stack.Status == StackStatus.Stopped) { object args = null; // If ArgsKey present only pass args along if the StartKey is the same if ((!string.IsNullOrEmpty(options?.ArgsKey) && stack.NavigationStartKey == options?.ArgsKey) || string.IsNullOrEmpty(options?.ArgsKey)) { stackResult = stackResult | StackResult.ArgsPassed; args = options?.Args; } var loadStartKey = options?.PredefinedStack == null; if (loadStartKey) { stackResult = stackResult | StackResult.NavigationStarted; } await stack.StartNavigation(args: args, loadStartKey: loadStartKey); } // Preload Stack if (options?.PredefinedStack != null) { foreach (var page in options.PredefinedStack) { await Navigate(page.Key, page.Value); } } // Find mainview from ViewHierarchy var viewContainer = _viewContainers[_stackViewContainers[options.StackChoice]]; // Tabbed View if (viewContainer is ITabbedContainer) { var tabbedView = viewContainer as ITabbedContainer; // Must start all stacks on the first tabbed view load // because when the tab changes, I can't block while I load an individual tab // I can only block moving to an entire page foreach (var item in tabbedView.Children) { if (item.Status == StackStatus.Stopped) { await item.StartNavigation(options?.Args); } } } // MasterDetail View load if (viewContainer is IMasterDetailContainer) { var masterDetailContainer = viewContainer as IMasterDetailContainer; if (masterDetailContainer.DetailStack != null) { // Setup Detail Stack var detailStack = _stacks[masterDetailContainer.DetailStack.StackIdentifier]; if (detailStack.Status == StackStatus.Stopped) { await detailStack.StartNavigation(options?.Args); } masterDetailContainer.Proxy.DetailNativeView = detailStack.Proxy.NativeView; // Setup Master Stack var masterStack = _stacks[masterDetailContainer.MasterStack.StackIdentifier]; if (masterStack.Status == StackStatus.Stopped) { await masterStack.StartNavigation(options?.Args); } masterDetailContainer.Proxy.MasterNativeView = masterStack.Proxy.NativeView; } } _currentViewContainer = viewContainer; if (!string.IsNullOrEmpty(options.ViewKey)) { await Navigate(options.ViewKey, options.Args, options.NewInstance); } _setRoot?.Invoke(viewContainer.NativeView); if (oldStack != null) { await oldStack.StackChanged(); } }); return(stackResult); } }
public Task <IView> Build(ITypeDefinition definition) { lock (_lock) { IView view = null; if (definition.CacheView && _cachedViews.ContainsKey(definition.Type)) { view = _cachedViews[definition.Type]; } else { ConstructorInfo constructor = null; object[] parameters = null; constructor = definition.Type.GetTypeInfo() .DeclaredConstructors .FirstOrDefault(c => !c.GetParameters().Any()); parameters = new object[] { }; if (constructor == null) { throw new InvalidOperationException( $"No suitable constructor found for view {definition.Type.ToString()}"); } ThreadHelper.RunOnUIThread(() => { view = constructor.Invoke(parameters) as IView; }); if (view == null) { throw new InvalidOperationException( $"View {definition.Type.ToString()} does not implement the interface {nameof(IView)}"); } // Assign Binding Context if (_viewsByType.ContainsKey(definition.Type)) { view.BindingContext = GetBindingContext(definition.Type); var multiView = view as IMultiView; if (multiView != null) { foreach (var p in multiView.Views) { p.BindingContext = GetBindingContext(p.GetType()); } } } else { throw new InvalidOperationException( "No suitable view model found for view " + definition.Type.ToString()); } if (definition.CacheView) { _cachedViews.Add(definition.Type, view); } } return(Task.FromResult(view)); } }
public async Task Navigate(string key, object args, bool newInstance, bool popSource) { using (var releaser = await _lock.LockAsync()) { await ThreadHelper.RunOnUIThreadAsync(async() => { // Do not navigate to the same view, unless duplicate if (key == CurrentView.Key && !newInstance) { var model = CurrentViewTrack[CurrentViewTrack.Count - 1].BindingContext as IViewModel; if (model != null) { model.OnNavigated(args).ConfigureAwait(false).GetAwaiter(); // Do not await. } return; } var platformKey = Abstraction.Tuple.Create(key, App.PlatformOptions.Platform); var genericKey = Abstraction.Tuple.Create(key, (string)null); Abstraction.Tuple <string, string> tupleKey = Abstraction.Tuple.Create(string.Empty, (string)null); TypeDefinition viewKey = null; if (_viewsByKey.ContainsKey(platformKey)) { tupleKey = platformKey; viewKey = _viewsByKey[platformKey]; } else if (_viewsByKey.ContainsKey(genericKey)) { tupleKey = genericKey; viewKey = _viewsByKey[genericKey]; } if (viewKey != null) { var typeDefinition = viewKey; if (Proxy == null) { throw new Exception($"{nameof(INavigationProxy)} is null. Did you forget to call NavigationService.Init()?"); } if (_viewKeyTracking.Contains(tupleKey) && !newInstance) { // Silent pop those in the middle, then do a pop, so its a single back animation according to the user var index = 0; foreach (var item in _viewKeyTracking) { if (item.Key != key) { index += 1; } else { break; } } var count = _viewKeyTracking.Count; for (int i = count - 2; i > index; i--) { await Proxy.SilentPopAsync(1); _viewKeyTracking.RemoveAt(i); } // Now should be single pop to go back to the page. while (key != CurrentView.Key) { if (args == null) { await Proxy.PopAsync(); } else { await Proxy.PopAsync(args); } } } else { var view = await _viewService.Build(typeDefinition) as IView; if (view == null) { throw new Exception(String.Format("Unable to build view {0}", typeDefinition.Type.ToString())); } Proxy.SetNavigationBar(ShowNavigationBar, view); var model = view.BindingContext as IViewModel; if (model != null) { var arg = new Args(); await model.OnPreNavigate(args, arg); // If user cancelled, stop forward navigation if (arg.Cancel) { return; } view.Appearing += (s, e) => { model.OnAppearing(); }; view.Disappearing += (s, e) => { model.OnDisappearing(); }; view.OnBackButtonPressed = () => { return(model.OnBackButtonPressed()); }; } var popCurrent = false; if (Proxy != null && !string.IsNullOrEmpty(CurrentView.Key)) { if (_viewsByKey[CurrentView].NoHistory) { popCurrent = true; } } await Proxy.PushAsync(view); if (popCurrent || popSource) // Pop the one behind without showing it { await Proxy.SilentPopAsync(1); // Remove the top one as the new tracking key hasn't been added yet _viewKeyTracking.RemoveAt(_viewKeyTracking.Count - 1); } _viewKeyTracking.Add(tupleKey); CurrentView = tupleKey; CurrentViewTrack.Add(view); if (model != null) { model.OnNavigated(args).ConfigureAwait(false).GetAwaiter(); // Do not await. } } } else { throw new ArgumentException( $"No such key: {key}. Did you forget to call NavigationService.Map?", nameof(key)); } }); } }
public static void Init() { ThreadHelper.Init(SynchronizationContext.Current); }