22 Nisan 2012

Windows Phone 7 de Json Veri Formatı ve WCF Servisi


Bir süredir makale yazmaya ara verdikten sonra yeniden windows phone 7 serisi ile makale yazımına devam ediyoruz. Bu makalemizin konusu, merkezi web servisleri ile çalışan mobil uygulamalarımızda hız ya da daha çok performans sağlayacağını düşündüğüm JSON (JavaScript Object Notation) veri formatı üzerinde duracağız. Ayrıca bu makalemizin WCF veri servisleri ve bandwith optimizasyonu ile uğraşanların ilgisini çekeceğini düşünüyorum.. Web servisimizi geliştirirken visual studio wcf service application template'den faydalanacağız.

Windows phone uygulamamızı yazmaya başlamadan önce, web servisimizi hazır durma getirerek, projemizi geliştirmeye başlayalım. Visual studio -> File -> New -> Project -> WCF -> "WCF Service Application" Template ile yeni bir solution oluşturacağız.
























WCF servisini oluşturmak için OK butonuna tıkladığımızda aşağıdaki servis dosyaları otomatik olarak oluşturulmuş olacaktır. IService1 isimli interface ve  Service1.svc.cs sınıfını kullanarak servis tarafındaki kodlarımızı yazmaya başlayabiliriz.






















Servis tarafında hizmet verecek bir de veritabanı hazırlayarak, servisin sunacağı verilerin, bir sqlserver veritabanı dosyasından gelmesini sağlayalım. Projemizin içinde yer alan App_Data klasörüne sağ tıklayarak örnek bir veritabanı hazırlayabiliriz. Veritabanımıza aspnetdb.mdf adını veriyorum..


































Bu örneğimizde SqlServer Express Edition kullanıyorum. aspnetdb.mdf db dosyamıza çift tıklayarak visual studio server explorer penceresi üzerinden db'mize PERSONEL adında küçük (3 kolondan oluşan) bir tablo oluşturarak hızlıca ID, ADI ve SOYADI kolonları oluşturalım. (Ben bu örnekte tablonun içine 168 satırlık, birbirinin tekrarı olan isimler ekledim..)

Şimdi gelelim Personel tablosuna ait bir de Personel.cs isimli bir sınıf oluşturmaya. Verilerin bu sınıfın yardımıyla json ve xml olarak olarak serileştirilmesini isteyeceğiz. Bunun için Personel sınıfını ve sınıfa ait property'leri aşağıdaki gibi yazalım.


C#
namespace MyWcfService
{
    [DataContract]
    public class Personel
    {
        [DataMember]
        public int ID { getset; }
        [DataMember]
        public string ADI { getset; }
        [DataMember]
        public string SOYADI { getset; }
    }
}

Personel.cs sınıfımızı ve sınıfa ait üyelerin DataContract, DataMember attribute'lerini eklemeyi unutmuyoruz, sonra sırada IService1 isimli interface içerisine kod satırlarımızı (kullanacağımız method imzalarını) aşağıdaki gibi ekleyelim. Interface içindeki method imzalarının attribute'lerine dikkat edecek olursak, servisimizde sunacağımız verinin formatını burada belirtiyoruz. Json için WebMessageFormat.Json, Xml için ise WebMessageFormat.Xml'den faydalanacağız.



