20 Nisan 2011

Windows Phone 7 de Veri Depolama - 1

IsolatedStorage


Windows Phone 7 uygulamalarımızda, veri kaynaklarına erişim için uygulama her açıldığında bir sunucu üzerinden web servisleri ile bağlantı kurarak verileri tekrar tekrar almak zorunda olmadığımızı söyleyerek makalemize başlayabiliriz. Bir windows phone uygulamasında uygulamamıza özgü tahsis edilecek olan isolated- storage (yalıtılmış/izole edilmiş depolama alanı) veri deposunu kullanabiliriz. Adından da alaşılacağı gibi bu alana verilerimizi yazabilir ve ihtiyaç duyduğumuzda rahatlıkla tekrar okuyabiliriz. Bu bellek alanı izole
edilmiş bir depolama alanı olduğu için yalnızca kendi uygulamamız tarafından yönetebilir olacağız.

Windows Phone 7 de isolated-stoarage' in kullanımında 2 temel yol vardır. Bunlardan birincisi bir basit anahtar ve değer çifti ile  (key-value pair) oldukça sade ve kolay kullanım yoludur. Diğer yol ise dosya erişim sistemi kullanarak (System.IO) stream 'ler (akış) ile dosyalara verilerimizi yazıp okuyabiliriz olacağız.
Örnek verecek olursak, uygulama kullanıcılarının bir uygulamayı her başlattıklarında kullanıcı adlarını tekrar tekrar yazmak istememeleridir, ya da sabit ve sürekli kullanılacak bir takım verileri isolated-storage alanında saklamak ve ihtiyaç duyulduğunda hızlıca ulaşmak performans, hız gibi konularda bize artı sağlayacaktır.
IsolatedStorageSettings sınıfını kullanarak ilk örneğimizde basit bir giriş ekranı oluşturalım. Aşağıdaki örneğimizde kullanıcı giriş ekranı üzerinde bulunan kullanıcı adı textbox nesnemiz eğer daha önce kullanıcı adı
girişi yapılmış ise dolu gelecek ve kursör şifre passwordbox nesnesine focus olacak.

XAML


<Grid x:Name="ContentPanel" Grid.Row="1" 
      Margin="12,0,12,0">
    <StackPanel>
        <TextBlock Text="Kullanıcı Adı"
                   Margin="10,0,0,0"/>
        <TextBox x:Name="txtUserName"/>
        <TextBlock Text="Şifre"
                   Margin="10,0,0,0"/>
        <PasswordBox x:Name="txtSifre"/>
        <Button x:Name="btnGiris" 
                Width="200" Height="80"
                Content="Giriş"
                HorizontalAlignment="Right"
                Click="btnGiris_Click"/>
    </StackPanel>
</Grid>

C#


private void MainPage_Loaded(object sender, RoutedEventArgs e) {
  string userName;
  IsolatedStorageSettings.ApplicationSettings.TryGetValue<string>("UserName",
                                                                      out userName);
  if (!string.IsNullOrEmpty(userName)) {
    txtUserName.Text = userName;
    txtSifre.Focus();
  }
  else {
    txtUserName.Focus();
  }
}
private void btnGiris_Click(object sender, RoutedEventArgs e) {
  IsolatedStorageSettings.ApplicationSettings["UserName"] = txtUserName.Text.Trim();
}
 























Yukarıdaki örnekte kullandığımız key-value pair yönteminde komplex bir objeyi de tercih edebiliriz.

C#


private void MainPage_Loaded(object sender, RoutedEventArgs e) {
  UserInfo user;
  IsolatedStorageSettings.ApplicationSettings.TryGetValue<UserInfo>("User",
                                                                     out user);
  if (user != null) {
    txtUserName.Text = user.KullaniciAdi;
    txtSifre.Focus();
  }
  else {
    txtUserName.Focus();
  }
}
 
private void btnGiris_Click(object sender, RoutedEventArgs e) {
  UserInfo user = new UserInfo() { KullaniciAdi= "gokhan", 
                                   KullaniciId = 1,
                                   KullaniciIsim = "Gökhan Manduz"
                                 };
  IsolatedStorageSettings.ApplicationSettings["User"] = user;
}
Uygulamamızın Isolated-Storage ApplicationSettings içerisinde bulunan bir değeri elde etmek için her defasında TryGetValue methodunu tekrar tekrar yazmaktansa aşağıdaki gibi daha merkezi bir çözüm ile jenerik bir method kullanarak da işimizi kolaylaştırabiliriz.

C#


public T GetAppSettingValue<T>(string key) {
  object value;
  if (IsolatedStorageSettings.ApplicationSettings.TryGetValue(key,
        out value)) {
            return (T)value;
   }
  return default(T);
}

Data Binding ile Isolated-Storage Kullanımı

Alternatif olarak farklı bir yöntemlede arayüzde kullandığımız textbox nesnesi kullanıcı adını DataBinding
yöntemi kullanarak bağlamak. İlk önce içerisinde string tipinde bir property barındıran sınıfımızı oluşturalım. Bu sınıfımızın görevi isolated-storage'e veri yazma ve okuma olsun.

C#


public class AppSettingsClass {
  public string UserName {
    get {
      string user;
      if (IsolatedStorageSettings.ApplicationSettings.TryGetValue("UserName",
                                                                  out user)) {
        return user;
      }
      return "";
    }
    set {
      IsolatedStorageSettings.ApplicationSettings["UserName"] = value;
    }
  }
}
Geriye yalnızca xaml kodları kullanarak kullanıcı adı textbox nesnesine iki yönlü olarak (TwoWay) yukarıdaki sınıfta belirttiğimiz UserName string property'sini bind etmek kalıyor; ilk önce App.xaml dosyasına kullanacağımız namespace'i local adıyla tanımlayalım. Daha sonra MyDataSettings adıyla Resource bölümüne AppSettingsClass tanımlamamızı yapalım.

