İster AJAX sitelerinde olsun ister Silverlight bir şekilde istemci tarafında
sayfanın manipüle edildiği web uygulamalarındaki dertlerden biri URL'in
değişmiyor olması ile beraber tarayıcı geçmişinin de çalışamaması. İlk bakışta
belki büyük bir sorun gibi gözükmese de müşterilerinize teslim ettiğiniz bu
gibi projelerin sonrasında aldığınız geri dönüşler emin olun sizi bu konuda
ciddi şekilde şaşırtabilir.
Navigation API ile sorunlara çözüm....
Silverlight uygulamaları içerisindeki Navigation konseptini çözmeyi
hedefleyen Navigation kontrolleri ve API aynı anda yukarıdak bahsettiğimiz
URL'in duruma göre değişebilmesi ve hatta istemci taraflı URLReWriting
yapılabilmesini de sağlıyor. Bu çerçevede yeni bir Silverlight projesi
yaratarak adım adım ilerleyelim.
İlk olarak uygulamanızda Navigation API kullanacaksanız hemen
System.Windows.Controls.Navigation assembly'sini referans olarak
almanız gerekiyor. Bu assembly içerisinde kullanacağımız sınıflar ve kontroller
bulunuyor. Navigation sistemine kendine has bir Frame ve
Page yapısına sahip. Uygulamanızda navigasyon uygulamak
istediğiniz ana bir sayfa belirledikten sonra bu sayfa içerisinde Frame
kontrolünü yerleştiriyorsunuz. Sonrasında bu Frame içerisine farklı Page
kontrollerini yükleyebilirsiniz. Aslında bu yapı bizim eski klasik HTML'den
alıştığımız IFRAME'e çok benziyor tek farkı özünde tamamen Silvelright
içerisinde bir yapı olması.
Yarattığımız yeni Silverlight uygulamasında gerekli DLL'leri referans
aldıktan sonra ana sayfa olarak varsayılan ayarlarla gelen
MainPage.xaml UserControl'ünü kullanacağız. Bu UserControl içerisine
bir Frame kontrolü yerleştirmemiz gerekiyor.
[XAML]
<UserControl x:Class="SilverlightApplication4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<navigation:Frame x:Name="BirFrame" Source="/AnaSayfa.xaml">
</navigation:Frame>
</Grid>
</UserControl>
System.Windows.Controls namespace'in eklenen kontrollerden biri olan Frame
kontrolü doğrudan System.Windows.Controls.Navigation assembly'si üzerinden
geliyor. Gerekli XML namespace'lerini de Usercontrol çapında tanımladıktan
sonra rahatlıkla söz konusu namespace üzerinden Frame kontrolünü
yaratabiliyoruz. Tabi bu Frame'in ilk açılışta göstereceği Page'in
adresini de Source olarak vermeniz gerekiyor.
Tüm bu hikaye içerisinde farkındaysanız bir UserControl bir Page
diye iki farklı şeyden bahsediyorum. UserControl'ler bizim normal şartlarda
kullandığımız hem ana sayfalarımız hem iç User Controllerimiz vs olabiliyor.
Silverlight içerisinde ana uygulama görseli de sonuç olacak bir UserControl.
Fakat söz konusu Navigation API olunca bir Frame içerisinde
ancak Page kontrollerini gösterebiliyorsunuz. Page
kontrollerinin özünde UserControl'lerden bir eksiği yok
fazlası var. O nedenle bir UserControl içerisinde yapabildiğiniz herşeyi Page
içerisinde yapabileceğinizi unutmayın.
Şimdi gelin bir de basit Page yaratıp adını
AnaSayfa.xaml yapalım ki yukarıdaki uygulamamız rahatlıkla çalışsın.
Projenizde "Add new item" dediğiniz "Silverlight Page" seçeneği ile
karşılaşacaksınız.
[XAML]
<navigation:Page x:Class="SilverlightApplication4.AnaSayfa"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
d:DesignWidth="640" d:DesignHeight="480"
Title="AnaSayfa Page">
<Grid x:Name="LayoutRoot">
</Grid>
</navigation:Page>
Gördüğünüz gibi Page kontrolleri de yine System.Windows.Controls.Navigation
altından geliyor. Bir Page kontrolünün Title özelliği uygulama tarayıcıda
açıkken tarayıcının işletim sistemine ait üst çubuğunda gözükecek olan içeriği
tanımlıyor. Böylece Frame içerisindeki Page'ler değiştikçe her
Page kendi Title bilgisini tarayıcının çubuğuna aktarabiliyor.
Sadece bu kadarla kalınmıyor aslında.
Hatırlarsanız ana sayfadaki Frame kontrolümüze Source olarak
AnaSayfa.xaml demiştik. Buradan yola çıkarak Frame kontrolü ilk
açıldığında Silverlight projeniz içerisinde AnaSayfa.xaml'ı yükleyecektir.
Sonrasında başka bir sayfaya yönlendirme yapmak isterseniz bunu ana
sayfanızdaki bir HyperlinkButton ile rahatlıkla
yapabilirsiniz.
[XAML]
<UserControl x:Class="SilverlightApplication4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<StackPanel>
<navigation:Frame Height="300" x:Name="BirFrame" Source="/AnaSayfa.xaml">
</navigation:Frame>
<HyperlinkButton x:Name="Link1" NavigateUri="/BaskaSayfa.xaml" TargetName="BirFrame" Content="TIKLA"/>
</StackPanel>
</Grid>
</UserControl>
Yukarıdaki örnekte gördüğünüz HyperlinkButton'un TargetName
özelliği çok önemli. Bu özelliğe aktarılan isim bizim Frame
kontrolünün ismi olduğu için kontrol içerisindeki linkin doğrudan Silverlight
içerisindeki Frame'e yönlendirileceği anlaşılabiliyor.
HyperlinkButton'ın NavigateUri özelliğinde ise Silvelright uygulaması
içerisindeki bir diğer Page kontrolünün adresi bulunuyor. Bu
adresler Silverlight uygulamasının rootuna göre veriliyor. Yukarıdaki
HyperlinkButton'a tıklandığıda otomatik olarak hedef Page Frame içerisinde
yüklenecektir.
Tüm bu işlemler gerçekleşirken Navigation API sizin yerinize tarayıcının
adres çubuğunda da gerekli değişiklikleri otomatik olarak yapacaktır.
Uygulama ilk açıldığında adresi:
http://localhost:2593/SilverlightApplication4TestPage.html#/AnaSayfa.xaml
HyperlinkButton'a tıkladıktan sonraki adres:
http://localhost:2593/SilverlightApplication4TestPage.html#/BaskaSayfa.xaml
Yukarıdaki adresler arasındaki farklarda da görebileceğiniz üzere Frame
içerisine yüklenen her kontrolün adresi tarayıcının da adres çubuğunda
bulunuyor. Bu adresler birer Fragment olarak implemente
edildiği için tarayıcı herhangi bir şekilde sayfaya refresh atmasa da bu
değişiklikleri tarayıcı geçmişine kaydedebilecektir. Böylece rahatlıkla
kullanıcılar tarayıcıların "İleri" ve "Geri" düğmeleri kullanarak uygulamamız
içerisinde gezebilecekler. Bu sistemin bir diğer avantajı da kullanıcıların
uygulamamızla ilgili farklı sayfaların linklerini alarak arkadaşlarına
gönderebilecek olmaları. Bu adresler eğer kopyalanıp farklı bir makineden
farklı bir tarayıcıda doğrudan çalıştırılırsa Navigation API uygun Page'i Frame
içerisine otomatik olarak yükleyecektir.
Page'lere parametre nasıl göndeririz?
Belki de Page'leri Frame içerisine yüklerken parametreler göndermek
isteyeceksiniz. Hatta belki de bir Page'in kendi içerisinde bulunduğu Frame'e
başka bir Page'i yüklemesini söyleyebilmesini isteyeceksiniz. Biraz karışık
oldu değil mi? Gelin tek tek bu soruları da cevaplayalım. İlk olarak ana
sayfadan değil de bir Page'in kendi içinden navigasyon sağlamanın yoluna
bakalım.
[VB]
Private Sub btntikla_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btntikla.Click
Me.NavigationService.Navigate(New Uri(String.Format("/Urun.xaml?ID={0}", 1), UriKind.Relative))
End Sub
Yukarıdaki kod doğrudan Frame içerisinde bir Page'in içindeki düğmeye bağlı.
Ana sayfada Frame'e ulaşarak "sen bu adresi aç" demek kolay fakat Frame
içerisinde bir Page'i kendi sahibi olan Frame'e böyle bir komut gönderebilmesi
için her Page içerisinde otomatik olarak yer alan NavigationService'i
kullanmamız gerekiyor. NavigationService üzerinden
çağırdığınız Navigate metoduna her zamanki gibi Silverlight
uygulamanız içerisindeki bir başka Page'in adresini verebilirsiniz.
Yukarıda yönlendirme yaptığımız adrese dikkat ettiyseniz sonunda bir
parametre var. Sanki normal bir web sitesinde yönlendirme yaparmış gibi
QueryString üzerinden parametre gönderebiliyoruz. Tabi söz konusu
Urun.Xaml adındaki Page'in de bu parametreyi okuyabilmesi gerekiyor.
[VB]
Partial Public Class Urun
Inherits Page
Public Sub New()
InitializeComponent()
End Sub
'Executes when the user navigates to this page.
Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
If Me.NavigationContext.QueryString.ContainsKey("ID") Then
GelenParametre.Text = Me.NavigationContext.QueryString("ID")
End If
End Sub
End Class
Urun.xaml adındaki Page'imizin için otomatik olarak gelen
OnNavigateTo metodu söz konusu Page ekrana geldiğinde çalışacaktır. Kontrol
ekrana geldiğinde hemen gidip kendisine QueryString üzerinden bir ID
gönderilip gönderilmediğini kontrol etmemiz gerek. Bunun için yine her Page'de
bulunan NavigationContext'i kullanıyoruz.
NavigationContext'in altındaki QueryString
nesnesinin ContainsKey özelliği ile ID parametresinin gelip
gelmediğini kontrol ettikten sonra QueryString Dictionary'sine doğrudan
elimizdeki key'i verip değeri alabiliyoruz. Böylece hazırladığınız bir Page'i
Frame içerisine yüklerken ona bir parametre gönderip onun da parametreye uygun
verileri göstermesini veya uygun işlemleri yapmasını sağlayabilirsiniz.
UriMapping işlemleri.
Şu ana kadar yaptığımız tüm işlemlerde verdiğimiz Frame adresleri otomatik
olarak adres çubuğuna yazıldı. Bu durumun birçok avantajı var. Fakat ortada hoş
olmayan bir konu var ki o da herşeyin alenen ve çirkin bir şekilde adres
çubuğunda gözüküyor olması. Örneğin aşağıdaki adres bizim Urun.xaml'a parametre
gönderdiğimize oluşan adres.
http://localhost:2593/SilverlightApplication4TestPage.html#/Urun.xaml?ID=1
Bu sorun tanıdık geliyor değil mi? Aslında biz bu sorunu yıllarda web
uygulamalarında da yaşadık ve UrlReWriting kullanarak daha hoş URL'lere sahip
olmayı öğrendik. İşte aynı sistemi Navigation API içerisinde de
UriMapper kontrolleri ile sağlayabiliyorsunuz.
[XAML]
<UserControl x:Class="SilverlightApplication4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<StackPanel>
<navigation:Frame Height="300" x:Name="BirFrame" Source="/AnaSayfa">
<navigation:Frame.UriMapper>
<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/AnaSayfa.xaml"/>
<uriMapper:UriMapping Uri="/{SayfaAdi}" MappedUri="/{SayfaAdi}.xaml"/>
</uriMapper:UriMapper>
</navigation:Frame.UriMapper>
</navigation:Frame>
<HyperlinkButton x:Name="Link1" NavigateUri="/BaskaSayfa"
TargetName="BirFrame" Content="TIKLA"/>
</StackPanel>
</Grid>
</UserControl>
uriMapper kontrolünü kullanabilmek için ayrı bir XAML namespace tanımlayarak
bu sefer de System.Windows.Controls.Navigation'ı import etmemiz gerekiyor.
Sonrasında uriMapper kontrolünü yaratarak doğrudan Frame'in
UriMapper özelliğine verebiliyoruz. UriMapper kendi içerisinde
UriMapping kontrolleri kullanıyor. Her uriMapping'in bir
Uri ve bir de MappedUri özelliği var.
[XAML]
<uriMapper:UriMapping Uri="" MappedUri="/AnaSayfa.xaml"/>
<uriMapper:UriMapping Uri="/{SayfaAdi}" MappedUri="/{SayfaAdi}.xaml"/>
Örneğimizdeki bu iki kodu incelersek ilkinde boş bir adres geldiğinde
açılarak kontrolün adresine yönlendirildiğini görebiliriz. İkincisinde ise bir
değişken kullanılmış durumda. SayfaAdi adını verdiğimiz bu
değişkeni gelen adresten alıp sonuna .xaml uzantısını ekleyip
yönlendiriyoruz. Böylece bir önceki adımdaki URL'lerimiz ile şu ankiler çok
daha farklı olabiliyor.
Uygulama ilk açıldığında adresi:
http://localhost:2593/SilverlightApplication4TestPage.html#/AnaSayfa
HyperlinkButton'a tıkladıktan sonraki adres:
http://localhost:2593/SilverlightApplication4TestPage.html#/BaskaSayfa
Eğer kodumuzda dikkat ettiyseniz artık HyperlinkButton'un
NavigateUri'sinde BaskaSayfa.xaml yazmıyor,
doğrudan sadece BaskaSayfa yazıyor. Artık sondaki .xaml
uzantıları Mapper tarafından halledilecek. Bu şekilde QueryString
parametrelerini de map edebilirsiniz.
[XAML]
<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/AnaSayfa.xaml"/>
<uriMapper:UriMapping Uri="/Urun/{ID}" MappedUri="/Urun.xaml?ID={ID}"/>
<uriMapper:UriMapping Uri="/{SayfaAdi}" MappedUri="/{SayfaAdi}.xaml"/>
</uriMapper:UriMapper>
Yukarıdaki ek Mapping sayesinde artık Urun/2 şeklinde gelen
adresler doğrudan Urun.xaml?ID=2 şekline dönüştürülecek.
UriMapping öncesi:
http://localhost:2593/SilverlightApplication4TestPage.html#/Urun.xaml?ID=2
UriMapping sonrası:
http://localhost:2593/SilverlightApplication4TestPage.html#/Urun/2
Gördüğünüz gibi Naviation API gerçekten kuvvetli bir altyapı sunuyor. Tüm bu
altyapının her noktasına ayrı ayrı müdahale edebiliyorsunuz. Mantık olarak çok
yabancı olmadığımız bir kullanım şekli olduğu da kesin.
Hepinize kolay gelsin.
Daron Yöndem