C#
namespace MyWcfService
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [WebGet(UriTemplate = "GetAllPersonel", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Personel[] GetAllPersonel();
 
        [OperationContract]
        [WebGet(UriTemplate = "GetAllPersonelWithXML", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
        Personel[] GetAllPersonelWithXML();
    }
}


Yukarıdaki interface içinde görüleceği gibi [OperationContract] attribute yanı sıra [WebGet] ile Request ve Response formatlarımızı belirttik.

Kasıtlı olarak 2 farklı method oluşturduk. Aynı veriyi (aynı boyutlardaki veri için) hem JSON hem de XML formatında servisimiz ile sunacağız. Bu örneğimizde Json ile GetAllPersonel, Xml ile de GetAllPersonelWithXML isimli methodları kullandık. Gelin şimdi hep birlikte interface'imizi kullanacağımız Service1.svc.cs dosyamızda iş mantığı kodlarımızı hazırlayalım.


C#
public class Service1 : IService1
{
  public Personel[] GetAllPersonel()
  {
      return getAllPersonelFromDB();
  }
  public Personel[] GetAllPersonelWithXML()
  {
      return getAllPersonelFromDB();
  }
 
  private Personel[] getAllPersonelFromDB() {
    try
    {
       string connStr = ConfigurationManager.ConnectionStrings[0].ConnectionString;
       using (SqlConnection connection = new SqlConnection(connStr))
       {
           using (SqlCommand cmd = new SqlCommand("SELECT * from PERSONEL",connection))
           {
               connection.Open();
               using (var myReader = cmd.ExecuteReader())
               {
                   List<Personel> listOfPersonel = new List<Personel>();
                   while (myReader.Read())
                   {
                       Personel p = new Personel() { 
                           ID = (int)myReader["ID"], 
                           ADI = (string)myReader["ADI"], 
                           SOYADI = (string)myReader["SOYADI"] 
                       };
                       listOfPersonel.Add(p);
                   }
                   myReader.Close();
                   connection.Close();
                   return listOfPersonel.ToArray();
               }   
           }
                   
       }
   }
   catch (Exception)
   {
       throw;
   }
 }
}


Yukarıda yazdığımız C# kodlarını inceleyecek olursak. Veritabanından tüm 
Personel verisini çekmek için, SqlCommand nesnesinin ExecuteReader methodunu 
kullandık. Özellikle daha çok performansa ya da hıza ihtiyaç duyduğumuz 
veritabanı sorgularında DataReader kullanmak sorgu işleminin çok daha hızlı 
çalışmasını sağlayacaktır. Aynı kayıt kümesini SqlDataAdapter kullanarak bir 
DataSet nesnesi içine doldurmaya (Fill) 
çalıştığınızda çok daha fazla zaman 
kaybı yaşanacağı hissedilir ölçüde görülecektir. Dileyen arkadaşlar yukarıdaki 
veri sorgusu için DataAdapter ve 
DataSet kullanarak zaman farkını test edebiilirler. Bu noktada tabiiki 
DataSet 
nesnesinin kullanılmasının yeri ve önemini yadsımıyoruz, fakat DataReader ile yalnızca 
ReadOnly (yalnızca okumak için) veri kümelerinin sorgulanacağı 
durumlarda daha fazla performans kazandıracağı bir gerçektir.

Aşağıdaki resmi inceleyecek olursak DataAdapter/DataSet ve DataReader'ın mimarideki yeri daha net görülebilir.






Dileyen MSDN linkinden DataSet ve DataReader arasındaki farklara daha detaylı göz atabilir. MSDN
Konumuzdan fazla uzaklaşmadan kaldığımız yerden devam edelim. Json veri formatı için web.config dosyamızda da gerekli endpoint konfigürasyonlarını hazırlamamız gerekiyor. Web.config dosyamız aşağıdaki gibi olacaktır.

XML (web.config)
xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="SQLDB" 
         connectionString="Data Source=.\SQLEXPRESS;
                           AttachDbFilename=DataDirectory;
                           Integrated Security=True;User Instance=True"/>
  connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  system.web>
  <system.serviceModel>
    
    <services>
      <service name="MyWcfService.Service1">
        <endpoint name="jsonEndPoint" 
                  binding="webHttpBinding"  
                  behaviorConfiguration="json" address=""
                  contract="MyWcfService.IService1"/>
      service>
    services>
    
    <behaviors>
      <endpointBehaviors>
        <behavior name="json">
          <webHttp/>
        behavior>
      endpointBehaviors>
    behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  system.webServer>
configuration>


Web.config dosyasını da düzenledikten sonra bilgisayarımızda 
internet browser üzerinde servis 
methodlarımızı test edebilir duruma geldik. Servis1.svc dosyasına sağ tıklayıp 
web browser'dan açarak 
üzerinden incelemeye devam edelim.



Internet browser'da servis sayfamız aşağıdaki gibi açılacaktır. URL komut satırında svc'den sonra /GetAllPersonel diyerek json data fırmatlı methodumuzu çağıralım.  (http://localhost:55382/Service1.svc/GetAllPersonel)






























Browser'ın alt kısmında çıkan popup'dan "Aç" diyerek verileri notepad dosyası formatında açabiliriz. Bu arada dikkat edilmesi gereken önemli bir noktayı gözden kaçırmayalım, dosyanın boyutunun 7,08 KB olarak göreceğiz. Dosyayı açtığımızda veri formatının da  [{"ADI":"Gökhan","ID":1,"SOYADI":"Manduz"},... şeklinde json formatında olduğunu görebiliriz.























Benzer şekilde, aynı veri kümesini XML formatında sunan methodumuzu da internet browser üzerinden test ettiğimizde aşağıdaki görüntüyle karşılaşacağız. (Aynı veri kümesini sorguladığımızı unutmayalım.)






























XML formatında açılan verilerin tümünü seçerek bir notepad dosyasına alıyorum. Sonuç aşağıdaki gibi : 11,08 KB
























Bu noktadan sonra, gelelim mobil taraftan servisimizi çağırmaya. Ben Json ile serileştirilen methodu kullanacağım. Dileyen XML kullanabilir. Fakat yukarıda da görüldüğü gibi özellikle mobil platformda Json'ın avantajı yadırganamaz.

Hemen aynı solution üzerinden, solution'a sağ tıklayarak bir windows phone projesi ekleyelim ve mobil client tarafını geliştirmeye başlayalım.

























Servis tarafında oluşturduğum Personel.cs sınıfının bire-bir aynısını, attribute'ler hariç client tarafta çalışacak olan phone projemize de ekliyoruz.

C#
namespace MyPhone7Application
{
    public class Personel
    {
        public int ID { getset; }
        public string ADI { getset; }
        public string SOYADI { getset; }
    }
}


Windows Phone ana ekranımın XAML kodlarınıda hızlıca aşağıdaki gibi hazırlıyorum. (Aşağıda RowDefinition / Height ile belirttiğim 15*, yüzde 15 anlamına gelmektedir.)


XAML
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="15*"/>
        <RowDefinition Height="15*"/>
        <RowDefinition Height="70*"/>
    Grid.RowDefinitions>
            
    <Button Grid.Row="0" Content="Json Listele" 
            Name="btnJson" Click="btnJson_Click" />
    <TextBlock Grid.Row="1" Name="txtResult"/>
    <ListBox Grid.Row="2" Name="lstPersonel" />
Grid>




C# tarafında WebClient nesnesi kullanacağız. Servis referansı eklemeye gerek kalmadan WebClient ile json olarak serileştirilmiş veriye asenkron çağrıda bulunacağız ve stream veriyi okuyacağız.  Personel[] nesnemize kavuşmak için DataContractJsonSerializer'dan yardım alarak json formatındaki veriyi tekrar geri serileştirmiş olacağız.(deserializer).

DataContractJsonSerializer nesnesi için System.ServiceModel.Web referansını önceden projemize eklememiz gerekmektedir.




























C#

public partial class MainPage : PhoneApplicationPage
{
   private DateTime _startTime;
   private DateTime _endTime;
   public MainPage()
   {
       InitializeComponent();
   }
   private void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
   {
       if (e.Error == null) {
           DataContractJsonSerializer serializer = 
               new DataContractJsonSerializer(typeof(ObservableCollection<Personel>));
 
           ObservableCollection<Personel> personelList = 
               (ObservableCollection<Personel>)serializer.ReadObject(e.Result);
 
           lstPersonel.Items.Clear();
           foreach (var item in personelList)
           {
               lstPersonel.Items.Add(String.Format("Id: {0} ,  {1} {2}",item.ID, 
                                                                        item.ADI, 
                                                                        item.SOYADI));
           }
           _endTime = DateTime.Now;
 
           TimeSpan interval = _endTime - _startTime;
           txtResult.Text = String.Format("Sorgulama {0} mili saniye sürdü.", interval.Milliseconds);
       }
   }
   private void btnJson_Click(object sender, RoutedEventArgs e)
   {
       WebClient clientJson = new WebClient();
       Uri uri = 
           new Uri("http://localhost/jsonwebtest/Service1.svc/GetAllPersonel");

       clientJson.OpenReadCompleted += client_OpenReadCompleted;
       _startTime = DateTime.Now;
       clientJson.OpenReadAsync(uri);
   }
}
 
Artık keyifle sonucu görmenin zamanı geldi. Uygulamayı windows phone emulatör'de F5 ile başlatarak test edelim, Uygulama emulator'de başladığında "Json Listele" butonuna tıklayarak sonucu görelim. Sorgu sonucu için geçen sürede tabiiki farklılıklar (kullanılan bilgisayarın da hızına bağlı olarak) olacaktır. Kendi kişisel bilgisayarımda 44 milisaniyeyi gördüm :)
Hızlı uygulamalar yazmanız dileklerimle, makalemizi burada sonlandırıyoruz. Özellikle bandwith optimizasyonu ile uğraşanlar için de json veri formatının oldukça faydalı bir çözüm olacağı kanısındayım.

Windows Phone Emulator










































Kolay gelsin.

Gökhan Manduz
http://gokhanmanduz.blogspot.com/

13 Mart 2012

Windows Phone 7 de Veri Depolama - 2


Windows Phone 7 de Veri Depolama - 1 konulu makalemizde genel hatlarıyla isolated-storage bellek alanının kullanılmasını incelemiştik. Geçen makalemizde Isolated-Storage bellek alanındaki verileri windows phone 7 uygulama ara yüzü nesnelerimize 'data-binding' yöntemi kullanarak bağlayıp, çeşitli kullanım yöntemleri incelemiştik.  Bu makalemizde ise, hali hazırda geliştirilmiş ve codeplex.com gibi internet sitelerine eklenmiş olan alternatif veritabanı projelerini inceleyeceğiz.  Windows Phone 7 de SqlServerCE gibi bir veri tabanı teknolojisinin kullanılmaması diğer taraftan windows phone 7 üzerinde offline verilerle çalışma ihtiyacı, bizleri daha derli toplu bir şekilde isolated-storage alanının kullanımına itmektedir.


Tekrar belirtmek isterim ki bu yazımızda SqlServer Compact Edition gibi bir veritabanı teknolojisi incelenmeyecek. (Zaten şu an phone 7'nin böyle bir desteği yok) Yalnızca isolated-storage bellek alanı üzerinde System.IO.IsolatedStorage.IsolatedStorageFile gibi sınıfların kullanıldığı, basit anlamda dosyalara verilerin belirli bir düzen içerisinde yazılıp-okunması gibi temel işlemleri içeren kütüphaneleri incelemiş olacağız.


Windows Phone 7 Database;

Windows Phone 7 Database projesinin kaynak kodlarına http://winphone7db.codeplex.com/ internet sitesi üzerinden ulaşabiliyoruz.














Oldukça sade ve düzenli yazılmış bu projeyi bilgisayarımıza indirdiğimizde, aşağıdaki imaj da görüleceği gibi WindowsPhoneDatabase isimli bir projenin olduğu görülecektir.








































İndirilen solution içerisinde SilverlightPhoneDatabase projesi ile birlikte SilverlightPhoneDatabaseTest isimli bir proje de yer almaktadır. SilverlightPhoneDatabase kütüphanesi ile silverlight isolated-storage tabanlı, windows phone uygulamaları için ayrılmış olan bellek alanı içerisinde bir veritabanı oluşturulmakta. Kütüphane içerisindeki methodları inceleyecek olursak, aşağıdaki class diagram üzerinden de görüleceği gibi Framework Proje olan SilverlightPhoneDatabase içerisindeki temel sınıfların Database, Table ve Crypthography olduğu görülecektir. Bunun yanı sıra bir takım yardımcı sınıflar ve bir de interface kullanılmış. 


































Şimdi yukarıdaki class diagram üzerinde görülen birkaç methodun kullanımına göz atalım.
Bu örnekte Person (Kişi) isminde bir tablo oluşturulacak. Person tablosuna karşılık gelen sınıf aşağıdaki gibi tanımlanmış;

C#


Database.DeleteDatabase("test");
Database db = Database.CreateDatabase("test");
db.CreateTable<Person>();
if (db.Table<Person>() != null)
{
    db.Table<Person>().Add(NewPerson());
}






Sterling WP7 Database;

Şimdi de farklı bir kütüphaneyi incelemek üzere http://sterling.codeplex.com/ adresli codeplex internet sitesi üzerinde yayınlanmış olan kütüphaneyi inceleyelim. Bu kütüphanenin kullanıldığı başka bir örneğe de http://www.codeproject.com/KB/silverlight/SLDatabaseApp.aspx adresinden ulaşabiliriz. Oluşturulmuş olan bu projede objelere erişirken tamamen LINQ desteği kullanılabilmektedir.



















Aşağıdaki grafik incelendiğinde, Sterling DB' nin de performans yönünden de oldukça başarılı olduğu görülecektir.























Sqlite Client for Windows Phone;

Windows Phone 7 işletim sistemi altında çalışabilir farklı bir database projesi olarak Sqlite Client isimli projenin de incelenmesinde fayda var. Sqlite Client projesine http://sqlitewindowsphone.codeplex.com/ adresinden ulaşılabilir. Örnek projeyi bilgisayarınıza indirdiğinizde Community.CsharpSqlite.WP isimli bir veritabanı kütüphanesi için oluşturulmuş bir proje ile bir de CSharpSqlite.TestProject isimli Phone 7 projesi görülebilir. Bu proje de Windows Phone 7 Emulatör aracılığı ile F5 ile çalıştırılmak istendiğinde ilk olarak aşağıdaki gibi örnek bir uygulama ile başlayacaktır.








































Örnek Windows Phone 7 projesinde yer alan btnInsert isimli (Generate Data başlıklı) butona tıklanıldığında aşağıdaki kod satırları çalıştırılarak, 50 adet random verinin test isimli bir tabloya nasıl kaydedildiğini görebiliriz.

C#


private void btnInsert_Click(object sender, RoutedEventArgs e)
{
  lbOutput.Text = "";
  if (db != null)
  {
      try
      {
          var start = DateTime.Now;
          SQLiteCommand cmd = db.CreateCommand("");
          int rec;
          var rnd = new Random();
          for (int i = 0; i < sliderRows.Value; i++)
          {
              var stream = new byte[i + 1];
              rnd.NextBytes(stream);
              var tst = new Test(i,"Entry "+i,i+10,DateTime.Now,(i%2==0)?true:false,stream);
              cmd.CommandText = " Insert into test (id,name,bytes,modified,condition,stream) " +
                                " values (@id,@name,@bytes,@modified,@condition,@stream)";
              cmd.ExecuteNonQuery(tst);
          }
          lbOutput.Text += "\nInserted " +
                           sliderRows.Value +
                           " rows\r\nGenerated in " +
                           (DateTime.Now - start).TotalSeconds;
      }
      catch (SQLiteException ex)
      {
          lbOutput.Text += "\nError: " + ex.Message;
      }
  }
}




Son olarak da Perst isimli object-oriented veritabanı sisteminin erişim adreslerini vererek makalemizi sonlandıracağız. Perst hakkında detaylı bilgilere http://www.mcobject.com/perst adresinden ulaşılabilir. İlgili Demo projeye ulaşmak için http://mobileworld.appamundi.com/blogs/andywigley/archive/2010/06/07/perst-a-database-for-windows-phone-7-silverlight.aspx adresini kullanabilirsiniz.
Demo uygulamayı bilgisayarınıza indirip Emulatör ile çalıştırdığınızda aşağıdaki gibi ekran görüntüleri ile karşılaşacağız.




































Perst Windows Phone 7 Database ile ilgili olarak da tabloları Drop etmeye yarayan örnek kod parçaları da aşağıdaki gibidir.

C#


public void Clear()
{
    IsComplete = false;
    try
    {
        Database.DropTable(typeof(Contact));
        Database.DropTable(typeof(Lead));
        Database.DropTable(typeof(Activity));
        Database.Storage.Commit();
        InvokeClearComplete(EventArgs.Empty);
    }
    finally
    {
        IsComplete = true;
    }
}




Şu ana kadar incelediğimiz windows phone 7 veritabanı projeleri bize geleneksel veritabanlarının kullanım şekillerini aratmayacak şekilde taklit edilmiş/tasarlanmış olduklarını söyleyebiliriz. İnternet üzerinden ücretsiz WP7 veritabanı projelerinin olduğunu gözlemleyebiliyoruz. İhtiyaçlar arttıkça bunlara benzer alternatif veritabanı projeleri de artacak ve gelişecektir. Son olarak bu projelere ait referans linklerin tümünü bir arada vererek makalemizi sonlandıralım.

http://winphone7db.codeplex.com/ (Windows Phone 7 Database)
http://sterling.codeplex.com/ (Sterling)
http://sqlitewindowsphone.codeplex.com/ (Sqlite Client)
http://www.mcobject.com/perst (Perst)

Kolay gelsin.

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