Posts Tagged Relative Links

Relative Hyperlinks mit Silverlight Navigation

Wenn Sie nicht bemerkt haben, passieren ich die Navigation Feature in Silverlight wie ziemlich viel (ich frage mich warum? :) ). In meinem anderen Stellen auf Navigation , ich verbrachte einige Zeit gewährt, zu erforschen, wie Sie die Anwendung navigieren können, um Seiten in Assemblys andere als die wichtigsten Montage und wie diese Baugruppen (Nachfrage kann auf-geladen, verwendet es einige Workarounds, aber es bringt uns, wo wir gehen wollen!).

Das ist alles schön und gut, aber es stellt ein ärgerliches Problem, dass die Wartbarkeit des Codes solche Auswirkungen. Insbesondere, zwingt sie jeden Hyperlink innerhalb der einzelnen externe Baugruppen zu wissen, wie man auf ihrer Versammlung vom Namen beziehen (dies ist vergleichbar mit dem Problem mit absoluten URLs in Hyperlinks auf Web-Seiten - diese Verbindungen werden fest an die Seite, für die sie erstellt wurden, gekoppelt und kann nicht in andere Projekte kopiert werden).

Technisch gesehen sind fast alle Uris von der Navigation Rahmenbedingungen heute relative URIs (es sei denn UriMappings verwendet werden, um absolute Einsen in relativen Drehung), aber sie sind anwendungs-bezogen und nie-Page relative. Dies bedeutet, dass wenn Sie eine Seite unter " / Views/Page1.xaml "und wollen zu einer anderen Seite unter" / Views/Page2.xaml "von innen Page1, müssen Sie den gesamten Pfad (" / Views/Page2.xaml ") nicht nur den relativen Pfad verweisen Link auf der anderen Seite (zB "Page2.xaml" oder "./Page2.xaml").

In diesem Beitrag werden wir auf einen Weg, um Page-relative Navigation innerhalb Ihrer Silverlight-Seiten ermöglichen aussehen. Der Ansatz wird verwende ich den Vorteil der INavigate Schnittstelle, die in Silverlight 3 aufgenommen wurde und die Kontrolle HyperlinkButton, dass diese Schnittstelle verwendet nehmen werde Navigation durchführen, wenn darauf geklickt.

Die INavigate Schnittstelle sieht wie folgt aus:

  öffentliche Schnittstelle INavigate 
  (
     / / Methoden 
      source); bool Navigate (Quelle Uri);
 ) 

Es ist eine einfache Schnittstelle mit einem einfachen Zweck: erlauben eine Komponente, einen Weg zu Navigation zu einem Uri Griff bieten. Gerade jetzt, die einzige Komponente in Silverlight gebaut, die tatsächlich nutzt es ist die HyperlinkButton Kontrolle. Wir verwenden diese Kontrolle oft in Navigation-fähigen Anwendungen, da sie uns zu einem bestimmten Frame-Steuerelement zu einer Seite von Uri Ziel navigieren kann. In der Silverlight-Anwendung-Projekt-Template-Navigation, wirst du sehen, wie diese XAML:

 : Frame x : Name =" ContentFrame " Style ="{ StaticResource ContentFrameStyle }" Source ="/Home" Navigated ="ContentFrame_Navigated" NavigationFailed ="ContentFrame_NavigationFailed"> </ navigation : Frame > <Navigation: Frame x: Name = "ContentFrame" style = "() StaticResource ContentFrameStyle" Source = "/ home" Navigated = "ContentFrame_Navigated" NavigationFailed = "ContentFrame_NavigationFailed"> </ Navigation: Frame> 

Und:

  x : Name ="Link2" Style ="{ StaticResource LinkStyle }" <HyperlinkButton x: Name = "Link2" style = "() StaticResource LinkStyle" 
                   TargetName ="ContentFrame " Content ="about"/> NavigateUri = "/ Über" TargetName = "ContentFrame" content = "über" /> 

