Merhaba,
Geçen hafta C# MVP 'si Fatih Boy'un düzenlediği Enterprisecoding video kanalına konuk oldum. Windows Phone 7 üzerine gerçekleştirdiğimiz 11dk.'lık videoya aşağıdan ulaşabilirsiniz.
İyi seyirler.
Windows Phone Series,XAML, Silverlight, C# .NET ve SQL konularında bilgi paylaşımı..
Windows Phone etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Windows Phone etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
10 Nisan 2011
27 Şubat 2011
Windows Phone 7 de Sayfa Oryantasyonu ve Sayfa Navigasyonu
Merhaba, bu makalemizde şu ana kadar incelemiş olduğumuz windows phone konularından, biraz daha başlangıç seviyesi konulara geri dönerek atlamış olduğumuz ve oldukça önemli olan sayfa oryantasyonu ve sayfa navigasyonu konularını incelemeye çalışacağız.
Mobil cihaz ekranlarının doğası gereği küçük olması zaman içerisinde bu cihazların tercih edilmesinin önüne geçmemiş, tam tersine oryantasyon düzeyleri ve hareket kabiliyetleri zaman içerisinde daha da geliştirilerek çok daha fazla tercih edilir noktalara taşınmaya başlamıştır. Özellikle bu gelişimi Windows Phone 7 ile çok daha net hissetmeye başlayacağız.
Windows Phone 7 için geliştirilmiş veya geliştirilmesi planlanan uygulmaları düşünecek olursak tabiiki daha çok bilgilerin listelenmesi gibi bir işleve sahip olan, portrait (düşey) ekran kullanılmaktadır. Fakat yatay düzlemde çok daha iyi görüntülenecek bir veri için telefonumuzu landscape-left (yatayda-sola) veya landscape-right (yatayda-sağa) taraflarına doğru çevirmemiz uygulama içerisinde de dinamik bir şekilde değişim gösterecektir.
Aşağıdaki resimlerde Portrait, Landscape-Left, Landscape-Right sayfa oryantasyonlarını görmekteyiz. (Emulatör ile portrait-down elde edilememektedir.)
Windows Phone 7 için bir uygulama geliştirirken, kullanıcının uygulamamızdaki sayfayı hangi oryantasyton ile kullanacağını bilmek bizim için oldukça önemli olacaktır. Bir PhoneApplicationPage sınıfının Orientation özelliğini kullanarak sayfamızdaki oryantasyonu yakalamamız mümkün. Aşağıdaki kod satırlarını kullanarak phone uygulamamızdan oryantasyon değişimlerini kolaylıkla elde edebiliriz.
(İlk uygulamamızı geliştirmeye başlarken Visual Studio 2010 / File / New / Project / Silverlight For Windows Phone / Windows Phone Application Template ile projemizi ekleyebiliriz.)
Constractor içerisinde sayfamızın SupportedOrientations özelliğini set edip, OrientationChanged event'ı ekliyoruz. "oryantasyon" isimli değişkenimizi switch kod snippet kullanarak oluşturduğumuzda aşağıdaki gibi
enumarasyon değerlerinin case seçeneklerini oluşturduğunu göreceğiz.
C#
public partial class MainPage : PhoneApplicationPage { public MainPage() { InitializeComponent(); this.SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape; this.OrientationChanged += MainPage_OrientationChanged; } void MainPage_OrientationChanged(object sender, OrientationChangedEventArgs e) { var oryantasyon = this.Orientation; switch (oryantasyon) { case PageOrientation.Landscape: case PageOrientation.LandscapeLeft: case PageOrientation.LandscapeRight: MessageBox.Show("Landscape Orientation"); break; case PageOrientation.None: break; case PageOrientation.Portrait: case PageOrientation.PortraitDown: case PageOrientation.PortraitUp: MessageBox.Show("Portrait Orientation"); break; } } }
Eğer sayfamızda sabit bir oryantasyon kullanılmasının daha uygun olacağını düşünüyorsak, aşağıdaki gibi sayfamızın SupportedOrientations özelliğini xaml kodlarıyla da set etmemiz yeterli olacaktır ve SupportedOrientations özelliğini oryantasyon desteğinin olmasını istediğimiz her sayfa için belirlememiz gerekiyor.
Sayfamıza farklı oryantasyon destekleri verdikten sonra, sayfa üzerinde yer alacak nesnelerin de bu değişimlere göre konumlanması isteyeceğiz. Aksi durumda nesnelerimizin sayfanın dışına taşması, kullanıcının nesneyi görememesi gibi durumlarla karşılaşabiliriz. Aşağıdaki örneğimizde Layout kullanarak butonları yerleştireceğiz. 5 adet farklı button nesnemizin her birini ekranımızın farklı yerine koyarak Horizontal ve Vertical Layout özelliklerini belirleyelim.
XAML
<phone:PhoneApplicationPage ...
SupportedOrientations="PortraitOrLandscape">
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Button Name="btn1" Content="Sol Üst" Height="72" Width="170" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" /> <Button Name="btn2" Content="Sağ Üst" Height="72" Width="170" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="5" /> <Button Name="btn3" Content="Sol Alt" Height="72" Width="170" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5" /> <Button Name="btn4" Content="Sağ Alt" Height="72" Width="170" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5" /> <Button Name="btn5" Content="Merkez" Height="72" Width="170"/> </Grid>
F5 ile Emulatör üzerinden uygulamamızı çalıştırdığımızda aşağıdaki ekran görnüntülerini elde edeceğiz. (Oryantasyon değişimi için emulatörün sağ yan kısmında bulunan butonları kullanabiliriz.)
Yukarıdaki buttonlar için düzenlediğimiz yöntem ile oryantasyon değişimine karşı önlem almış olduk, fakat bu seferde üst ve alt button nesnelerinin birbirine yaklaştığını görüyoruz. Böylesi bir sayfa da ihtiyacımızı karşılamayacaksa sayfa için ScrollViewer tekniğini kullanabiliriz. ScrollViewer nesnesinin içerisine
ContentPanel isimli grid nesnemizi yerleştirelim. Bu yerleşim planının önemli bir noktası grid nesnesine vereceğimiz Height="800" özelliği olacak. ScrollViewer da kullanarak XAML kodlarımızı aşağıdaki gibi hazırlayalım.
XAML
<Grid x:Name="LayoutRoot" Background="Transparent"> <ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" > <Grid x:Name="ContentPanel" Height="800"> <Button Name="btn1" Content="Sol Üst" Height="72" Width="170" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" /> <Button Name="btn2" Content="Sağ Üst" Height="72" Width="170" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="5" /> <Button Name="btn3" Content="Sol Alt" Height="72" Width="170" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5" /> <Button Name="btn4" Content="Sağ Alt" Height="72" Width="170" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="5" /> <Button Name="btn5" Content="Merkez" Height="72" Width="170"/> </Grid> </ScrollViewer> </Grid>
XAML kodlarımızda yaptığımız düzenlemeden sonra tekrar F5 ile uygulamamızı çalıştırdığımızda aşağıdaki ekran görüntüleri ile karşılaşacağız. Dikkat edecek olursak ScrollViewer nesnemizin VerticalScrollBarVisibility özelliğini Auto olarak ayarlıyoruz. Bu kullanım yöntemi ile de oryantasyon değişiminde dikey düzlemde sayfa üzerinde parmakla kaydırarak kullanarak, ekran üzerindeki nesnelerimi kaybetmeden ve sıkışık bir görüntü oluşturmadan kullanabiliriz.
ContentPanel isimli Grid nesnesinin Height özelliği 800 olarak belirlendiği için Landscape konumdayken sayfa üzerinde aşağıya ve yukarıya doğru gezinebilme olanağı yakalamış oluyoruz.Sayfa oryantasyonları ile ilgili önemli noktaları belirledikten sonra, şimdi de sayfalar arasındaki geçişleri incelemeye başlayalım;
Sayfa Navigasyonu
Şimdiye kadar örneklerimizi tek bir sayfa üzerinden gerçekleştirdik. Uygulamamız içerisinde tabiki bir den fazla sayfaya ihtiyaç duyabiliriz. Daha önceki bir makalemizde de Panorama ve Pivot Control' e değinmiştik (Windows Phone'da Panorama ve Pivot Control : http://www.yazgelistir.com/Makaleler/1000002595.ygpx) Panorama veya Pivot control kullanımı ile hızlı görüntü geçişleri elde etmiştik. Farklı sayfalara da kolaylıkla erişebiliriz.
Yukarıdaki, köşelere eklediğimiz buton nesneli örneğimizi silmeden projemize SecondPage.xaml isimli bir sayfa daha ekleyelim. Bu butonların Click event'ı üzerinden farklı navigasyon yöntemleriyle ikinci sayfayı
görüntülemeye çalışacağız.
C# (MainPage)
private void btn1_Click(object sender, RoutedEventArgs e){ var frame = Application.Current.RootVisual as PhoneApplicationFrame; frame.Source = new Uri("/SecondPage.xaml",UriKind.Relative); } private void btn2_Click(object sender, RoutedEventArgs e){ var frame = Application.Current.RootVisual as PhoneApplicationFrame; frame.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative)); } private void btn3_Click(object sender, RoutedEventArgs e){ this.NavigationService.Navigate(new Uri("/SecondPage.xaml", UriKind.Relative)); }
Peki bu ana sayfadan ayrılmadan önce kullanıcının eksik bırakmış olduğu bir takım verilerin olduğunu varsayarsak, bu durumda kullanıcıdan onay alarak diğer sayfaya geçiş yapabiliriz.
C# (MainPage)
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e) { if (MessageBox.Show("Sayfadan ayrılmak istiyor musunuz?", "Onay", MessageBoxButton.OKCancel) != MessageBoxResult.OK) { e.Cancel = true; } base.OnNavigatingFrom(e); }
C# (App)
public App() { UnhandledException += Application_UnhandledException; if (System.Diagnostics.Debugger.IsAttached) { Application.Current.Host.Settings.EnableFrameRateCounter = true; } InitializeComponent(); InitializePhoneApplication(); RootFrame.Navigating += App_Navigating; } void App_Navigating(object sender, NavigatingCancelEventArgs e){ Debug.WriteLine("Navigating to " + e.Uri); }
Sayfalar arasında veri transfer edebilmek için de 2 farklı yöntemi ele alacağız. Bunlardan ilki FragmentNavigation. Bir sayfadan diğerini navigate ederken # işareti ile aşağıdaki kod satırlarında olduğu gibi veriyi de eklemek. btn1 isimli buton nesnemizin Click event'ını değiştirerek aşağıdaki gibi yazalım. MainPage'den SecondPage'e "Merhaba Dünya :)" verisini gönderelim.
C# (MainPage)
private void btn1_Click(object sender, RoutedEventArgs e){ this.NavigationService.Navigate(new Uri("/SecondPage.xaml#Merhaba Dünya :)", UriKind.Relative)); }C# (SeconPage)
public partial class SecondPage : PhoneApplicationPage { public SecondPage() { InitializeComponent(); } protected override void OnFragmentNavigation(FragmentNavigationEventArgs e) { base.OnFragmentNavigation(e); MessageBox.Show("Fragment : " + e.Fragment); } }F5 ile uygulamamızı başlatalım. Bir taraftan Output penceresinden de navigate ettiğimiz bilgileri de göreceğiz.
Sayfalar arasın veri transferindeki ikinci yöntemimiz ise QueryString yöntemi. Bu yöntemde de navigate ettiğimiz sayfanın sonuna ? ekleyerek değerlerimizi & işaretcisi ile ayırarak yazmak. Aşağıdaki örnekte MainPage'den SecondPage sayfasına MusteriID ve UrunKodu değerlerini göndereceğiz.
C# (MainPage)
private void btn1_Click(object sender, RoutedEventArgs e){ this.NavigationService.Navigate( new Uri("/SecondPage.xaml?MusteriID=15 & UrunKodu=77",UriKind.Relative)); }C# (SecondPage)
protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); StringBuilder sb = new StringBuilder(); foreach (var item in NavigationContext.QueryString) { sb.AppendLine("Query String Key: " + item.Key + " Value: " + item.Value); } MessageBox.Show(sb.ToString()); }Tekrar F5 ile emulatör üzerinden sayfa navigasyonumuzu QueryString olarak NavigationContent nesnesi içerisinden çekerek makalemizi sonlandıralım.
Bu makalemizde sayfa yapıları, sayfalar arası geçişler/navigasyon konularına değindik. Dilerim faydalı bir yazı olmuştur.
Bir sonraki makalemizde görüşmek üzere...
Kolay gelsin.
gokhanmanduz.blogspot.com
23 Ocak 2011
Windows Phone 7 Media Element
Windows Phone, ses ve görüntü dosyalarını oynatabilmek için de oldukça başarılı bir ortam sunmaktadır. Kullanımı kolay ve gelişmiş Silverlight mediaelement nesnesi ile phone uygulamalarımıza güçlü media özellikleri kazandırabiliriz. Bu makalemizde yeni bir Windows Phone 7 uygulaması oluşturarak, örneklerle mediaelement komponentini inceleyeceğiz.
Mediaelement komponenti ile, oynatacağımız .mp3 veya .wav uzantılı dosyaları projemize ekleyerek, ya da uzak bir sunucuda yayınlanan bir media kaynağına erişim sağlayarak da bu dosyaları oynatabiliriz. Uzak sunucuda yer alan media dosyasının Uri adresini mediaelement' in Source Property 'sine bağlamamız bunun için yeterli olacaktır. Eğer uzak sunucudaki bir dosyaya erişmek yerine bu dosyaları projemize eklemek istiyorsak, bu dosyaların BuildAction özelliğinin "Content" ve CopyToOutput özelliğinin de "Copy Always"
olmasına dikkat edelim.
Dikkat edilmesi gereken önemli bir nokta da windows phone için hangi codec bileşenlerinin desteklendiğidir. Örneğimize başlamadan önce, desteklenen windows phone media codec listesini buradan (Supported
Media Codecs for Windows Phone) inceleyebilirsiniz.
Projemize content olarak ekleyeceğimiz bir mp3 dosyasını oynatarak örneğimize başlayalım. Tabii her zamanki gibi ilk iş olarak Visual Studio / File / New / Project / Visual C# / Silverlight For Windows Phone template'i seçip, yeni bir Windows Phone projesi oluşturalım. Toolbox penceresinden mediaelement ' i tutup sürükleyerek default olarak oluşturulmuş olan MainPage.xaml sayfamızın üzerine bırakalım.
Bilgisayarımda hazır bulunan örnek müziklerimden Sleep Away.mp3 dosyasını da projeme content olarak ekliyorum. Copy To Output Directory özelliğini Always True olarak seçiyorum. AutoPlay="True" olarak
seçip, ilk açılışta otomatik olarak mp3 dosyasının çalınmasını sağlayacağım.
XAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="2,0,2,0"> <MediaElement x:Name="myMediaElement" Margin="10" Source="/Sleep Away.mp3" AutoPlay="True"/> </Grid>
Benzer bir şekilde, yukarıdaki mediaelement nesnesinin Source özelliğine uzak bir sunucuda yer alan dosyanın Uri adresini set edeceğim. Test amacıyla uzak sunucu olarak kendi bilgisayarımda bulunan iis dizini altına
(inetpub/wwwroot) mymuzik isminde bir klasör oluşturup Kalimba.mp3 isimli dosyamı buraya kopyalıyorum. Bu yöntem ile media dosyalarının direk olarak IIS' den yayınlanması tabiki doğru bir çözüm değildir. Sağlıklı bir çözüm için Windows Media Services veya IIS Smooth Streaming yöntemleri kullanılabilir. Eğer
Windows Media Sevis'i kurmak istiyorsak, http://daron.yondem.com/tr/PermaLink.aspx?guid=c44b96e8-e240-4ede-8c1f-7bdc000da97f linkinde yer alan makaleyi de inceleyebilirsiniz. (Ayrıca iis smoot streaming incelemek isteyenler http://www.iis.net/download/SmoothStreaming adresini ziyaret edebilirler.) Bu makalemizin konusu media dosyalarının yayınlanması olmadığı için kaldığımız yerden devam edelim.
XAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="2,0,2,0"> <MediaElement x:Name="myMediaElement" Margin="10" Source="http://localhost/mymuzik/Kalimba.mp3" AutoPlay="True"/> </Grid>
MediaElement nesnesinin Source özelliğini direk olarak set ettiğimiz için ilgili media dosyasının yüklenmesi belirli bir zaman alabilir. Ya da oynatacağımız dosya içinde oluşmuş bozulmalardan kaynaklı yavaşlamaları
engellemek için de öncelikle dosyayı telefonumuzun isolated storage alanına indirerek oynatmayı da deneyebiliriz. (Windows Phone Isolated Storage konusunuda ayrıca bir makalede inceleyebiliriz.) Isolated Storage alanı, adından da anlaşılacağı üzere uygulamamız tarafından kullanabileceğimiz, diğer uygulamalardan yalıtılmış bir yazma ve yazdıklarımızı okuma alnıdır. Uygulamamız için özel olarak tahsis edilmiş bir bellek alanıdır. Şimdi WebClient nesnesi ile uzak sunucumuzdaki Kalimba.mp3 dosyamıza okuma çağrısında bulunalım ve sonucu asenkron olarak elde edelim. Elde edeceğimiz result değeri Stream tipinde olacaktır. Gelen stream değerini bir döngü içerisinde öncelikle isolated storage alanına yazdıktan sonra mediaelement'
imizin SetSource özelliğini kullanarak oynatalım.
XAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="2,0,2,0"> <MediaElement x:Name="myMediaElement" Margin="10" /> </Grid>
C#public MainPage() { InitializeComponent(); Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { WebClient web = new WebClient(); web.OpenReadCompleted += web_OpenReadCompleted; Uri myAddress = new Uri("http://localhost/mymuzik/Kalimba.mp3"); web.OpenReadAsync(myAddress); } void web_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { if (e.Error == null) { using (var s = e.Result) { using (var isolatedFile = new IsolatedStorageFileStream("Kalimba.mp3", FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication())) { int i; var buffer = new byte[10000]; while ((i = s.Read(buffer, 0, buffer.Length)) > 0) { isolatedFile.Write(buffer, 0, i); } isolatedFile.Seek(0, SeekOrigin.Begin); this.myMediaElement.SetSource(isolatedFile); } } } }
Şimdi de yukarıdaki örneğimizden farklı olarak, uzak bir sunucu da bulunan örnek bir videoyu oynatarak medielement nesnemizin özelliklerini tanımaya çalışalım. Xaml kodlarımızı aşağıdaki gibi hazırlayalım.
MediaElement'in Source'una Uri adresini C# kodu ile set edeceğiz.
XAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <MediaElement Height="423" Width="438" Margin="5" Name="myMediaElement" VerticalAlignment="Top" AutoPlay="True"/> <TextBlock Height="34" HorizontalAlignment="Left" Margin="12,476,0,0" Name="txtState" Text="" VerticalAlignment="Top" Width="152" FontSize="24" /> <TextBlock Height="34" HorizontalAlignment="Left" Margin="175,476,0,0" Name="txtPercentage" Text="" VerticalAlignment="Top" Width="90" FontSize="24" /> </Grid> </Grid>
Videomuz otomatik olarak öncelikle telefonumuzun belleğine alınacaktır. Playing (Oynatma) başlamadan önce, buffering (arabelleğe alma) için gereken süreyi de dilersek belirtebiliriz. Bunun için mediaelement' in BufferingTime özelliğine TimeStamp türünde değer atanabilir.
Şimdi C# ile uzuk sunucudaki video ile bağlantı kurarak, media element nesnemizde oluşacak state'leri (opening, buffering, playing), buffering olan miktarı ekranımıza yazdıralım.
C#
public MainPage() { InitializeComponent(); Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { myMediaElement.CurrentStateChanged += myMediaElement_CurrentStateChanged; myMediaElement.BufferingProgressChanged += myMediaElement_BufferingProgressChanged; myMediaElement.Source = new Uri("http://mschannel9.vo.msecnd.net/o9/mix/09/wmv/key01.wmv"); } void myMediaElement_BufferingProgressChanged(object sender, RoutedEventArgs e) { double percent = myMediaElement.BufferingProgress; string str = percent == 1d ? "Ok." : string.Format("{0:P}", percent); txtPercentage.Text = str; } void myMediaElement_CurrentStateChanged(object sender, RoutedEventArgs e) { txtState.Text = myMediaElement.CurrentState.ToString(); }
F5 ile emulatör üzerinden uygulamamızı başlatalım, txtState TextBlock üzerinde o an ki durumu, txtPercentage TextBlock üzerinde ise yüzde olarak ne kadarlık buffer miktarının tamamlandığını göreceğiz.
Buffering tamamlandıktan sonra video'nun oynamaya başladığını ve txtState TextBlock nesnesine "Playing", txtPercentage üzerine ise "Ok." yazılacağını göreceğiz. Media Element komponentimizin genel olarak ne tür de özelliklere ve methodlara sahip olduğunu bir tablo üzerinden inceleyerek makalemizi sonlandıralım.
Property (Özellik) | Açıklama |
Source | Oynatılacak media dosyasının Uri adresidir. |
Volume | Oynayan dosyanın ses düzeyini belirlemek için kullanılır. Default olarak 0.5'dir (Orta seviye). |
Position | TimeStamp türü ile oynayan media dosyasının zaman çizelgesinde, hangi pozisyonda olduğu bilgisidir. Dilersek Position değerini set ederek, istediğimiz pozisyondan başlatabiliriz. |
NaturalDuration | TimeSpan türünde oynayan dosyanın ne kadar uzunlukta olduğunu belirtir. |
IsMuted | İstenirse oynayan dosya sessiz duruma getirilebilir. O an ki ses durumu da (kapalı/açık) elde edilebilir. |
DownloadProgress | Yüzdelik olarak ne kadar download edildiği bilgisini tutar. |
CanPause | Oynayan media'nın pause olup, olamayacağı bilgisini verir. ReadOnly'dir. |
CanSeek | Position değerine müdahale edilip edilemeyeceği bilgisini döner. |
Methods | |
Pause | Eğer CanPause property true ise Pause methodu ile media durdurulur. Pause durumunda oynayan son film karesi görüntülenecektir. |
Play | Media dosyasını oynatır. Eğer durum stop veya pause ise tekrar oynamaya başlayacaktır. |
Stop | Oynayan media dosyası durdurulacaktır. Bu durumda ilk film karesi ekranda gösterilecektir. |
SetSource | Stream bir değeri parametre olarak set edebiliriz. Yukarıdaki örneğimizde de yaptığımız gibi Isolated Storage alanına depolanmış bir media' yı oynatmak için oldukça kullanışlıdır. |
Bir sonraki makalemizde görüşmek üzere.
Kolay gelsin.
19 Aralık 2010
Windows Phone 7 Push Notification Types
Bu makalemizde Windows Phone 7 işletim sistemli telefonlarda kullanılan Push Notification (Türkçede 'bildirim itme' ya da 'dürtme' anlamında) konusunu 3 farklı bildirim tipi (notification types) ile ele alacağız.
Bu bildirim tiplerini sırasıyla;
1. Tile Notification
2. Toast Notification
3. Raw Notification
olarak 3 farklı gruba ayırarak inceleyelim. Öncelikle, kısaca ve ekran görüntüleri ile bu bildirim tiplerinin ne olduğunu anlamaya çalışalım.
1. Tile Notification
Windows Phone 7 açılış ekranında gösterimi yapılacak olan bildirim tipidir. Görsel olarak dikkat çekici konumdadır ve uygulamaları çalıştırdığımız ana ekranda yer alacaktır. Windows Phone 7 içerisinde her uygulama için ana ekranda bir 'Tile' (giriş ekranında yer alan ve application quick launchers olarak adlandırılan ekran ) bulunabilir.
Bir Tile Backgraund Image, Count ve Title'dan oluşur. Backgraund Image: Arka plan resmi için local veya bir uzak sunucuda bulunan imaj dosyası kullanılabilir. Tabiiki burada daha fazla performans istiyorsak local dosyada olması tercih nedeni olacaktır. Count: Integer sayıdır. Bildirim sayısını göstermek için kullanacağız. Title: Alt kısımda yer alan ve yalnızca bir satırlık string bilgi gösterilebilecek alandır. Bu sebepten dolayı tile genişliğini aşmayacak uzunlukta string bildirimler gönderilmesi gerekecektir.
2. Toast Notification (Tost :)
Bir bildirim geldiğinde ekranın üst kısmında belirecektir. Aşağıdaki resimde de görüleceği gibi turuncu arka plan renginde bir title ve bir de sub-title'dan oluşur. Title bold font, sub-title ise normal font olacaktır.
3. Raw Notification
Eğer yukarıda belirttiğimiz Tile ve Toast bildirimde bulunmak yerine direk olarak uygulamıza bildirimde bulunmak istiyorsak raw notification kullanacağız. Eğer gönderim sırasında uygulamamız kapalı ise Microsoft Push Notification servisinde bu bildirim iptal edilecektir ve cihaza iletilmeyecektir.
( Önemli Not : Tüm bu bildirimlerle ilgili UI tasarlamadan önce Microsoft' un belirttiği UI Guidelines'ı bir sıkıntı yaşamamak için (Phone Marketplace için) incelemekte fayda var. İlgili Guidelines'ı buradan indirebilirsiniz. )
Bildirim türlerinden kısaca bahsettikten sonra şimdi de bir örnek ile notification türlerini daha yakından
incelemeye çalışalım. Örneğimiz için 2 farklı proje oluşturacağız. Öncelikle bir WPF projesi ile Notification Sender tarafını daha sonrada Windows Phone projesi ile bildirimlerin cihaza nasıl ulaştığını ve cihazda nasıl gösterildiğinden bahsedeceğiz.
Notification Sender Side (WPF Application)
Visual Studio 2010 / File / New / Project / Visual C# / Windows / WPF Application seçeneği ile yeni bir proje oluşturarak notification göndereceğimiz tarafı oluşturmaya başlayalım. MainWindows ekranımızı aşağıdaki gibi oluşturalım.
MainWindows XAML
<Window x:Class="SenderApplication.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Sender Application" Height="433" Width="563"> <Grid> <Border BorderBrush="#FF8AC0C0" BorderThickness="1" Height="43" HorizontalAlignment="Left" Margin="13,10,0,0" Name="border1" VerticalAlignment="Top" Width="507"> <TextBlock Height="21" Name="textBlock1" Text="Windows Phone 7 URI" Width="133" HorizontalAlignment="Left" Margin="5" /> </Border> <TextBox Height="23" HorizontalAlignment="Left" Margin="152,21,0,0" Name="txtUri" VerticalAlignment="Top" Width="357" /> <GroupBox Header="Tile Notification" Height="100" HorizontalAlignment="Left" Margin="13,59,0,0" Name="groupBox1" VerticalAlignment="Top" Width="513"> <Grid> <TextBox Height="23" HorizontalAlignment="Left" Margin="133,6,0,0" Name="txtTileTitle" VerticalAlignment="Top" Width="142" /> <TextBlock Height="21" HorizontalAlignment="Left" Margin="10,8,0,48" Name="txt" Text="Title" Width="91" /> <TextBox Height="23" HorizontalAlignment="Left" Margin="133,35,0,0" Name="txtTileBackgraundimage" VerticalAlignment="Top" Width="252" /> <TextBlock Height="21" HorizontalAlignment="Left" Margin="10,35,0,21" Name="textBlock3" Text="Basckbraund Image" Width="109" /> <TextBox Height="23" HorizontalAlignment="Left" Margin="331,5,0,0" Name="txtCount" VerticalAlignment="Top" Width="54" /> <TextBlock Height="21" HorizontalAlignment="Left" Margin="281,7,0,49" Name="textBlock4" Text="Count" Width="44" /> <Button Content="Gönder" Height="23" HorizontalAlignment="Left" Margin="415,48,0,0" Name="btnSendTile" VerticalAlignment="Top" Width="75" Click="btnSendTile_Click" /> </Grid> </GroupBox> <GroupBox Header="Toast Notification" Height="100" HorizontalAlignment="Left" Margin="13,165,0,0" Name="groupBox2" VerticalAlignment="Top" Width="513"> <Grid> <TextBox Height="23" HorizontalAlignment="Left" Margin="133,10,0,0" Name="txtToastValue1" VerticalAlignment="Top" Width="252" /> <TextBlock Height="21" HorizontalAlignment="Left" Margin="10,10,0,46" Name="textBlock2" Text="String Value" Width="124" /> <TextBox Height="23" HorizontalAlignment="Left" Margin="133,39,0,0" Name="txtToastValue2" VerticalAlignment="Top" Width="252" /> <TextBlock Height="21" HorizontalAlignment="Left" Margin="10,39,0,17" Name="textBlock5" Text="Sub-String Value" Width="124" /> <Button Content="Gönder" Height="23" HorizontalAlignment="Left" Margin="415,48,0,0" Name="btnSendToast" VerticalAlignment="Top" Width="75" Click="btnSendToast_Click" /> </Grid> </GroupBox> <GroupBox Header="Raw Notification" Height="100" HorizontalAlignment="Left" Margin="13,271,0,0" Name="groupBox3" VerticalAlignment="Top" Width="513"> <Grid> <TextBox Height="23" HorizontalAlignment="Left" Margin="133,10,0,0" Name="txtRawValue" VerticalAlignment="Top" Width="252" /> <TextBlock Height="21" HorizontalAlignment="Left" Margin="10,10,0,46" Name="textBlock6" Text="String Value" Width="124" /> <Button Content="Gönder" Height="23" HorizontalAlignment="Left" Margin="415,48,0,0" Name="btnSendRaw" VerticalAlignment="Top" Width="75" Click="btnSendRaw_Click" /> </Grid> </GroupBox> </Grid> </Window>
UI hazırladıktan sonra Tile, Toast ve Raw buttonların click eventları altına ilgi notification gönderim kodlarını ekleyelim. Tile notification özelliklerine uygun olacak şekilde bir title, count ve arkaplanda çıkacak imaj adresini parametre olarak olan methodumuzu hazırlayalım. Imaj olarak ApplicationIcon.png dosyasını kullanabiliriz. "ApplicationIcon.png" dışında client windows phone uygulamamız tarafına content olarak eklenmiş farklı bir imaj dosyası da kullanabilirdik. (Windows Phone projesine eklenecek imaj dosyasının build action özelliğinin content olmasına dikkat edelim.)
Tile Notification Sender Method ve Button Click Event;
private void sendTile(Uri phoneUri, string title, int count, string backgroundImage) { string xmlMsg = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Tile>" + "<wp:BackgroundImage>" + backgroundImage + "</wp:BackgroundImage>" + "<wp:Count>" + count.ToString() + "</wp:Count>" + "<wp:Title>" + title + "</wp:Title>" + "</wp:Tile>" + "</wp:Notification>"; byte[] data = new UTF8Encoding().GetBytes(xmlMsg); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(phoneUri); request.Method = WebRequestMethods.Http.Post; request.ContentLength = data.Length; request.Headers["X-MessageID"] = Guid.NewGuid().ToString(); request.Headers["X-WindowsPhone-Target"] = "token"; request.ContentType = "text/xml"; request.Headers["X-NotificationClass"] = "1"; Stream requestStream = request.GetRequestStream(); requestStream.Write(data, 0, data.Length); requestStream.Close(); HttpWebResponse response = request.GetResponse() as HttpWebResponse; }
private void btnSendTile_Click(object sender, RoutedEventArgs e) { int count = Convert.ToInt32(txtCount.Text); sendTile(new Uri(txtUri.Text), txtTileTitle.Text, count ,txtTileBackgraundimage.Text); count++; txtCount.Text = count.ToString(); }
Yukarıdaki sendTile methoduna parametre olarak vereceğimiz phoneUri değerinin de önceden WindowsPhone tarafından verilmiş olması gerekiyor. uri adresinin nasıl elde edileceğini Windows Phone Application tarafında göreceğiz. Şimdi de Toast notification gönderecek olan methodumuzu ve click event'ımızı ekleyelim.
private void sendToast(Uri phoneUri, string str, string subStr) { string msg = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Toast>" + "<wp:Text1>" + str + "</wp:Text1>" + "<wp:Text2>" + subStr + "</wp:Text2>" + "</wp:Toast>" + "</wp:Notification>"; byte[] data = new UTF8Encoding().GetBytes(msg); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(phoneUri); request.Method = WebRequestMethods.Http.Post; request.ContentLength = data.Length; request.Headers["X-MessageID"] = Guid.NewGuid().ToString(); request.Headers["X-WindowsPhone-Target"] = "toast"; request.ContentType = "text/xml"; request.Headers["X-NotificationClass"] = "2"; Stream requestStream = request.GetRequestStream(); requestStream.Write(data, 0, data.Length); requestStream.Close(); HttpWebResponse response = request.GetResponse() as HttpWebResponse; }
private void btnSendToast_Click(object sender, RoutedEventArgs e) { sendToast(new Uri(txtUri.Text), txtToastValue1.Text, txtToastValue2.Text); }
Yukarıdaki kod satırlarında görüleceği gibi Toast gönderime uygun olacak şekilde sendToast parametre değerine bir string ve sub-string değer gönderiyoruz. Tile gönderimde olduğu gibi burada da uri adresini windows phone tarafında elde ediyor olacağız.
HttpWebResponse dönen kod satırında ise eğer dilerseniz gönderim sonrası durum bilgilerini ekrana yazdırabilirsiniz. Örneğin response.Header["X-DeviceConnectionStatus"] ile cihaz bağlantı durum bilgisi elde edilebilir. Raw Notification gönderimi için de aşağıdaki kod satırlarını ekleyelim;
private void sendRaw(Uri phoneUri, string str) { MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8); writer.Write(str); byte[] data = stream.ToArray(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(phoneUri); request.Method = WebRequestMethods.Http.Post; request.ContentLength = data.Length; request.Headers["X-MessageID"] = Guid.NewGuid().ToString(); request.Headers["X-NotificationClass"] = "3"; Stream requestStream = request.GetRequestStream(); requestStream.Write(data, 0, data.Length); requestStream.Close(); }
private void btnSendRaw_Click(object sender, RoutedEventArgs e) { sendRaw(new Uri(txtUri.Text), txtRawValue.Text); }
Raw notification gönderiminde de benzer şekilde string değerimiz ile windows phone kanal adresimizi parametre olarak gönderiyoruz. Şimdi de Windows Phone tarafında yeni bir bağlantı kanalı oluşturarak sender
uygulamıza verelim. Hemen ardından bildirimlerin nasıl gözükeceğine göz atalım.
Windows Phone Application Side
Öncelikle private kanal değişkenimizi, kanala vereceğimiz adı ve constractorümüz içerisinde Loaded event ekleyerek başlayalım. HttpNotificationChannel using Microsoft.Phone.Notification namespace altında bulunmaktadır. bu namespace default olarak projemize eklenen Microsoft.Phone.dll altında bulunmaktadır.
private HttpNotificationChannel httpChannel;
const string channelName = "MyPushChannel";
const string serviceName = "MyPushServis";
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
MainPage Loaded event handler altında çalışacak kod satırlarımızı ekleyelim. Tanımladığımız isimle yeni bir notification kanalı oluşturulmasını sağlayalım. Eğer bu isimde bir kanal tanımlı ise hazır durumda olan kanalımızı debug modda iken output penceremize yazdıracağız(Debug.WriteLine ile). Bu event handler içerisinde, yeni bir kanal oluşturma ve mevcut kanalın kontrol edilmesi Microsoft Push Notification Servisi tarafından
verilmektedir. Bu servisin nasıl çalıştığı konusunda bilgi almak isteyenler buradan ulaşabilirler.
private void MainPage_Loaded(object sender, RoutedEventArgs e) { httpChannel = HttpNotificationChannel.Find(channelName); if (null == httpChannel) { Debug.WriteLine("Yeni kanal oluşturuldu."); httpChannel = new HttpNotificationChannel(channelName, serviceName); httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(httpChannel_ChannelUriUpdated); httpChannel.Open(); } else { Debug.WriteLine("Var olan kanal : " + httpChannel.ChannelUri.ToString()); } // Raw event handler ekleniyor httpChannel.HttpNotificationReceived += httpChannel_HttpNotificationReceived; // Toast event handler ekleniyor httpChannel.ShellToastNotificationReceived += httpChannel_ShellToastNotificationReceived; // Hata için event handler httpChannel.ErrorOccurred += httpChannel_ErrorOccurred; }ChannelUriUpdated event handler Microsoft Push Notification servisinden gelen yanıtları yakalayacaktır;
private void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e) { Debug.WriteLine("Güncellenen kanal:" + httpChannel.ChannelUri.ToString()); httpChannel.BindToShellToast(); httpChannel.BindToShellTile(); }
Şimdide sırasıyla Raw ve Toast bildirimleri yakalayan event handler kod satırlarımızı ekleyelim. Gelen bildirimler asenkron olarak çalışacağı için Windows Phone ekranına koyacağımız bir textblock'da görüntüleyebilmek için textblock'un Dispatcher.BeginInvoke methodundan faydalanacağız.
private void httpChannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e) { BinaryReader reader = new BinaryReader(e.Notification.Body, System.Text.Encoding.UTF8); string ntext = reader.ReadString(); txtMessageBox.Dispatcher.BeginInvoke(new Action(delegate() { txtMessageBox.Text += "Raw Notification" + Environment.NewLine; txtMessageBox.Text += ntext + Environment.NewLine; } ) ); } private void httpChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e) { txtMessageBox.Dispatcher.BeginInvoke(new Action(delegate() { txtMessageBox.Text += "Toast Notification:" + Environment.NewLine; })); if (e.Collection != null) { Dictionary<string, string> collection = (Dictionary<string, string>)e.Collection; foreach (string elementName in collection.Keys) { txtMessageBox.Dispatcher.BeginInvoke(new Action(delegate() { txtMessageBox.Text += elementName + " - " + collection[elementName] + Environment.NewLine; })); } } }ErrorOccured event handler da bir hata oluşması durumunda, hatayı yakalayacak ve kanalı kapatıp açarak tekrar bağlantının kurulmasını deneyecektir.
private void httpChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e) { Debug.WriteLine("Hata oluştu: " + e.Message); Debug.WriteLine("Kanal tekrar açılacak..."); httpChannel.Close(); httpChannel.Open(); }
Windows Phone kod satırlarımızı da eklediğimize göre, şimdi debug modda F5 ile projemizi çalıştırıp, olup biteceklere göz atalım. Windows Phone 7 Emulatör seçili durumda ve debug modda uygulamamızı çalıştıralım. MainWindows Loaded event handler altına eklediğimiz Debug.WriteLine kod satırları ile gönderdiğimiz bilgilere output penceresinden bakıyoruz.
Output penceresinden Microsoft Push Notification Servisinin gönderdiği kanal adresini kopyalayarak sender programımızı çalıştırıp ilgili URI alanına, kanal adresini kopyalayalım.
Raw Notification string alanına "Merhaba Dünya :)" yazarak Gönder butonu ile bildirimimizi gönderelim. Windows Phone uygulamamız açık ve ilgili event handler eklenmiş olduğu için gönderilen bildirim aşağıdaki ekran görüntüsünde olduğu gibi ekrana yansıyacaktır.
Raw notification ile gönderdiğimiz bildirim mesajı yalnızca uygulama ekranı açık olduğunda iletilecektir. Toast ve Tile notification'lar için uygulama ekranının açık olmasına gerek yoktur. İlgili bildirim Toast ise ekranın üst
kısmında belirecek, Tile ise quick launch ekranında uygulama tile alanında yazdırılacaktır.
Aşağıdaki ekranda Windows Phone Toast notification görüntüsü yer alıyor. Phone uygulamamızın icon özelliğini project properties'den "warning.png" olarak değiştirdiğimiz için bir ünlem işareti ile toast bildirimi almış olduk ve ilgili bildirim mesajıyla "Ekmek Almayı unutma :)" mesajını göndermiş olduk.
Kolay gelsin.
Faydalı Linkler:
http://msdn.microsoft.com/en-us/library/ff941124(v=vs.92).aspx
http://msdn.microsoft.com/en-us/wp7trainingcourse_usingpushnotificationslab_topic1
http://create.msdn.com/en-US/education/catalog/sample/push_notifications
Gökhan Manduz
http://gokhanmanduz.blogspot.com/
gmanduz@gmail.com
Kaydol:
Kayıtlar (Atom)