XAML (App.xaml)

<Application 
    x:Class="WP7StorageSample.App"
    xmlns:local="clr-namespace:WP7StorageSample"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
    
    <Application.Resources>
        <local:AppSettingsClass x:Key="MyDataSettings" />
    </Application.Resources>
    
    <Application.ApplicationLifetimeObjects>
        <shell:PhoneApplicationService 
            Launching="Application_Launching" Closing="Application_Closing" 
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>
 
</Application>

Kullandığımız kullanıcı adı Textbox nesnemizi de aşağıdaki gibi xaml kodları yardımıyla düzenleyelim. Binding modu TwoWay olacağından dolayı textbox her değiştiğinde otomatik olarak isolated-storage'e yazılan değer kaydedilecektir ve sayfa sayfa açıldığında da textbox üzerine isolated-storage'den okunan değer bind edilecektir.

XAML (MainPage.xaml)


<TextBox x:Name="txtUserName"
         DataContext="{StaticResource MyDataSettings}"
         Text="{Binding UserName, Mode=TwoWay}"/>

IsolatedStorageFileStream Kullanımı


Yazımızın başlarında da belirttiğimiz gibi isolated-storage'in bir diğer kullanım tekniği de IsolatedStorageFileStream ile yalıtılmış bellek alanı içerisinde bir dosyaya veya dosyalar üzerinde yazma ve okuma işlemlerini rahatlıkla uygulayabiliriz. System.IO 'dan alışık olduğumuz File.Exist, File.Create gibi methodları kullanabileceğimiz gibi bir StreamReader veya StreamWriter nesnesini kullanarak File üzerinde veri depolama işlemlerimizi yapma şansımız da olacak.

Şimdi StreamWriter ve StreamReader sınıflarını da kullanarak dosya oluşturup yazma ve okuma işlemlerini
gerçekleştireceğimiz örneğimizi yazmaya başlayalım.

C#


private void btnKaydet_Click(object sender, RoutedEventArgs e) {
  using (var myStream =
         new IsolatedStorageFileStream("demo.txt"FileMode.Create,
         IsolatedStorageFile.GetUserStoreForApplication()))
  using (var writer = new StreamWriter(myStream)) {
    writer.WriteLine("Bu string cümlesini deneme isimli dosyaya yazdım.");
  }
  MessageBox.Show("Kaydedildi.");
}
C#


private void btnOku_Click(object sender, RoutedEventArgs e) {
  using (var myStream = 
         new IsolatedStorageFileStream("demo.txt"FileMode.Open,
         IsolatedStorageFile.GetUserStoreForApplication()))
  using (var reader = new StreamReader(myStream)) {
    var text = reader.ReadToEnd();
    MessageBox.Show(text);
  }
}
Peki default olarak ayrılmış olan isolated-storage alanı ihtiyacımızı karşılamayacak olursa? Bu durumda aşağıdaki gibi byte bazında kotayı arttırabiliriz. Eğer artış sağlanırsa dönüş değeri true aksi durumda false 
olacaktır.

C#


var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication();
bool result = isolatedStorageFile.IncreaseQuotaTo(100000);
Windows Phone 7 de Sql Server Compact gibi bir veritabanı teknolojisi desteklenmediği için verilerimizi telefon üzerinde saklamak ve ihtiyaç durumunda tekrar kullanmak için IsolatedStorage bellek alanına oldukça 
fazla ihtiyaç duyulacak gibi görünüyor. Bir sonraki makalelerimizde verilerimizi sanki bir veri tabanı teknolojisi ile çalışıyormuşuz gibi insert, update ve delete methodları oluşturarak static resource dosyaları üzerinde işlemlerimizi gerçekleştirebilmek üzere bu makalemizi burada sonlandıralım.

Kolay gelsin.

gokhanmanduz@hotmail.com

10 Nisan 2011

Fatih Boy ile Windows Phone 7 Üzerine Röportaj

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.

27 Mart 2011

"Windows Phone 7 de Uygulama Geliştirmek" Webiner Videosu




Merhaba, aşağıdaki linkten 23 Mart 2011 tarihli düzenlediğim windows phone 7 de uygulama geliştirme konulu webiner video dosyasına ulaşabilirsiniz. ( http://bit.ly/dEZszP )














İndirmek için tıklayınız.. ( http://bit.ly/dEZszP )
İyi seyirler.


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);
}


Eğer sayfalar arasındaki navigasyon geçişlerini izlemek isterseniz, App sınıfı constractor içerisine aşağıdaki kod satırlarını ekleyerek debug da iken bunu da sağlayabilirsiniz.

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

15 Şubat 2011

Yaz geliştir de ayın makalesi..

Yazgeliştir ekibi WP7' de touch ve multi-touch inputs konulu makalemi ayın makalesi seçmiş.. Yaz geliştir ekibine teşekkür ediyorum... 

1 Şubat 2011

Windows Phone Development: For update supported country list

Windows Phone Developer Account için gelen sorular üzerine aşağıdaki linki veriyorum, listeden Türkiye' nin olup olmadığı kontrol edilebilir. Bir süre daha beklememiz gerekiyor..
App Hub
https://users.create.msdn.com/Register

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.