Dies alles funktioniert, weil die Frame-Steuerelement implementiert INavigate. Mit anderen Worten, es gibt keine Magie gibt - Sie können es auch! Hier ist der Weg der HyperlinkButton funktioniert, wenn Sie versuchen, eine INavigate (Ziel ca. :) ):

  • Für jeden Elternteil FrameworkElement hinauf auf die visuelle Baum aus dem HyperlinkButton ...
    • Prüfen Sie, ob die FrameworkElement ist ein INavigate und dass ihr Name TargetName (ignoriert Treffer, wenn TargetName ist null oder leer)
      • Wenn ja, nennen INavigate.Navigate () auf dem FrameworkElement
      • Andernfalls rekursiv Suche nach einem INavigate das ist richtig in jedem von den Kindern der FrameworkElement benannt
    • Wenn keine ordnungsgemäß benannt INavigate gefunden wurde, in Bewegung bleiben die Visual Tree

In anderen Worten, die HyperlinkButton seinen Weg nach oben und unten die Visual Tree (technisch tut eine Vorbestellung Breitensuche von jedem Elternteil der HyperlinkButton, arbeitet sich die visuelle Suche Baum) für eine angemessene INavigate zu nennen.

Also, was hat das alles INavigate Zeug für mich?

Mit dieser technischen Details aus dem Weg, die Frage lautet: Wie können wir diese nutzen, um Page-relative Navigation ermöglichen? Nun, das ist der Grund eines Frame-Navigation funktioniert innerhalb Seiten heute, da die Frame-Steuerelement implementiert INavigate, und die HyperlinkButton arbeitet sich die visuelle Baum, bis er diese findet.

Für unsere Zwecke ist diese große, weil es bedeutet, können wir den Aufruf INavigate.Navigate abzufangen () durch Implementierung der Schnittstelle irgendwo zwischen den HyperlinkButton und der Rahmen. Es ist ein bequemer Platz für dieses, da Anwendungen, die Page / Frame und HyperlinkButtons verwenden innerhalb dieser Seiten haben eine visuelle Struktur wie folgt aus:

  • Anwendung
    • Layout
      • Rahmen
        • Seite
          • HyperlinkButton
          • Andere Steuerelemente
      • Andere Controls

Was ich vorschlage, ist, dass die Page wir INavigate umzusetzen und biegen Seite navigieren relative Uri's in anwendungsorientierte relative Uri's, bevor sie von der Übergabe NavigationService (oder Rahmen), tatsächlich führen die Navigation.

Ich habe vor gegangen und erweiterte meine DynamicNavigation Bibliothek zu machen DynamicPage umzusetzen INavigate zu tun, was wir wollen, aber Sie könnten das gleiche auf jede Unterklasse von Page (einschließlich jeder Ihrer Seiten, wenn Sie nicht wollen, eine gemeinsame Basisklasse zu tun) . Hier ist meine einfache Implementierung (mit einem Schalter zum Ausschalten dieser Funktion auf DynamicPages):

 { return ( bool )GetValue(RelativeLinksProperty); } set { SetValue(RelativeLinksProperty, value ); } } public static readonly DependencyProperty RelativeLinksProperty = DependencyProperty .Register( "RelativeLinks" , typeof ( bool ), typeof ( DynamicPage ), new PropertyMetadata ( true )); private static readonly Uri basePlaceHolderUri = new Uri ( "none:///" , UriKind .Absolute); #region INavigate Members public bool Navigate( Uri navigateUri) { string original = navigateUri.OriginalString; if (RelativeLinks && !navigateUri.IsAbsoluteUri && !original.StartsWith( "/" )) { Uri result; if (NavigationService.CurrentSource.IsAbsoluteUri) { result = new Uri (NavigationService.CurrentSource, navigateUri); } else { Uri baseUri = new Uri (basePlaceHolderUri, NavigationService.CurrentSource); result = new Uri ( "/" + basePlaceHolderUri.MakeRelativeUri( new Uri (baseUri, navigateUri)).OriginalString, UriKind .Relative); } return NavigationService.Navigate(result); } else { return NavigationService.Navigate(navigateUri); } } #endregion public bool RelativeLinks (get (return (bool) GetValue (RelativeLinksProperty);) set (SetValue (RelativeLinksProperty, value);)) public static readonly DependencyProperty RelativeLinksProperty = DependencyProperty. Register ("RelativeLinks", typeof (bool), typeof (DynamicPage) , neue PropertyMetadata (true)); private static readonly Uri basePlaceHolderUri = new Uri ("none :///", UriKind. Absolute); # region INavigate Mitglieder public bool Navigate (Uri navigateUri) (string = original navigateUri.OriginalString, wenn (RelativeLinks & &! navigateUri.IsAbsoluteUri & &! original.StartsWith ("/")) (Uri führen; if (NavigationService.CurrentSource.IsAbsoluteUri) (result = new Uri (NavigationService.CurrentSource, navigateUri);) else (baseURI = new Uri Uri (basePlaceHolderUri, NavigationService.CurrentSource); Ergebnis = new Uri ("/" + basePlaceHolderUri.MakeRelativeUri (neu Uri (baseURI, navigateUri)). OriginalString, UriKind. Relative);) return NavigationService.Navigate (result);) else ( Rückkehr NavigationService.Navigate (navigateUri);)) # endregion 

