Provides helper function for navigation.
示例#1
0
        /// <summary>
        /// Performs navigation against current ModernFrame.
        /// </summary>
        /// <param name="oldValue">Navigate From Uri</param>
        /// <param name="newValue">Navigate To Uri</param>
        /// <param name="navigationType">Type of Navigation</param>
        /// <param name="passingParameter">Parameter for passing.</param>
        /// <remarks>
        /// Can be used to fire Navigated events.
        /// </remarks>
        public void Navigate <TK>(Uri oldValue, Uri newValue, NavigationType navigationType, TK passingParameter)
        {
            Debug.WriteLine("Navigating from '{0}' to '{1}'", oldValue, newValue);

            // set IsLoadingContent state
            Frame.SetValue(ModernFrame.IsLoadingContentPropertyKey, true);

            // cancel previous load content task (if any)
            // note: no need for thread synchronization, this code always executes on the UI thread
            if (Frame.TokenSource != null)
            {
                Frame.TokenSource.Cancel();
                Frame.TokenSource = null;
            }

            // push previous source onto the history stack (only for new navigation types)
            if (oldValue != null && navigationType == NavigationType.New)
            {
                _history.Push(oldValue);
            }

            object newContent = null;

            if (newValue != null)
            {
                // content is cached on uri without fragment
                var newValueNoFragment = NavigationHelper.RemoveFragment(newValue);

                if (navigationType == NavigationType.Refresh || !this._contentCache.TryGetValue(newValueNoFragment, out newContent))
                {
                    var localTokenSource = new CancellationTokenSource();
                    Frame.TokenSource = localTokenSource;
                    // load the content (asynchronous!)
                    var scheduler = TaskScheduler.FromCurrentSynchronizationContext();

                    var task = Frame.ContentLoader.LoadContentAsync(newValue, Frame.TokenSource.Token);

                    task.ContinueWith(t => {
                        try
                        {
                            if (t.IsCanceled || localTokenSource.IsCancellationRequested)
                            {
                                Debug.WriteLine("Cancelled navigation to '{0}'", newValue);
                            }
                            else if (t.IsFaulted && t.Exception != null)
                            {
                                var failedArgs = new NavigationFailedEventArgs
                                {
                                    Frame   = Frame,
                                    Source  = newValue,
                                    Error   = t.Exception.InnerException,
                                    Handled = false
                                };

                                OnNavigationFailed(failedArgs);
                                // if not handled, show error as content
                                newContent = failedArgs.Handled ? null : failedArgs.Error;
                                SetContent(newValue, navigationType, newContent, true, passingParameter);
                            }
                            else
                            {
                                newContent = t.Result;

                                if (ShouldKeepContentAlive(newContent))
                                {
                                    // keep the new content in memory
                                    _contentCache[newValueNoFragment] = newContent;
                                }

                                SetContent(newValue, navigationType, newContent, false, passingParameter);
                            }
                        }
                        finally
                        {
                            // clear global tokenSource to avoid a Cancel on a disposed object
                            if (Frame.TokenSource == localTokenSource)
                            {
                                Frame.TokenSource = null;
                            }

                            // and dispose of the local tokensource
                            localTokenSource.Dispose();
                        }
                    }, scheduler);
                    return;
                }
            }

            // newValue is null or newContent was found in the cache
            SetContent(newValue, navigationType, newContent, false, passingParameter);
        }
示例#2
0
        /// <summary>
        /// Performs navigation to specified link.
        /// </summary>
        /// <param name="uri">The uri to navigate to.</param>
        /// <param name="source">The source element that triggers the navigation. Required for frame navigation.</param>
        /// <param name="parameter">An optional command parameter or navigation target.</param>
        public virtual void Navigate(Uri uri, FrameworkElement source = null, string parameter = null)
        {
            if (uri == null)
            {
                throw new ArgumentNullException(nameof(uri));
            }

            if (uri.OriginalString.StartsWith(@"www."))
            {
                uri = new Uri("http://" + uri.OriginalString);
            }

            var args = new NavigateEventArgs(uri);

            PreviewNavigate?.Invoke(this, args);
            if (args.Cancel)
            {
                return;
            }

            // first check if uri refers to a command
            if (Commands != null)
            {
                if (Commands.TryGetValue(uri, out var command))
                {
                    // note: not executed within BbCodeBlock context, Hyperlink instance has Command and CommandParameter set
                    if (command.CanExecute(parameter))
                    {
                        command.Execute(parameter);
                    }
                    return;
                }

                if (uri.IsAbsoluteUri)
                {
                    var original = uri.AbsoluteUri;
                    var index    = original.IndexOf('?');
                    if (index != -1)
                    {
                        var subUri = new Uri(original.Substring(0, index), UriKind.Absolute);
                        if (Commands.TryGetValue(subUri, out command))
                        {
                            parameter = uri.GetQueryParam("param");
                            if (command.CanExecute(parameter))
                            {
                                command.Execute(parameter);
                            }
                            return;
                        }
                    }
                }
            }

            if (uri.IsAbsoluteUri && ExternalSchemes != null && ExternalSchemes.Any(s => uri.Scheme.Equals(s, StringComparison.OrdinalIgnoreCase)))
            {
                // uri is external, load in default browser
                Process.Start(uri.AbsoluteUri);
            }
            else
            {
                // perform frame navigation
                if (source == null)     // source required
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, UiStrings.NavigationFailedSourceNotSpecified, uri));
                }

                // use optional parameter as navigation target to identify target frame (_self, _parent, _top or named target frame)
                var frame = NavigationHelper.FindFrame(parameter, source);
                if (frame == null)
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, UiStrings.NavigationFailedFrameNotFound, uri, parameter));
                }

                if (!(Window.GetWindow(frame) is INavigateUriHandler window) || frame.GetParent <ModernFrame>() != null || window.NavigateTo(uri) != true)
                {
                    // delegate navigation to the frame
                    frame.Source = uri;
                }
            }
        }