Example #1
0
 public static void Init(SynchronizationContext uiContext, IPlatformOptions options)
 {
     ThreadHelper.Init(uiContext);
     PlatformOptions = options;
 }
Example #2
0
 /// <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);
 }
Example #3
0
        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);
            }
        }
Example #4
0
        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));
            }
        }
Example #5
0
        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));
                    }
                });
            }
        }
Example #6
0
 public static void Init()
 {
     ThreadHelper.Init(SynchronizationContext.Current);
 }