Nun, innerhalb der Seite, die Sie verwenden können Page-relative Uri's auf HyperlinkButtons. Alles, was Sie tun müssen, ist zu vermeiden Festlegung einer TargetName (entweder durch einen Stil oder direkt auf der HyperlinkButton), und die Seite wird die Navigation Griff!

Page-relative URI's können eine Vielzahl von Formen annehmen. Vorausgesetzt, die Page Sie sind momentan in ist "/ MyLibrary; component/Views/Main/Page1.xaml", die folgende Veränderungen stattfinden (als Beispiel):

  • "Page2.xaml" -> "/ MyLibrary; component/Views/Main/Page2.xaml"
  • "./Page2.xaml" -> "/ MyLibrary; component/Views/Main/Page2.xaml"
  • "../Page3.xaml" -> "/ MyLibrary; component/Views/Page3.xaml"
  • "../Secondary/Page3.xaml" -> "/ MyLibrary; component/Views/Secondary/Page3.xaml"
  • "../../ BasePage.xaml "->" / MyLibrary; Komponente / BasePage.xaml "
  • "SubMain/Page4.xaml" -> "/ MyLibrary; component/Views/Main/SubMain/Page4.xaml"
  • "SubMain/Page4.xaml? A = b & c = d" -> "/ MyLibrary; component/Views/Main/SubMain/Page4.xaml? A = b & c = d"
  • "/ MyLibrary; component/Views/Main/Page5.xaml" -> "/ MyLibrary; component/Views/Main/Page5.xaml" (keine Veränderung)

Cool! Kann ich sehen, sie in Aktion?

Natürlich! :) Wie immer, können Sie spielen, um mit einer laufenden Anwendung, tut dies hier:

Live sample of page-relative navigation

Klicken Sie auf den Link am Ende dieser Seite, um eine relative peform Navigation, die Sie mit auf eine Reise zwischen einer Reihe von Seiten sollten - all das navigieren relative Navigation.

Als Referenz hier ist die Datei-Struktur für die Beispielanwendung.

File structure of the sample application.

Also, was wollen Sie hinaus?

Nun, um es zusammenzufassen - in der Lage zu Seite-relative Navigation erhöht die Portabilität Ihrer Seiten zu tun. Es ist besonders nützlich, wenn Sie es in Verbindung mit UriMapping verwenden. Mit der Technik vor, die "relative-ness" bezieht sich auf den Benutzer- zugewandten Uri. Dies bedeutet, dass Sie UriMappings zu schaffen, um eine "virtuelle" Datei-Struktur zu erstellen, und alle Ihre relative Links sollten auch weiterhin zu arbeiten (und neuer möglich sein könnte!). Give it a shot und lassen Sie mich wissen, was Sie denken, ich bin zu experimentieren weiter mit Navigation, immer auf der Suche nach Dingen, die Erfahrung zu verbessern könnten bei der Arbeit mit ihm.

Schon längst ausgebacken! Gib mir die Ware!

Geduld! Sie haben nicht wirklich geglaubt, dass ich verlassen Sie hängen, hast du? Hier geht's:

Hör auf zu reden, um sich selbst!

Okay. :)

, , , ,

6 Kommentare