Ana Sayfa | English Blog | Seminer TV | Dil Cookie Sil  Blog'u Mail ile takip et!  
Daron Yöndem - Silverlight 2.0
bir yazılımcının tasarıları...
 Thursday, April 01, 2010

Her sene 1 Nisan MVP'liğimin bittiği gün :) Şaka gibi değil mi? :) Biliyorsunuz MVP ünvanı her seferinde senelik olan Microsoft tarafından verilen bir ünvan bu nedenle bir bitiş tarihi var ve bu nedenle de her sene yenilenmesi gerekiyor :) Eh benimki bugün yenilendi. 2010 yılında da "Silverlight MVP"si olarak var olmaya devam edeceğim. Bu gaz ile önümüzdeki dönemde blogda ekstra hareketlilik göreceğinizden de emin olabilirsiniz :)

Hepinize bu dönemde gösterdiğiniz destek için ayrıca çok teşekkürler. Bilgiyi paylaşmak ancak paylaşabileceğiniz insanlar oldukça zevkli ve güzel. 2010'da da daha yapacak çok işimiz var ;) ve güzel sürprizlerim var ;)

Görüşmek üzere.

Thursday, April 01, 2010 6:58:01 AM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight | Silverlight 2.0 | Silverlight 3.0 | Silverlight 4  | 
 Saturday, February 13, 2010

Bu görsel dersimizde Silverlight ile sunucuya FileUpload işlemi yapmanın yollarından birini inceliyoruz.

Yukarıdaki videoyu bilgisayarına indirmek isteyenler blogumun SeminerTV bölümünden faydalanabilirler.

İyi seyirler...

Saturday, February 13, 2010 5:35:43 PM (GTB Standard Time, UTC+02:00)  #    Comments [11]   Silverlight 2.0 | Silverlight 3.0 | Silverlight 4  | 
 Wednesday, September 02, 2009

DVD veya CD arayüzleri hala bilgisayar dünyasında ciddi bir yere sahip. İçeriğin paylaşımı adında internet ciddi bir yol almış olsa da hala CD ve DVD medyalarını kullanarak içeriğin dağıtımı bazı senaryolarda çok daha işlevsel olabiliyor. Bu gibi durumlarda doğal olarak bir arayüz ile söz konusu içeriği bir CD veya DVD içerisinde sunmak gerekiyor. Peki bu arayüzü geliştirmek için hangi teknolojileri kullanabiliriz?

Gelin beraberce sıralayalım;

HTML - Pufff!
Flash - ActionScript? Pufff!
WPF - .NET Framework yükletmek? Puff!
Silverlight - Oley! İşte bu!

Şaka bir yana :) aslında bir CD veya DVD arayüzü geliştirirken ihtiyacımız olan şey hem arayüz içerisinde her tür data işlemini yapabilimek hem de güzel bir arayüz tasarlayabilmektir. Varsayalım bir ürün kataloğu yapıyorsunuz, büyük ihtimal ile söz konusu ürünler arasında arayüzde arama da yapılabilmelidir. İşte ufak da olsa bir programlama noktası karşımızda. Olabildiğince rahat programlamak ve bildiğimiz bir dili kullanmak önemli. HTML ile JavaScript veya Flash ile ActionScript bir .NET developer için çok da ferah bir gelecek vaadetmeyecektir. Ayrıca HTML ile zaten güzel bir arayüz, zengin bir kullanıcı deneyimi sağlamak da pek mümkün değil.

Alternatiflerden bir diğeri WPF olabilir ve aslında çok da güzel olur. Fakat bu sefer de .NET Framework gereksinimi ile karşı karşıya kalıyoruz. Eh hadi DVD'nin içine koyalım ama insanların bir DVD arayüzünü görebilmek için .NET Framework kurup (en az 5dk) makinelerine restart atacaklarından emin misiniz?

Tüm bu senaryonda en güzeli Silverlight! Hem bildiğimiz VB, C# hem Expression Blend ile süper kullanıcı deneyimi hem de 4MB Runtime ve 5 saniye yükleme süresi. Hem MAC desteği de var! Eh gönül daha ne ister?

Tamam da şimdi tarayıcıda açtırmak da pek hoş olmuyor!

Kesinlikle! Bir CD veya DVD arayüzünün tarayıcı içerisinde açılması benim en uyuz olduğum noktalardan birisidir özünde. Neden mi? Çünkü ister istemez bir web sitesi hissiyatı yaratıyorsunuz ve en azından bende "çok uğraşılmamış" efekti oluşturuyor. Yani "adamlar web sitesi yapıp koymuş DVD'ye!" gibi abuk bir yorumun gelmesi olasılığı ciddi yüksek. O nedenle tarayıcıdan kurtulmamız gerek.

HTML Application = HTA!

HTA'larla ilk tanışdığımda "İşte bu" demiştim :) Sanırım SQL 2000'in yükleme CD'sinin arayüzünde görmüştüm. Arayüz ilgimi çekmişti çünkü bir tarayıcı gibi içinde HTML olduğunu hissetmiş fakat ortada bir tarayıcı görmemenin de şaşkınlığını yaşamıştım. Sonra biraz CD'yi karıştırınca HTA'larla tanıştım. HTA aslında HTML vs bir scripting dili ile yazılabilir uygulamalar şeklinde tanımlanabilir. Bu uygulamalar "Microsoft HTML Applicatio Host" adında özel bir uygulama tarafından Windows içerisinde host edilir. Arka planda Internet Explorer kullanılır fakat kullanıcılar bunu görmez. HTA uzantılı bir dosya rahatlıkla Notepad ile açılabilen birer HTML dosyasıdır aslında.

[HTA]

<HTML>

  <head>

  <link href="img/styles.css" type="text/css" rel="stylesheet" />

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <TITLE>

      Internet Explorer 8 -DVD

    </TITLE>

 

    <HTA:APPLICATION

     APPLICATIONNAME="IE8DVD" 

     MAXIMIZEBUTTON="no"

     MINIMIZEBUTTON="no"

     SINGLEINSTANCE="yes"

     ICON="setup.ico"

     SCROLL="no" />

  </HEAD>

 

<body style="margin:0px;">

 

    <script for="window" event="onload">

   window.resizeTo(820,640);

   window.moveTo((screen.width - 820) / 2, (screen.height - 640) / 2);

</script>

</body>

</html>

Yukarıda gördüğünüz kod basit bir HTA dosyasının içeriği. Aslında içerisinde pek birşey yok. İlk anlamamız gereken şey aslında bir HTML ile çalışıyor olduğumuz. Tabi biz arayüzü oluşturmak için HTML değil Silverlight kullanacağız. Önemli olan ilk şey tabi ki dokümanın TITLE kısmını ayarlamak çünkü bu uygulamanızın açılan penceresinin başlığı olacak. Aşağıda gördükleriniz ise uygulama parametreleri.

[HTA]

    <HTA:APPLICATION

     APPLICATIONNAME="IE8DVD" 

     MAXIMIZEBUTTON="no"

     MINIMIZEBUTTON="no"

     SINGLEINSTANCE="yes"

     ICON="setup.ico"

     SCROLL="no" />

Uygulamanın açılacağı pencerede pencereyi büyütme, küçültme vs gibi düğmeleri isteyip istemediğinizi belirtebilir hatta uygulamanın tek oturumunun olmasını da yukarıdaki parametreler ile sağlayabilirsiniz. Uygulama ikonunu da ayarladıktan sonra önemli noktalardan biri Scroll özelliği NO şeklinde set etmek. Malum biz bu HTML içerisinde arayüz olarak Silverlight koyacağımız için zaten gerekli scroll işlemlerini de SL içerisinde halledebiliriz.

[HTA]

    <script for="window" event="onload">

   window.resizeTo(820,640);

   window.moveTo((screen.width - 820) / 2, (screen.height - 640) / 2);

</script>

Yukarda basit bir JavaScript kodu görüyorsunuz. Bu kod uygulamanızın penceresinin boyutunu ayarlayacağı gibi pencerenin de ekranın tam ortasında gözükmesini sağlayacaktır. HTA'lar içerisinde hem JavaScript hem VBScript kullanabilirsiniz. Her script ait olduğu nesneye for özelliği ve ait olduğu nesnenin hangi event'ını dinleyeceğine de event parametresi ile bağlanır.

Bu noktadan sonra tabi ki sizin ilk olarak Silverlight uygulamanızı hazırlamanız gerek. Arayüz olarak kullanılacak Silverlight uygulaması hazırlandıktan sonra bu HTA içerisine uygun şekilde yerleştirilebilmesi çok önemli.

[HTA]

<HTML>

  <head>

  <link href="img/styles.css" type="text/css" rel="stylesheet" />

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <TITLE>

      Internet Explorer 8 -DVD

    </TITLE>

 

    <HTA:APPLICATION

     APPLICATIONNAME="IE8DVD" 

     MAXIMIZEBUTTON="no"

     MINIMIZEBUTTON="no"

     SINGLEINSTANCE="yes"

     ICON="setup.ico"

     SCROLL="no" />

  </HEAD>

 

<body style="margin:0px;">

    <div id="silverlightControlHost">

        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">

            <param name="source" value="ClientBin/Interface.xap"/>

            <param name="background" value="white" />

            <param name="minRuntimeVersion" value="2.0.31005.0" />

            <param name="autoUpgrade" value="true" />

            <img style="cursor:pointer;" ID="SLInstall" border="0" src="images/install.jpg" />

        </object>

    </div>

 

    <script for="window" event="onload">

   window.resizeTo(820,640);

   window.moveTo((screen.width - 820) / 2, (screen.height - 640) / 2);

</script>

     <SCRIPT FOR="SLInstall" EVENT="onclick" LANGUAGE="VBScript">

      Dim objShell

      Dim lngReturn

 

      on error resume next

 

      set objShell = CreateObject( "WScript.Shell" )

 

        lngReturn = objShell.Run ("Silverlight.2.0.exe", 4, 1)

 

      set objShell = Nothing

      document.execCommand("Refresh")

 

    </SCRIPT>

</body>

</html>

İşte esas noktaya geldik. Yukarı gördüğünüz OBJET tagları klasik bir SL uygulamasının bir HTML sayfaya yerleştirildiği taglardan farklı değil. Bir tek minik fark var o da OBJECT tagları içindeki HTML kodu! Hatırlarsanız tarayıcılar eğer OBJECT taglarını render edemezse içlerindeki HTML'i gösteriyorlardı. Bu gibi bir durumda Silverlight hedef makinede yüklü değilse bu demektir de tarayıcı OBJECT taglarını render edemeyecek bir OBJECT içerisindeki HTML'i kullanıcıya gösterecek.

[HTML]

      <img style="cursor:pointer;" ID="SLInstall" border="0" src="images/install.jpg" />

Yukarıdaki şekilde güzel bir resim Silverlight yüklü değilken gösterilecek resim olarak seçilebilir. Tabi bu resmin tasarımında kullanıcıya uygun mesajı bir metin olarak göstermeniz şart. Diğer yandan bu resim nesnesinin fare ile üzerine geldindiğinde el işareti gösterilmesi için uygun CSS'in kullanılması da gerekiyor. Son olarak bu IMG'ye bir de ID veriyoruz çünkü bu resme tıklandığında Silverlight Runtime yüklemesini başlatmalıyız!

[VBScript]

     <SCRIPT FOR="SLInstall" EVENT="onclick" LANGUAGE="VBScript">

      Dim objShell

      Dim lngReturn

 

      on error resume next

 

      set objShell = CreateObject( "WScript.Shell" )

 

        lngReturn = objShell.Run ("Silverlight.2.0.exe", 4, 1)

 

      set objShell = Nothing

      document.execCommand("Refresh")

 

    </SCRIPT>

Yukarıda bir VBScript kodu görüyorsunuz. Silverlight Runtime yüklemesine ait EXE dosyasının HTA ile aynı klasöre koyduktan sonra uygun zamanda yüklemeyi başlatmak şart. Bunun için bir Shell nesnesi yaratarak yüklemeyi başlatabiliyoruz. Yükleme bitince de sayfaya Refresh atıyoruz böylece kullanıcı yüklemeyi yaptıktan sonra ekranı kapatıp açmadan hemen arayüzü görebiliyor. Bu scriptin FOR ve EVENT özelliklerine bakarsanız bizim bir önceki adımda yarattığımız IMG nesnesinin onclick durumunda çalışacağını görebilirsiniz.

Diskten birşey çalıştırmak istersek?

Biliyorsunuz Silverlight'ın çalıştığı makinedeki diske erişimi yok. Bunun nedeni Silverlight'ın çalıştığı yer olan tarayıcı içerisindeki alandan yani bir web sitesinden de hedef makinedeki diske ulaşamıyor olmamız. HTA'lar bu konuda biraz farklılar. HTA'larda rahatlıkla diske erişebilirsiniz. Aslında bir önceki örnekte biz bu işi zaten yapmadık mı? HTA içerisinden gidip Silverlight Runtime'ı yüklemek demek harici bir EXE'yi çalıştırmak demek değil mi? Aynen öyle. Peki biz bunu Silverlight içerisinden nasıl yapabiliriz?

Silverlight içerisinde çıkıp VBScript'e ulaşıp, parametre göndererek VBScript ile de diske erişebiliriz.

[VBScript]

     <SCRIPT LANGUAGE="VBScript">

             sub Getir(byval address)

      Dim objShell

      Dim lngReturn

 

      on error resume next

 

      set objShell = CreateObject( "WScript.Shell" )

 

        lngReturn = objShell.Run (address, 4, 1)

 

      set objShell = Nothing

            end sub

    </SCRIPT>

Yukarıda gördüğünüz VBScript metodu tek bir parametre alarak Shell nesnesi yaratıp parametreden gelen adresi diskte çalıştırmaya çalışıyor. Bu durumda biz bu metodu Silverlight tarafından çağırıp uygun parametreyi verebilirsek işlem tamamlanmış demektir.

[VB]

    Private Sub btnSource_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSource.Click

        System.Windows.Browser.HtmlPage.Window.Invoke("Getir", New String("samples/Hedehodo.exe"))

    End Sub

İşte bu kadar basit. Silverlight'tan DOM'a çıkarak Getir adındaki metodumuzu çalıştırıp bir de String parametre gönderiyoruz. Söz konusu String parametre aslında çalıştırmak istediğimiz uygulamanın HTA dosyasının bulunduğu yere göre relative Uri'sini içeriyor. Böylece bu parametre VBScript'e aktarılacak, oradan da Shell üzerinden çalıştırılabilecek.

Süper değil mi?

Şimdi yapabileceklerinizi bir düşünün :) Silverlight uygulaması içerisinde yapabildiğiniz herşey bir anda bir DVD arayüzüne dönüştürülebiliyor. SaveFileDialog, OpenFileDialog, Socket bağlantılar!, Desktop moduna geçip makineye anında yükleme yapabilmek! ve daha bir çok Silverlight özelliğini bir anda kullanabilir hale geliyorsunuz! Bu gerçekten muhteşem!

Wednesday, September 02, 2009 5:39:03 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight | Silverlight 2.0 | Silverlight 3.0  | 
 Monday, June 01, 2009

Haziran ayı ile beraber yaz dönemi geldi. Tatile gidemeyenler olarak :) gelin bu dönemi yenilenme/gelişme dönemi olarak değerlendirelim :) Bu ayı "Silverlight Öğrenme Ayı" ilan ediyorum ;) ve 12 Seminerden oluşan Silverlight WebCast serimi duyuruyorum!

Silverlight'a Giriş - 8 Haziran, 21.00
Bu webinerde Silverlight nedir sorusuna cevap verirken mimari yapısına bakarak Silverlight dünyasına bir giriş yapacağız. Silverlgiht projeleri nasıl oluşturulur,nasıl yayınlanır, XAML nedir? ve "Neden Silverlight" gibi soruların cevapları da bu webinerde.
https://www.livemeeting.com/cc/usergroups/join?id=GFRH8M&role=attend

Silverlight ile Animasyonlar - 9 Haziran, 21.00
Animasyon mantığını kavrayacağımız bu webinerde ilk olarak Expression Blend arayüzüne bakarak animasyonlarının Blend tarafında nasıl oluşturulabildiğine göz atacağız. Sonra bu animasyonların programatik olarak yaratılmasını ve kontrollerini inceleyerek Silverlight tarafında bir animasyon uzmanı olacağız.
https://www.livemeeting.com/cc/usergroups/join?id=6GRJPM&role=attend

Layout Kontrolleri ve Dinamik Arayüzler, 10 Haziran, 21.00
Silverlight içerisinde istediğiniz görsel arayüzü oluşturabilmek için arayüz oluşturma esnasından kullanabileceğiniz Layout kontrollerini çok iyi tanımanız gerekir. Diğer yandan dinamik olarak tüm nesneleri yaratbilmeniz, bu nesnelerin birbiri ile konuşabilmesi ve projenizi doğru biçimde UserControl yapıları ile şekillendirmeniz de şart. İşte bu webinerde bu konulara değineceğiz.
https://www.livemeeting.com/cc/usergroups/join?id=PBRM8P&role=attend

Kontrol Şablonları ve VisualStateManager, 11 Haziran, 21.00
Standart kontroller arasında sıkışmayın ve kontrollerinizi tamamen baştan yaratın. Hatta bu tasarımları tekrar ve tekrar kullanın. Bu webinerde silverlight kontrollerinin şablonlarının değiştirilmesini, Template Binding mekanizmasını ve visual State Manager'ın kullanımını Custom State yapıları ile beraber inceleyeceğiz.
https://www.livemeeting.com/cc/usergroups/join?id=R8JSQH&role=attend

Silverlight içerisinde Veri Erişimi, 12 Haziran, 21.00
İster klasik web servisleri kullanın, ister WCF servisleri veya ister Socket üzerinden haberleşin hepsinin de kendine göre avantaj ve dezavantajları var. Gelin hepsinin de Silverlight tarafındaki detaylarını beraber inceleyip Silverlight uygulamalarımızı veri ile tanıştıralım.
https://www.livemeeting.com/cc/usergroups/join?id=GH9T5W&role=attend

Offline/Online/Desktop çalışma yapıları, 15 Haziran, 21.00
Silverlight 3.0 ile beraber uygulamalarınızı masaüstüne birkaç tıklama ile taşıyabilirsiniz. Peki hem masaüstünde hem webde hem online hem offline çalışırken tüm bu sistemi, verilerinizi nasıl kontrol edeceksiniz. Bu webinerde farklı çalışma yapılarını göz atarken verilerimizi IsolatedStorage içerisinde saklayacağız.
https://www.livemeeting.com/cc/usergroups/join?id=QTZH9R&role=attend

İş Uygulamaları Yaparken Silverlight, 16 Haziran, 21.00
Animasyonlar hoştur, güzeldir ama herşey değildir. DataGrid'ler, Comboboxlar, Calendar'lar bir araya girdiğinde hepsinden bir iş uygulaması arayüzü yaratıp kontrol etmeye ne dersiniz? Bu webinerde hep beraber bir iş uygulamasının ekranını hazırlayacağız.
https://www.livemeeting.com/cc/usergroups/join?id=BGN6BT&role=attend

RIA Services, 17 Haziran, 21.00
Farklı bir bakış açısı ile Silverlight uygulamalarınızdan veritabanına erişimine çocuk oyuncağına dönüştürmek ister misiniz? RIA Services sadece verinin taşınmasını değil aynı anda kendi kontrolleri ile düzenlenmesini de kolaylaştırıyor. Nasıl olacağını merak ediyorsanız bekleriz.
https://www.livemeeting.com/cc/usergroups/join?id=P9KQ6B&role=attend

Silverlight projelerinde SEO, 18 Haziran, 21.00
Arama motorlarına dair optimizasyonların çoğumuz için önemli. Silverlight projelerinde özellikle asenkron veri erişimi nedeniyle söz konusu veriye arama motorları ulaşamıyor. Peki ya bir çözümü varsa? Tabi ki o çözümü paylaşma vakti.
https://www.livemeeting.com/cc/usergroups/join?id=Q6H2G7&role=attend

Video Aşkına! Canlı/Cansız Yayın, 19 Haziran, 21.00
İnternette televizyoz izlemek veya cansız kayıtları yayınlamak, amacınız ne olursa olsun video konusunda Silverlight çok güçlü. Bu webinerde Silverlight ile canlı yayın, Media Services ayarları, Adaptive Streaming, cansız yayın ve Video Player hazırlanması gibi konulara değineceğiz.
https://www.livemeeting.com/cc/usergroups/join?id=BNPK36&role=attend

DeepZoom Uygulamaları, 22 Haziran, 21.00
Yaklaştıkça daha çok detay görmek isteyenlerin tarzı DeepZoom uygulamalarını hızlı bir şekilde geliştirmenin yanı sıra sıfırdan DeepZoom uygulamalarını yazmak, uygulamaları özelleştirmek ve veri bağlantısı yaparak dinamik DeepZoom projeleri yaratmak isteyenler bu webineri kaçırmasın.
https://www.livemeeting.com/cc/usergroups/join?id=BZFCH9&role=attend

Tarayıcı Entegrasyonu, 23 Haziran, 21.00
Silverlight ile tarayıcı arasındaki ilişkiyi inceleyeceğimiz bu webinerde Silverlight tarafındaki C#/VB kodunuz ile DOM entegrasyonunun yanı sıra tam ekran uygulamaları, ön yükleme ekranlarını ve RunTime yükleme ekranlarını özelleştirmeye göz atacağız.
https://www.livemeeting.com/cc/usergroups/join?id=3GZKMH&role=attend

Webinerlerle ilgili güncel gelişmeleri ve hatırlatmaları isterseniz twitter üzerinden beni takip ederek edinebilirsiniz. Herkese faydalı olması dileği ile ;)

P.S.: Unutmadan :) Mümkünse bu seriyi bloglarınızda, üye olduğunuz mail gruplarda paylaşabilirseniz çok sevinirim. "Silverlight'ı nereden öğrenebiliriz" şeklinde özellikle Anadolu'nun farklı köşelerinden mailler alıyorum. 12 seminerlik bu seriyi düzenlememin en büyük nedeni de budur. En azından bu sefer "haberimiz yoktu" durumlarının oluşmaması için duyuru konusunda desteğini rica ediyorum. Ne kadar çok kişi faydalanırsa o kadar mutluluk verci olur benim için, hepimiz için.

Monday, June 01, 2009 10:03:54 AM (GTB Standard Time, UTC+02:00)  #    Comments [21]   Silverlight 2.0 | Silverlight 3.0  | 
 Wednesday, April 01, 2009

2009 Silverlight MVP'liği!Geçen yıl bugünlerde sizlerle ASP.NET alanında MVP olmamın müjdesini paylaşmıştım. Bu süreçte şöyle kabaca baktığımda son bir yılda 300'ü aşkın blogpost, 100'ü aşkın teknik makale ile bildiklerimi paylaşmaya çalışırken seminerler ile de hesabıma göre 15.000 kişiye ulaşmışım. İtiraf etmek gerekirse "önümüzde yılda daha fazlasını yapacağım" gibi bir iddiada bulunamam :) ama aynı tempo devam edecek diyebilirim.

Silverlight MVP'si oldum!

Bu yazıyı yazmamın esas nedeni sanırım belli oldu :) 2009 yılında da MVP ödülüne layık görüldüm. Bu sefer ödülü aldığım alan Silverlight oldu. Biraz şanslı bir olarak dünyadaki ilk Silverlight MVP'lerindenim çünkü bu uzmanlık alanı daha yeni açıldı :) Ortadoğu-Afrika bölgesinde ise en azından bu dönemde aldığım duyumlara göre tek Silverlight MVP'si olmuşum. Bu durum özellikle bölgede Türkiye'nin önderliği adına, kendi kendime mutlu olduğum bir detay oldu diyebilirim.

Hepinize bu süreçte gösterdiğiniz destek için çok teşekkür ediyorum.

Wednesday, April 01, 2009 10:53:32 PM (GTB Standard Time, UTC+02:00)  #    Comments [32]   Silverlight | Silverlight 2.0 | Silverlight 3.0  | 
 Monday, March 16, 2009

Dün süper bir mail aldım :) Sevgili Volkan Albayrak blogumu takip ederken tüm Silverlight makalelerimi de bir E-Kitap olarak derlemiş. Gerçekten şaşırdım... E-Kitap toplam 300 sayfayı geçmiş. Hemen aşağıdaki linkten kitabı indirebilirsiniz.

Silverlight E-Kitap - 16032009_1.pdf (4.15 MB)
Silverlight E-Kitap - 16032009_1.xps (5.55 MB)

Çok yakında bir başka kitapçık sürprizi ile karşınızda olacağım ;) Volkan'a buradan tekrar çok teşekkürler ;)

Monday, March 16, 2009 11:09:02 PM (GTB Standard Time, UTC+02:00)  #    Comments [7]   Silverlight 2.0  | 
 Sunday, March 15, 2009

Bugün sizlerle ufak fakat bence bir o kadar da değerli bir ip ucu paylaşacağım. Üzerinde çalıştığımız projelerden birinde hiç hoş olmayan bir sorun ile karşılaştık. Aslında sorunun nedeni Visual Studio ve Expression Blend içerisinde Silverlight projeleri düzenlenirken söz konusu projeler içerisindeki UserControl'lerin PageLoad ve Init kodlarının tasarım aşamasında da çalıştırılıyor olması. Ne demek istiyorum?

Örneğin Detay adında bir UserControl hazırladınız ve bunu da Ana adında bir UserControl'ün içerisine yerleştirdiniz. Bu yerleştirme işlemini de XAML içerisinde namespace tanımlayarak yaptınız ki tasarımcı Blend içerisinde söz konusu UserControl'ü rahatlıkla düzenleyebilsin. Özetle UserControl'lerinizin XAML kodları aşağıdaki gibi olsun;

[Ana.xaml]

<UserControl x:Class="SilverlightApplication27.Ana"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300" xmlns:SilverlightApplication27="clr-namespace:SilverlightApplication27" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBlock x:Name="Metin" Text="DENEME"/>

        <SilverlightApplication27:Detay Margin="83,61,217,139" d:LayoutOverrides="VerticalAlignment"/>

    </Grid>

</UserControl>

Gördüğünüz üzere diğer UserControl'ü almak üzere XAML NameSpace tanımı yapılmış ve ekrana da Detay adındaki UserControl yerleştirilmiş.

[Detay.xaml]

<UserControl

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

    x:Class="SilverlightApplication27.Detay"

    d:DesignWidth="100" d:DesignHeight="100">

 

    <Grid x:Name="LayoutRoot">

        <Grid/>

        <TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap" x:Name="Metin"/>

    </Grid>

</UserControl>

Yukarıdaki şekli ile tanımladığımız Detay adındaki UserControl içerisinde de sadece bir TextBlock bulunuyor. Detay'ın kodunda bir şekilde Page.Load durumunda ekrandaki kontrollere veri bağlarsanız tüm bu işlemlerin Expression Blend içerisinde Ana.XAML açıldığında çalıştırıldığını göreceksiniz. Sonuç itibari ile Ana.XAML içerisine Detay kontrolünü koyduğumuz için Blend Ana adındaki UserControl içerisinde göstermek üzere Detay'ı çalıştırıp doğrudan sahneye yerleştiriyor. "Ne kadar güzel?" dediğinizi duyar gibiyim :) Aslında durum gerçekten hoş. Bu sistem sayesinde ana bir kontrole yerleştirilmiş UserControl'ler kendi Page.Load'ları da çalıştırılarak gerçek çalışır hallerindeki görüntüleri ile tasarımcıya gösteriliyorlar. Fakat ya Page.Load'da çalışan kod uygulamanın bir web sunucu üzerinden host edilmiş olmasını gerektiriyorsa? İşte tam da o noktada Blend çatlıyor :) doğal olarak....

Peki ne yapmak gerek?

Çözüm basit. Bizim UserControl'lerin kendilerinin Blend'de mi yoksa gerçekten çalışma zamanında da çalıştırıldıklarını algılamaları ve ona uygun işlem yapmaları gerekiyor. Örneğin bizim detay adındaki UserControl Blend tarafından açıldığında kendi içindeki TextBlock'e "DENEME" yazarken, gerçekten açıldığında ise sunucudan veri çekmeli.

[VB]

        If Not ComponentModel.DesignerProperties.GetIsInDesignMode(Me) Then

            MyServis.GetNewsFromBlogAsync()

        Else

            textBlock.Text = "Blend içerisinde blog ile bağlantı kurulamaz."

        End If

Yukarıda gördüğünüz kod ile herhangi bir UIElement'in Blend içerisinde Design modunda açılıp açılmadığını öğrenebiliyorsunuz. Örneğin bizim örneğimizde normal şartlarda web servisinden veri çeken kod eğer Blend içerisinde açılmış ise veri çekmek yerine uygun yere uygun mesajı yazıyor. Farklı örneklerde tasarımcıya yardımcı olmak amacı ile DataBind ettiğiniz kontrolleri belki de tasarımcı için kod içerisinde veri yaratıp databind edebilirsiniz. Oysa uygulama çalıştığında gerçek veri kaynağına yönelebilir.

GetIsInDesignMode metoduna parametre olarak herhangi bir UIElement verdiğinizde size Design modunda olunup olunmadığına dair Boolean bir değer döndürüyor.

Hepinize kolay gelsin ;)

Sunday, March 15, 2009 9:31:23 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Monday, March 09, 2009

Blogdan da duyurduğum üzere geçen hafta sonunu Eskişehir'de geçirdik. Yine çok zevkli bir etkinlikte iki gün boyunca yoğun bir tempo ile birçok konuya değindik. Silverlight, Oyun Programlama, WPF, LINQ, ASP.NET 3.5 vs derken yoğun bir bombardımanın altında tüm katılımcıların da yüzlerinde memnuniyetin izlerini görüyor olmak gerçekten çok sevindirici oldu. Umarım katılan herkes için olabildiğince faydalı ve efektif geçmiştir hafta sonu.

Osmangazi Üniversitesi, INETA Eskişehir Seminerleri
Osmangazi Üniversitesi, INETA Eskişehir Seminerleri

Aktivitenin organizasyonundaki katkısından dolayı sevgili MSP, Selim Özenç'e buradan çok teşekkür ediyorum. Ayrıca beni yalnız bırakmama konusundaki ısrarlı duruşu ile :) sevgili MSP, Ali Uğur Çakmak'a da çok teşekkürler. Tabi organizasyonda emeği geçen tüm diğer arkadaşları da kesinlikle unutmadım, özellikle, büyük ihtimal yakında blogdan da sizlerle paylaşacağım bir röportaj maceramız oldu ki :) dillere destan.

Eskişehir'e buradan en kısa zamanda tekrar görüşmek üzere diyerek seminerlere katılan tüm arkadaşlara çok teşekkür ediyorum.

Monday, March 09, 2009 2:08:32 PM (GTB Standard Time, UTC+02:00)  #    Comments [9]   AJAX | ASP.NET 3.5 | Silverlight 2.0 | WPF  | 
 Monday, March 02, 2009

Hafta sonu Eskişehir'deyiz! Osmangazi Üniversitesi Fen Edebiyat Fakültesi (F5 Blok) Konferans Salonu'nda iki günlük bir program ile zevkli bir hafta sonu geçirmek isteyen herkesi bekliyoruz. Etkinlik planını aşağıdaki görselde bulabilirsiniz.

INETA Eskişehir Hit Afişi
INETA Eskişehir Hit Afişi

Etkinlik serisi tamamen halka açık ve herhangi bir şekilde kayıt olmanız gerekmiyor. Görüşmek üzere...

Monday, March 02, 2009 10:29:32 AM (GTB Standard Time, UTC+02:00)  #    Comments [9]   AJAX | ASP.NET 3.5 | LINQ | Silverlight 2.0 | WPF  | 
 Sunday, March 01, 2009

Bugün Microsoft Oyun Turu'nun son ayağında Ankara Bilkent ve ODTÜ'deydik. XNA ve Silverlight ile Oyun programlama konularını işlediğimiz seminerlerde sevgili XNA uzmanımız Engin Yıldız ile beraber üniversiteler arası kısa birer maraton ile oturumları değiştirerek bir günde iki üniversitede etkinlik yapmayı başardık.

Ankara, ODTÜ, Silverlight ile Oyun Programlama Seminerim.
Ankara, ODTÜ, Silverlight ile Oyun Programlama Seminerim.

Etkinlikteki katkılarından dolayı MSP'lerimiz Ali Uğur Çakmak, Alper Özçetin, Cemil Uzun, Murat Alıravcı'ya çok teşekkür ediyorum.

Sunday, March 01, 2009 10:19:01 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Friday, February 27, 2009

Son iki gündür Erzurum, Atatürk Üniversitesi'ndeydim. Silverlight, WPF, AJAX, LINQ konularına değindiğimiz ikin günlük bir serinin sonunda minik bir de DreamSpark dağıtımı yaptıktan sonra iki saatlik gecikme ile uçağıma binip dönüp dolaşım yine :) İstanbul'a döndüm. Oturumlarda şaşkınlık ile karışık bir tepkisizliğin hakimiyetine karşın aralarda aldığım tepkiler çok sıcaktı. Anadolu'daki üniversitelerin havası gerçekten çok farklı, Erzurum'da da bunu yaşadım. Gençlerin gözlerindeki ışıltı ve kaba tabiri ile doğu bölgelerindeki bu gibi etkinliklere yönelik ihtiyacın tam olarak giderilememesi tezatı beni gerçekten üzüyor. Olanaklar el verdikçe Anadolu üniversitelerine gidiş sevdamı ben de bu şekilde tatmin etmeye çalışıyorum :)

Erzurum, Atatürk Üniversitesi Seminerlerim
Erzurum, Atatürk Üniversitesi Seminerlerim

Tabi ki yine teşekkür etmem gereken onlarca dost var Erzurum'dan. Yüksel hocama ve afacana buradan selamlarımı gönderdikten sonra :) öğrenci kardeşlerimden de Mehmet Keklik'e etkinliğe vesile olması ve organizasyondaki katkısı için çok teşekkür ediyorum. Umarım seneye taptaze ve daha dolu bir etkinlik ile tekrar buluşuruz ;)

Friday, February 27, 2009 2:01:14 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   AJAX | ASP.NET 3.5 | LINQ | Silverlight 2.0 | WPF  | 
 Wednesday, February 25, 2009

Silverlight 2.0 uygulamaları hazırladığınızda sunucu tarafına yükleme işlemini yaptığınız gibi XAP dosyanızın büyüklüğüne göre Silverlight Runtime tarafından otomatik olarak bir ön yükleme sistemi gösterilecektir. Kullanıcılar sitenizi ziyaret ettiğinde XAP dosyasının istemciye inme sürecini gösteren bu yükleme göstergelerini isterseniz rahatlıkla özelleştirebilir ve değiştirebilirsiniz. Tabi tüm bunları XAP dosyanız dışında daha XAP dosyası yüklenmeden bir şekilde yine Silverlight ile yapabiliyor olmamız gerek.

Silverlight ile beraber gelen standart ön yükleme animasyonu.
Silverlight ile beraber gelen standart ön yükleme animasyonu.

Aslında bu yükleme ekranını değiştirirken belki de eski Silverlight 1.0 günlerini biraz hatırlayacaksınız. XAP dosyası yüklenmeden önce bu şekilde bir yükleme animasyonu gösterebilmemiz için animasyonu oluşturacak ayrı bir XAML ve download durumunu kontrol edecek ayrı bir JavaScript koduna ihtiyacımız var.

Görsel kısmı halledelim...

İlk olarak ön yükleme işlemini gösterecek olan animasyonu ve görsel öğeleri düzenleyelim. Tüm bu görsel öğelerin tabi ki XAP dosyası dışında olması gerek. Bu durumda tek bir alternatif kalıyor, o da hazırlayacağımız tüm XAML kodunun harici bir dosya olarak sunucuda tutulması. Eğer Visual Studio ile bir Silverlight projesi yarattıysanız büyük ihtimal ile yanında bir de ASP.NET siteniz olacaktır. İşte tam da o ASP.NET sitesine bir XAML dosyası eklemeliyiz. Bunu ister Visual Studio içerisinde yapın ister Expression Blend içerisinde, önemli olan projeleri karıştırmayarak XAML dosyasını kesinlikle web sitesinde tarafında bir dosya olarak yaratmanız.

Maalesef bu noktadan sonra Expression Blend bize pek yardımcı olamayacak çünkü Web sitesindeki XAML dosyasının tam olarak ne tür bir projeye ait olduğunu algılayamayacak. O nedenle çoğu kodu elle yazmak zorunda kalacağız.

[XAML]

<StackPanel Orientation="Horizontal" xmlns="http://schemas.microsoft.com/client/2007"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        x:Name="LayoutRoot" Background="White" Height="104">

  <Rectangle Height="33" x:Name="Progress" Fill="#FF00FF00"/>

  <TextBlock Height="18" Text="Yükleniyor..."/>

</StackPanel>

Yukarıdaki kodumuz bizim önyükleme ekranının tasarımı olacak. Tasarım oldukça basit; bir StackPanel içerisinde TextBlock ile Rectangle kullanarak işi çözüyoruz. Tabi siz örneklerinizde farklı tasarımlar kullanabilirsiniz. Bizim örneğimizde ekranda sürekli "Yükleniyor..." yazacak ve yanında da 0 pikselden 100 piksele doğru genişleyecek olan bir Rectangle yer alacak. Böylece kullanıcıya standart görselden farklı bir şekilde XAP dosyasının  yüklenmesine ait süreci göstermiş olacağız.

Bu kod içerisinde en önemli nokta Rectangle nesnesinin adının Progress olması. İleriki aşamalarda yazacağımız JavaScript kodları ile bu nesneyi bularak gerekli değişiklikleri yapacağız.

Ortamı hazırlayalım...

Silverlight uygulamamızı sayfaya yerleştirdiğimiz OBJECT tagları içerisinde bazı ek parametreler tanımlamamız gerekiyor. Böylece Silverlight Runtime XAP dosyasının indirirken nerede ve nasıl bir progress göstermesi gerektiğini bilebilecek. Gelin uygun bir OBJECT tagına göz atalım.

[XAML]

        <object id="SL" data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">

            <param name="splashscreensource" value="Scene1.xaml"/>   

<param name="onSourceDownloadProgressChanged" value="onSourceDownloadProgressChanged" />

            <param name="source" value="ClientBin/SilverlightApplication5.xap"/>

            <param name="onerror" value="onSilverlightError" />

            <param name="background" value="white" />

            <param name="minRuntimeVersion" value="2.0.31005.0" />

            <param name="autoUpgrade" value="true" />

            <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

            </a>

        </object>

Gördüğünüz üzere kod içerisinde kalın olarak yazılı üç farklı nokta var. Bunlardan birincisi OBJECT taglarına vermiş olduğumuz ID olan SL ismi. OBJECT taglarımızı bu şekilde isimlendirmek zorundayız çünkü birazdan JavaScript ile bu OBJECT taglarına yani Silverlight uygulamamıza ulaşmamız gerekecek. Son olarak ayarlamamız gereken iki tane de parametre bulunuyor. Bu parametrelerden ilki XAP dosyası yüklenmeden önce ve yüklenirken gösterilecek olan XAML dosyamızın tam yolu olacak. splashscreensource adındaki bu parametreye biz örneğimizde basit bir şekilde Scene1.xaml değerini verdik. Bu dosya içerisinde bir önceki adımda yazdığımız ve içerisinde Progress Rectangle'ının bulunduğu XAML yer alıyor. Son olarak onSourceDownloadProgressChanged event'ına da yine aynı isimde bir JavaScript event-listener ekleyerek XAP dosyasının download durumu ile ilgili değişiklikleri takip edebiliyoruz. Gelelim yazacağımız bu JavaScript event-listener koduna...

Biraz da JavaScript...

Bir önceki adımda hazırladığımız OBJECT tagının parametrelerinden birinde onSourceDownloadProgressChanged adında bir event-listener tanımlamıştık. Bu event-listener içerisinde ilk olarak sayfamızdaki OBJECT tagını ve içerisindeki Silverlight uygulamamızı bulmamız gerekiyor. Bu yapı Silverlight 1.0 günlerinden hatırladığımız bir yapı. Aşağıdaki kodumuzda SL adını verdiğimiz OBJECT taglarını bulduktan sonra içeriğine bakarak findName ile Progress adındaki Rectangle'ımızı bulmuş olduk.

[JavaScript]

        function onSourceDownloadProgressChanged(sender, eventArgs) {

            var Progress = document.getElementById("SL").content.findName("Progress");

            if (eventArgs.progress)

                Progress.Width = eventArgs.progress * 100;

            else

                Progress.Width = eventArgs.get_progress() * 100;

        }

Son olarak söz konusu Rectangle'ın genişliğini elimizdeki yükleme durumuna göre değiştireceğiz. Yükleme durumunu bize 1 üzerinden decimal olarak verecek olan şey tarayıcı tipine göre ya bir Property ya da bir metod olacağı için bir IF kontrolü ile onu de kontrol ederek gerekli işlemi yapıyoruz.

Artık Silverlight Runtime ile beraber gelen ön yükleme animasyonlarından kurtulabilir ve kendi özgür iradeniz ile :) kendi tasarımlarınızı kullanabilirsiniz.

Hepinize kolay gelsin.

Wednesday, February 25, 2009 12:53:01 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, February 22, 2009

Son iki gündür sevgili Uğur Umutluoğlu ile Ankara, Bilkent Üniversitesi'ndeyiz. Toplam iki gün süren ve 6 oturumdan oluşan bir seri ile birçok konuya değindik. WPF, WCF, LINQ, C# 3.0, Silverlight, ASP.NET 3.5 SP1 başlıklarına sahip oturumların hepsinde de muhteşem ilgili bir kitle bulunduğunu itiraf etmeliyiz.

Bilkent Üniversitesi, Ankara, Silverlight Oturumum
Bilkent Üniversitesi, Ankara, Silverlight Oturumum

Oturumlarımızdan birini de LAB çalışması olarak gerçekleştirdik ve Silverlight seminerinde öğrendiklerimizi Silverlight ile bir oyun geliştirerek pekiştirdik. LAB çalışması benim neredeyse etkinlik içerisinde en sevdiğim bölüm oldu. "Üretmenin" zevkini herkesin gözlerinde gördüm.

Silverlight Lab Çalışması
Silverlight Lab Çalışması

Buradan teşekkür etmem gereken o kadar çok kişi var ki :) Sevgili MSP'lerimiz Ali Uğur Çakmak, Alper Özçetin'a çok teşekkürler. Ayrıca BTS ve ACM'deki herkese teşekkürler. Süper bir hafta sonu geçirdim, "dayının yeri"ni hala unutamıyorum :)

Sunday, February 22, 2009 10:29:12 PM (GTB Standard Time, UTC+02:00)  #    Comments [6]   ASP.NET 3.5 | LINQ | Silverlight 2.0 | WCF | WPF  | 
 Friday, February 20, 2009

Bugün Kocaeli Üniversitesi'ndeki yazgelistir.com seminer serisinin ikincisini gerçekleştirdik. Sevgili Burak Batur ile beraber SharePoint ve Silverlight oturumlarımızla katılımcılara ilginç duygular yaşattığımızdan eminim :) Silverlight'ı görünce şaşıranlardan tutun SharePoint'i görünce "Ne gerek var ASP.NET öğrenmeye" :) diyenlere kadar ilginç bir manzara içerisinde bitirdik seminerlerimizi diyebilirim.

Kocaeli Üniversitesi, Silverlight Oturumum
Kocaeli Üniversitesi, Silverlight Oturumum

Tüm katılan arkadaşlar ve MSP'miz Gökhan Gülbiz'e buradan çok teşekkürler. Ayrıca organizasyonda emeği geçen tüm genç kardeşlerimi de buradan kutluyorum. Çok başarılı bir iş çıkardınız ;) Umarım başka bir zamana daha uzun oturumlar ile daha da detaylara girebiliriz.

Friday, February 20, 2009 10:02:58 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Wednesday, February 18, 2009

Bugün Silverlight 2.0 Runtime için yeni bir update çıktı. İstemci tarafında Silverlight Runtime kendini otomatik olarak update edecek şekilde ayarlı geldiği için çoğu kullanıcı bu değişikliği fark etmeyecektir fakat özellikle Developer tarafındaki Runtime'ın farklı olduğunu düşünürsek bu konuya dikkat etmenizde fayda var.

Silverlight 2.0 Developer Runtime (2.0.40115.0)

Gelen update ile beraber sadece bazı buglar kapatıldığı için yukarıdaki yükleme haricinde Visual Studio için herhangi bir ek yükleme vs yapmanız gerekmiyor.

Wednesday, February 18, 2009 10:26:38 PM (GTB Standard Time, UTC+02:00)  #    Comments [7]   Silverlight 2.0  | 
 Sunday, February 08, 2009

Haber aslında açık ve net :) TRT'nin tüm televizyon ve radyo kanalları Silverlight ile yayında. Hali hazırda uzun süredir Windows Media Services ile yayın yapan TRT arayüz olarak MediaPlayer'a bağımlı iken artık Silverlight ile çok daha hareketli ve zengin bir kullanıcı deneyimi sağlayabiliyor. Diğer yandan ASP.NET tarafında yazılım geliştiren bir ekip için Silverlight tarafına geçiş de bir o kadar kolay oluyor tabi ki.

Daha fazla konuşmayarak yorumu sizlere bırakıyorum ;)

www.trt.com.tr sayfasında üst köşedeki "Canlı Yayın" linkine tıklamanız yeterli!

Sunday, February 08, 2009 2:47:38 AM (GTB Standard Time, UTC+02:00)  #    Comments [21]   Silverlight 2.0  | 
 Friday, February 06, 2009

Her zaman söylerim; web yazılım dünyası "grafik tasarım yapmak zorunda kalan yazılımcıların" kurbanı oluyor :) Kimseyi suçlamıyorum çünkü çok açık ve net bir şekilde aslında hiçbir yazılımcının grafik tasarım da yapmak zorunda kalmaktan memnun olmadığını biliyorum. Özetle kimse isteyerek yapmıyor. Bazen de yazılımcının bu işi üstlenmemesi veya proje gereği böyle bir "grafik tasarım" ihtiyacı yokmuş gibi davranılması sonucu bu sefer de ortaya çıkan ürün gerekli değeri görmeyebiliyor. Örnek mi istiyorsunuz? :)

Bir yazılımcıdan arayüz tasarımı!
Bir yazılımcıdan arayüz tasarımı!

Yukarıda görmekte olduğunuz program bir MultiPoint Paint yazılımı. Yani özetle bir bilgisayara birden çok fare bağlayarak birden çok kişinin aynı anda çizim yapabilmesini sağlıyor. Özellikle İlköğretim seviyesinde öğrenci başına bir bilgisayar düşmediğini düşünürsek güzel bir alternatif olabilir. MultiPoint programlama ile ilgili blogumda gerekli makaleleri bulabilirsiniz.

Neyse konumuza dönelim. Gördüğünüz üzere yazılımın işlevsellik anlamında bir sorunu yok. Her şey açık ve net. Değil mi? Peki aynı yazılımı bir de bir grafik tasarımcının elinden geçtikten sonra inceleyelim ne dersiniz?

Bir grafik tasarımcının arayüz tasarımı...
Bir grafik tasarımcının arayüz tasarımı...

Nereden nereye? Değil mi? Gerçekten arada büyük fark var. Aslına bakarsanız yukarıdaki yazılım ile aşağıdaki arasında işlevsellik veya kod açısından hiçbir fark yok! Bahsini ettiğimiz yazılım bir WPF uygulaması ve tasarımı Expression Design ile yapıldıktan sonra hali hazırda programlanmış olan WPF uygulamasına tasarımın aktarılması yeterli oldu. Bu süreçte arka planda yazılımcının yazmış olduğu hiçbir kod değiştirilmedi!

Demek ki neymiş? Görsel tasarım gerçekten çok önemli. Görsel tasarım, Kullanıcı deneyimi tasarımı ve programlama konuları bir projede topluca düşünülmesi gereken konular ve maalesef ki bu konuların ayrı uzmanlar tarafından değerlendirilmesi de şart!

İsterseniz yukarıdaki projeye geri dönelim ve süreci nasıl işledi biraz da ondan bahsediyim. İlk olarak ilk görselde gördüğünüz yazılım bir yazılımcı tarafından kodlanıyor ve arayüz görüldüğü üzere rezalet. Sonrasında tasarımcı bu rezalet arayüz için Expression Design ile alternatif bir tasarım hazırlıyor. Bir sonraki adımda ise hem programlama tarafına hem de kullanıcı deneyimi tarafına hakim bir başka uzman hazırlanan görsel tasarımı yazılıma uyguluyor! Bu uygulayan kişi ise Expression Blend kullanarak eldeki hazır programlanmış projeyi açarak tasarım öğelerini düzenliyor. Sonuçta ortaya süper bir yazılım çıkıyor diyebiliriz.

Sizlerin de elinde bu gibi karşılaştırmalı örnekler varsa lütfen yorumlarda paylaşın ;)  

Friday, February 06, 2009 4:55:28 PM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight 2.0 | WPF  | 
 Thursday, February 05, 2009

Yarışmayı kazananları büyük bir sürpriz bekliyor! Sanırım bir yazıya böyle başlamak epey garip olsa gerek fakat maalesef şu anda sürpriz olduğu için sizlerle paylaşamayacağım fakat yarışmanın birincisini bekleyen süper bir sürpriz var! Peki nedir Mobil-Star? Hemen aşağıdaki adresten web sitesini ziyaret ederek inceleyebilirsiniz.

www.mobil-star.net

Siteyi tamamen Silverlight 2.0 ile yaptığımızı özellikle belirtmek isterim :) Hepiniz iyi şanslar ;) Bakalım Star siz misiniz?

Thursday, February 05, 2009 4:38:13 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, February 03, 2009

Silverlight projeleriniz büyüdükçe projenin bazı bölümlerini sonradan istemci tarafına aktarmayı daha uygun bir seçenek olarak görebilirsiniz. Bu gibi durumlarda acaba ayrı bir XAP dosyası yapsak da onu haricen istemciye yüklesek diye düşünürseniz maalesef söz konusu XAP dosyasını kendi kodlarınız ile ZIP şeklinde açmanız ve içerisindeki Manifest.xml'i yine kendi kodunuz ile okuyup tek tek DLL'leri yüklemeniz gerekecektir. Bu konuda detaylı bir makaleye buradan ulaşabilirsiniz.

Bu zorluklarla uğraşmadan hızlı bir şekilde belki de sadece bir UserControl'ü haricen sonradan yüklemek istiyorsanız aslında çok daha pratik ve hızlı bir yöntem de kullanılabilir. Bu yönteme sadece UserControl'ler değil harici olarak yazılan sınıflar da dahil. Gelin daha fazla teorik konuşma yerine bir örnek üzerinden ilerleyelim.

Haricen yüklenecek içeriği hazırlayalım....

İlk olarak ana Silverlight uygulamamıza sonradan yüklenecek olan içeriği hazırlayalım. Bunun için Visual Studio içerisinde "File / New Project" dedikten sonra "Silverlight" seçeneği altındaki "Silverlight Class Library" proje tipini seçiyoruz. Bu proje tipinde doğrudan tüm proje içeriği bir DLL içerisine konacak fakat bu DLL ayrıca bir XAP dosyası içerisinde sıkıştırılmayacak. Böylece biz de Silverlight ile istemci tarafında bir XAP dosyası açmak veya Manifest ile uğraşmak zorunda kalmayacağız.

Normal şartlarda Silverlight Class Library projesi yarattığınızda proje içerisinde sadece bir CS veya VB dosyası görebilirsiniz. Oysa bu projelere de isterseniz XAML dosyaları ile beraber UserControl'ler eklenebilir. Projenize sağ tuş tıklayarak Solution Explorer içerisinden "Add New Item" demeniz ve gelen seçeneklerden de "Silverlight User Control"ü seçmeniz yeterli olacaktır. Artık isterseniz bu projeyi Blend içerisinde de açıp normal bir Silverlight projesindeki gibi animasyonlar vs kullanabilirsiniz.

Örnek olarak projemize bir resim dosyası ekleyerek UserControl'ümüz içerisinde de onu gösterebilir. Unutmayın ki resim dosyasını projeye "Add Existing Item" diyerek eklerseniz artık bu resim de DLL'inizin içerisine dahil edilecektir.

[XAML]

<UserControl x:Class="SilverlightClassLibrary1.SilverlightControl1"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Image Margin="71,47,97,122" Source="Forest.jpg"/>

    </Grid>

</UserControl>

Yukarıdaki şekli ile UserControl'ümüz hazır olduktan sonra projemizi Build ederek DLL'imizi yaratmış oluyoruz. Bu DLL'i bir sonraki adımda yaratacağımız Silverlight projesinin XAP dosyası ile aynı konuma koyabilirsiniz. Silverlight projemiz içerisinden bu DLL'i istemciye asenkron olarak download ederek sahneye DLL içerisindeki UserControl'ü yükleyeceğiz.

Gelelim Silverlight projemize...

Tertemiz bir Silverlight projesi yarattıktan sonra proje ile beraber gelen ASP.NET sitesi içerisinde ClientBin klasörüne bir önceki adımda yarattığımız DLL dosyasını kopyalayalım. Böylece projeyi Build ettiğimiz aynı konuma otomatik olarak kopyalanacak olan XAP dosyası üzerinden DLL'e de rahatlıkla ulaşabiliriz.

Yeni Silverlight projemizin ana Page.XAML dosyasına bir Button ve bir de Canvas ekleyelim. Böylece düğmeye basıldığında harici DLL'i yükleyecek ve DLL içerisindeki UserControl'ümüzü de Canvas içerisine yerleştireceğiz.

[XAML]

<UserControl x:Class="SilverlightApplication5.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Button x:Name="btnTikla" Height="19" HorizontalAlignment="Right" Margin="0,0,18,17" VerticalAlignment="Bottom" Width="89" Content="Button"/>

        <Canvas x:Name="Icerik" Margin="13,13,18,54"/>

    </Grid>

</UserControl>

Düğmeye tıklandığı anda hemen bir WebClient yaratarak download işlemimizi başlatalım.

[VB]

Private BirAssembly As System.Reflection.Assembly

 

Public Sub New()

    InitializeComponent()

    AddHandler Me.btnTikla.Click, AddressOf btnTikla_Click

End Sub

 

Private Sub btnTikla_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)

    Dim Yukleyici As New WebClient()

    AddHandler Yukleyici.OpenReadCompleted, AddressOf Yukleyici_OpenReadCompleted

    Dim Yol As String = System.Windows.Application.Current.Host.Source.AbsoluteUri.Replace("SilverlightApplication5.xap", "SilverlightClassLibrary1.dll")

    Yukleyici.OpenReadAsync(New Uri(Yol, UriKind.Absolute))

End Sub

[C#]

        System.Reflection.Assembly BirAssembly;

 

        public Page()

        {

            InitializeComponent();

            this.btnTikla.Click += new RoutedEventHandler(btnTikla_Click);

        }

 

        void btnTikla_Click(object sender, RoutedEventArgs e)

        {

            WebClient Yukleyici = new WebClient();

            Yukleyici.OpenReadCompleted += new OpenReadCompletedEventHandler(Yukleyici_OpenReadCompleted);

            string Yol = System.Windows.Application.Current.Host.Source.AbsoluteUri.Replace("SilverlightApplication5.xap", "SilverlightClassLibrary1.dll");

            Yukleyici.OpenReadAsync(new Uri(Yol, UriKind.Absolute));

        }

Yukarıdaki kodu dikkatli incelemek gerekirse ilk adımda en üstteki Assembly tipindeki BirAssembly adındaki değişkenimizi açıklamak gerekecek. Kodumuz sunucudan bir DLL indirecek ve içindeki UserControl'ü sahneye koyacak. Aslında DLL'i indirdikten sonra içerisinden UserControl1 sınıfından bir instance alarak sahneye koyacağız. Eğer bu işlemi yaptıktan sonra başka instance'lara da ihtiyacımız olursa tekrar DLL'i indirmemek için eldeki Assembly'yi bir değişken olarak tutmak daha mantıklı olacaktır. O nedenle en üstteki BirAssembly değişkenimiz şimdiden yerini almış durumda.

Button'umuzun Click koduna baktığımızda bir WebClient yarattığımızı ve OpenReadCompleted event listener'ını da başka bir koda bağladığımızı görebilirsiniz. Sunucudan bir dosya indireceği ve indirme işlemi bittiğinde de başka işler yapacağız. O nedenle bu event'ları yakalayabiliyor olmak çok önemli. İsteyenler WebClient'ın DownloadProgressChanged event'ını da yakalayarak download durumu ile ilgili yüzde üzerinden ne kadarının indirildiğine dair bilgileri de ekranda gösterebilirler.

Sunucudan indireceğimiz dosyanın tam yolunu verebilmek için şu anki XAP dosyasının tam yolunu alıp sadece dosya adını değiştiriyoruz. Bizim örneğimizde saten her şeyin yeri ve dosya adları belli olduğu için herhangi bir sorun olmayacaktır.

Son olarak OpenReadAsync metoduna da indirilecek olan dosyanın yolunu verip download işlemini başlatıyoruz. Peki ya bu işler bitince çalışacak olan Yukleyici_OpenReadCompleted metodunda neler yapacağız?

[VB]

Private Sub Yukleyici_OpenReadCompleted(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)

    Dim GelenAssembly As New AssemblyPart()

    BirAssembly = GelenAssembly.Load(e.Result)

    Dim Kontrol As UserControl = DirectCast(BirAssembly.CreateInstance("SilverlightClassLibrary1.SilverlightControl1"), UserControl)

    Me.Icerik.Children.Add(Kontrol)

End Sub

[C#]

            AssemblyPart GelenAssembly = new AssemblyPart();

            BirAssembly = GelenAssembly.Load(e.Result);

            UserControl Kontrol = (UserControl)BirAssembly.CreateInstance("SilverlightClassLibrary1.SilverlightControl1");

            this.Icerik.Children.Add(Kontrol);

Download işlemi bittiği anda bir AssemblyPart değişkeni yaratarak onun da Load metodunu kullanıyoruz. Load metoduna e.result ile aslında Yukleyici_OpenReadCompleted event-listener'ına gelen argüman üzerindeki datayı almış oluyoruz. Yani özünde sunucudan indirdiğimiz DLL'in Stream'i e.result içerisinde saklanıyor ve biz de bu AssemblyStream'i doğrudan bir AssemblyPart üzerinden Load ederek Assembly tipindeki BirAssembly değişkenimize yüklüyoruz. Hatırlarsanız zaten bu değişkenimiz de global anlamda sürekli hafızada tuttuğumuz bir değişkendi. Bir sonraki adımda bir UserControl değişkeni tanımlayarak bunu da Assembly'miz içerisinde SilverlightControl1'e eşitlememiz gerekiyor.

Assembly üzerinden CreateInstance metodu bizden yaratılacak nesnenin TypeName'ini istiyor. Silverlight Class Library projesinin içerisindeki UserControlümüzün tipinin adını full path olarak veriyoruz. Bunu zaten UserControl'ün XAML dosyasının en üstünden de bulabilirsiniz. Artık elimizdeki Kontrol değişkeni yine elimizdeki BirAssembly'nin içerisinden SilverlightControl1'in bir instance'ıdır. Herhangi bir UserControl gibi bu da alıp sahnede istediğimiz yere yerleştirebiliriz.

Hepinize kolay gelsin.

Tuesday, February 03, 2009 3:57:55 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Wednesday, January 28, 2009

Bu hafta sonu INETA Professional Hit etkinliğimizi gerçekleştirdik. Kayıt alımındaki sorunlara karşın etkinlik boyunca gelen olumlu tepkiler epeyce moralimi düzeltti. Level 300 hedefi ile yola çıksak da maalesef beni dinlemeyip :) oturumlardaki konularla ilgili hiç çalışmamış arkadaşlar da geldi! Umarım bir sonraki Level 300 etkinliğimizin seviyesi ile ilgili biraz da olsa fikir oluşmuştur kafalarda. Özellikle benim Silverlight oturumunda salonun yarısının hiç Silverlight ile ilgilenmemiş olması Level 300 seviyelerine çıkmamızı engelledi diyebilirim.

INETA Professional Hit İlk Gün
INETA Professional Hit İlk Gün

Neyse :) Bu her açıdan bir "ilk"ti ve hepimiz Level 300 seminerlerle ilgili bir şeyler öğrendik. Bir dahakinin daha verimli olması için bazı notlar da aldık kenara. Şimdi sıra geldi artık fotoğrafları :) ve örnek kodlar ile sunumları sizlerle paylaşmaya.

http://cid-8eca4439fd9a640f.skydrive.live.com/browse.aspx/INETA%20Professional%20Hit%20012009

Yukarıdaki adresten tüm fotoğrafları orijinal çözünürlükleri ile indirebilirsiniz. Ayrıca yukarıdaki adreste bir de Ozel.rar dosyası göreceksiniz :) O dosya içerisinden de kişisel çekilmiş fotoğraflar var.

INETA Professional Hit 2. Gün
INETA Professional Hit 2. Gün

Son olarak aşağıdaki download linklerinden de her oturumla ilgili örnekleri ve sunumları indirebilirsiniz.

28012009_ADONET.rar (1,13 MB)
28012009_AJAX.rar (75 KB)
28012009_CSHARP.rar (551,66 KB)
28012009_LifeCycle.rar (126,8 KB)
28012009_Silverlight.rar (672,98 KB)

Katılan herkese çok teşekkürler. Bir başka aktivitede görüşmek üzere ;)

Wednesday, January 28, 2009 1:45:36 PM (GTB Standard Time, UTC+02:00)  #    Comments [11]   ADO.NET Data Services | AJAX | ASP.NET 3.5 | Silverlight 2.0 | WCF  | 
 Friday, January 16, 2009

Bugün sizlere SoThink'ten "Quicker for Silverlight" ürününden bahsedeceğim. SoThink firması hali hazırda neredeyse tüm Flash developer'ların bildiği ve özellikle Flash De-Compile araçları ile tanınan bir yazılım şirketi. Silverlight'ın popülerliğinin giderek arttığını gördüğünü tahmin ettiğim SoThink bunun bir sonucu olarak Silverlight için de hızlı bir şekilde animasyonlu uygulamaların hazırlanması için ek bir araç çıkartmış.

Çok İlginç..

Nedir ilginç olan? İlginç olan SoThink'in çıkardığı bu aracın arayüzüne baktığımızda tamamen Flash'ta animasyon yapar gibi animasyon hazırlayabilmemiz. Aldığımız çıktı ise bir Silverlight projesi oluyor. Yani her zamanki gibi gidip Flash'tan alışık olduğumuz yapıda KeyFrame'ler ekleyip Motion Tween'ler yaratarak farklı TimeLine'lar ile ilerleyebiliyorsunuz.

İlginç olan kötü özellikler de var. Uygulama tamamen Silverlight tarafındaki programlama işini JavaScript'e yıkıyor ve 2.0'da gelen .NET dillerinden özel olarak tercih edilirse sadece C# kullanabiliyor. Bu durumda maalesef ki ben bu yazılımın Silverlight geliştiricileri tarafından pek tercih edileceğini sanmıyorum. Diğer yandan yaptığım denemelerde Silverlight'ın gücünün tam olarak kullanılamadığı ve FPS miktarının düşük olduğunu gördüm.

Sonuç

Aşağıdaki adresten indirebileceğiniz "Quicker for Silverlight"'ı denemeye değer mi? Karar sizin. Fakat uzun vadede bu ürünü takip etmekte fayda var çünkü SoThink kendi alanında gerçekten başarılı bir yazılım şirketi belki bir gün bu ürünleri de kullanılabilir bir hale gelir.

http://www.sothink.com/product/animation-maker-for-silverlight/index.htm

Friday, January 16, 2009 3:14:42 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Thursday, January 15, 2009

Uzun bir aradan sonra tekrar İstanbul'da güzel bir etkinlik ile karşınızdayız. Ankara ve İzmir derken biraz İstanbul'u boşladığımızı kabul ediyorum. Ama önümüzdeki dönemde bolca telafilerimiz olacak. Gelelim konumuza; INETA Professional Hit!

İki günlük bir etkinlik dizisi ile bu sefer Microsoft binasında buluşuyoruz. Fakat farklı bir şeyler var! Türkiye'de ilk defa tamamen Level 300 ve üstü oturumlardan oluşan halka açık bir aktivite yapıyoruz. Gelin bu konuyu biraz açıklığa kavuşturalım ve şu Level konusuna göz atalım.

  • Level 100: Bahsi geçen konuya giriş ve genel anlatım içerir. Katılımcıların oturumun konusu ile ilgili herhangi bir bilgi birikimine sahip olmadıkları ön görülür.
  • Level 200: Level 100 bilgisine sahip olunduğunu ve buna ek olarak anlatılacak konu ile ilgili genel bir bilgi birikiminin katılımcılarda olduğu var sayılır. Genelde bu oturumlarda anlatılan teknolojilerin detayları ve kullanım alanları ile ilgili gerçek hayat senaryoları işlenir.
  • Level 300: Anlatılacak konu ile ilgili Level 200 bilgisine sahip olunduğu düşünülür. Bu oturumlarda bahsi geçen teknolojilerin uç noktada kullanımına dair örnekler derinlemesine işlenir.
  • Level 400: Bu oturumlar uzmanından uzmanına oturumlardır. Anlatılan teknoloji ile ilgili en gelişmiş ve üst seviyeli bilginin aktarıldığı bu oturumlar ürünlerin üst sınırlarını zorlayan oturumlardır.

Gördüğünüz gibi normal şartlarda bizim INETA tarafındaki etkinliklerimiz ağırlıklı olarak Level 100 ile Level 200 arasında dolaşıyor. Genel olarak baktığımızda bu seviyenin üzerinde etkinliklerin eksikliğini sizler de değerlendirme formlarında defalarca dile getirdiniz. INETA Professional Hit tamamen uzmanlara hitap eden Level 300 ve Level 400 oturumlar içeriyor. Bu kapsamda giriş seviyesi bir beklenti ile etkinliğe gelmemekte fayda var. Giriş seviyesi için yakın zamanda bir etkinliğimiz daha olacak.

Program içeriğimiz ve oturumların seviyeleri şu şekilde;

24 Ocak

10.00-12.30 Silverlight ile Veri Uygulamaları - Daron Yöndem - Level 300
13.00-16.00 ADO.NET Data Services - Burak Selim Şenyurt - Level 300
16.30-18.00 SharePoint üzerinde özel kolon geliştirmek - Nezih Tınas - Level 400

25 Ocak

10.00-12.30 Derinlerde C# 3.0 - Burak Selim Şenyurt - Level 300
13.00-15.00 ASP.NET AJAX 4.0 - Daron Yöndem - Level 300
15.30-18.00 Asp.Net Application ve Page LifeCycle - Oğuz Yağmur - Level 300

Etkinlik Microsoft İstanbul ofisinde olacak. Adres şu şekilde; Bellevue Residence, Levent Mahallesi Aydin Sokak, No: 7 Levent

Etkinliğe katılabilmeniz için aşağıdaki adresten kayıt olmanız gerekiyor.

http://daron.yondem.com/kayit/

Çok yakında giriş seviyesi etkinliklerde de görüşmek üzere.

Thursday, January 15, 2009 2:40:01 AM (GTB Standard Time, UTC+02:00)  #    Comments [23]   ADO.NET Data Services | AJAX | ASP.NET 3.5 | SharePoint | Silverlight 2.0  | 
 Tuesday, January 13, 2009

Bugünlerde bana sıkça gelen sorulardan biri Silverlight tarafından uygulamanın çalıştığı adresin nasıl alınacağı ile ilgili oluyor. Aslında basit bir şekilde Silvetlight'tan DOM'a çıkmanız bunun için yeterli olacaktır. Peki bunu nasıl yaparız?

Silverlight içerisinden DOM'a çıkmak için yolculuğunuzun başlayacağını namespace System.Windows.Browser namespace'i olacaktır. Bu NameSpace içerisinden ister sayfadaki JavaScript metodlarına ulaşır ister sayfadaki HTML elementlerine ulaşabilirsiniz.

[C#]

MessageBox.Show(System.Windows.Browser.HtmlPage.Document.DocumentUri.AbsoluteUri.ToString());

Yukarıda gördüğünüz kod Silverlight uygulamanızın çalıştığı sayfanın tam yolunu verecektir. DocumentUri üzerinden giderek bu adrese ait farklı bilgileri de alabilirsiniz.

Hepinize kolay gelsin.

Tuesday, January 13, 2009 10:36:48 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Sunday, January 11, 2009

Bu hafta sonu İzmir'deydik. Daha önce sizlere duyurmuş olduğum INETA EGE HIT etkinliğini Dokuz Eylül Üniversitesi'nde gerçekleştirdik. Katılımcı profili gerçekten muhteşemdi, hem Cumartesi hem de Pazar günü en ufak bir oturumu bile kaçırmayın daimi bir kitlemiz vardı :) Benim için çok eğlenceli ve sevindirici oldu diyebilirim. Her oturumda aldığım tepkiler çok güzeldi.

INETA Ege Hit başlangıcı.
INETA Ege Hit başlangıcı.

Her zamanki gibi iki de anekdot yarattık; birincisi benim gülen surat çizimimi görüp animasyon olarak "yağmur yağsın ve şemsiye açılsın" diyen arkadaşımızdı :) Dikkatinizi çekerim gülen suratın ne yağmur ne de şemsiye ile alakası yok ayrıca İzmir'de yağmur falan da yapmıyordu :) Her neyse... İkinci anekdot ise buradan paylaşamayacağım hatta sanırım ömür boyu hiç paylaşamayacağım bir şey :) Üzgünüm...

INETA Ege Hit sonu...
INETA Ege Hit sonu...

Organizasyondaki katkılarından dolayı sevgili İzmir MSP'lerimize buradan ÇOK teşekkür ediyorum. Sevgili Buğra, Murat, Gülşah ve Okan'a çok teşekkürler. Etkinlik boyunca çekilen resimlerin orijinal boyutlu hallerine buradan ulaşabilirsiniz. Ayrıca tüm oturumlardaki örneklere ait kodları da aşağıdaki linkten bilgisayarınıza indirebilirsiniz.

Oturumlardaki örnek projeler - 11012009.rar (5,11 MB)

Sunday, January 11, 2009 3:39:22 PM (GTB Standard Time, UTC+02:00)  #    Comments [7]   ASP.NET 3.5 | LINQ | Silverlight 2.0 | WPF  | 
 Saturday, January 10, 2009

Silverlight 2.0 tarafında veritabanı erişimi için mecburen web servisleri kullanmak zorundayız. Durum böyle olunca tek tek veritabanındaki işlemler için ayrı web servisleri yazmak bir noktadan sonra işkenceye dönüşebiliyor. Bugünlerde özellikle LINQ ve Entity Framework ile beraber data layer'larımızda ciddi kolaylıklardan faydalanabiliyoruz fakat web servisleri tarafında geldiğinde ise LINQ vs ile gelen nesneleri geri döndüren web servislerini tek tek yazmak yine can sıkıcı bir hal alıyor.

Aslında tüm bu sorunları çözebilecek bir altyapı .NET Framework içerisinde artık mevcut. ASP.NET Data Services adını verdiğimiz altyapı ile beraber bir veritabanına erişimi doğrudan REST üzerinden yapabiliyorsunuz.

Peki nasıl?

İlk önce gelin ASP.NET Data Services sonuç olarak nasıl bir hizmet yaratıyor ona bakalım. Bugün herhangi bir veritabanına farklı where sorguları ile select'ler göndermek istesek bu sorgulardaki where cümleciklerini parametreli hale getirmemiz ve bu parametreleri alarak uygun datayı döndüren web servisleri yazmamız gerekiyor. Ancak bu şekilde Silverlight ile veritabanına erişebiliyoruz. Farklı senaryolardan eğer sorgularınızın filtreleme şekilleri değişirse bu sefer tekrar gidip uygun web servisini yazmak zorunda kalıyorsunuz. Başka bir seçenek olarak where cümleciklerini parametre alan bir servis yazılabilir fakat bu pek güvenli bir manzara olmaz.

Tüm bu problemleri çözmek için ASP.NET Data Services ile sorgularınızı yazabileceğiniz özel bir syntax geliyor ve artık URL üzerinden sorgu gönderebiliyoruz.

http://localhost:4351/WebDataService1.svc/Uruns(2)

Örneğin yukarıdaki gibi bir adrese gittiğimizde veritabanındaki Uruns tablosunda ID'si 2 olan ürünün bilgilerini XML olarak almış oluyoruz.

[XML]

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<entry xml:base="http://localhost:4351/WebDataService1.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">

  <id>http://localhost:4351/WebDataService1.svc/Uruns(2)</id>

  <title type="text"></title>

  <updated>2009-01-11T22:18:06Z</updated>

  <author>

    <name />

  </author>

  <link rel="edit" title="Urun" href="Uruns(2)" />

  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Kategori" type="application/atom+xml;type=entry" title="Kategori" href="Uruns(2)/Kategori" />

  <category term="SilverlightApplication17.Web.Urun" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

  <content type="application/xml">

    <m:properties>

      <d:ID m:type="Edm.Int32">2</d:ID>

      <d:Adi>Ürün2</d:Adi>

      <d:KategoriID m:type="Edm.Int32">1</d:KategoriID>

    </m:properties>

  </content>

</entry>

Tahmin ettiğiniz üzere aslında bizim normal şartlarda yazdığımız web servisleri de kısmen bu işi yapıyor. Yani bize XML ile istediğimiz veriyi gönderiyoruz. Şimdi bir düşünelim, bu şekilde esnek olarak URL üzerinden farklı sorgular gönderdiğimde bana istediğim veriyi XML ile sanki web servisinden sonuç dönüyormuş gibi döndüren bir sistem aslında benim Silverlight tarafından veritabanını sorgulamam için çok daha esnek bir yapı olmaz mı? Her farklı sorgu için ayrı ayrı web servisleri yazmaktan kurtulmaz mıyım? Evet :) amaç da zaten bu.

Tabi bu arada bir web servisinin çalışma şeklide ve sağladığı XML'lerin snytax'ı ile buradaki biraz farklı. Konumuz dışında olsa da aradaki bu farkın bilincinde olmakta fayda var.

Yapalım şu işi...

Gelin hızlı bir örnek ile ASP.NET Data Services yapısının kullanımını ve Silverlight tarafındaki yansımalarını giriş seviyesine inceleyerek ilerleyelim. İlk olarak yeni bir Silverlight projesi yaratıyor ve yanına da güzel bir ASP.NET sitesi alıyoruz. ASP.NET sitemize hemen bir ADO.NET Data Service dosyası eklememiz gerekiyor. Bunu ASP.NET sitenize sağ tıklayarak "Add New Item" diyerek gelen pencereden uygun dosyayı seçip yapabilirsiniz.

[VB]

Imports System.Data.Services

Imports System.Linq

Imports System.ServiceModel.Web

 

Public Class WebDataService1

    Inherits DataService(Of DataClasses1DataContext)

 

    Public Shared Sub InitializeService(ByVal config As IDataServiceConfiguration)

        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead)

    End Sub

 

End Class

ADO.NET Data Service'i projenize eklediğinizde hemen karşınıza yukarıdaki kodlar çıkacaktır. Koyu ile yazılı kısımları bizim elle eklememiz gerekiyor. DataClasses1DataContext olarak adı geçen şey aslında projemizdeki bir LINQ2SQL Classes dosyası. ADO.NET'in Data Servisleri üzerinden hangi Entity'leri yayınlayacağını belirlememiz gerek. Bu nedenle aslında bir data servisi yaratmadan önce ya LINQ2SQL DBML dosyanızı hazırlamanız ya da Entity Framework tarafında Entity'lerinizi hazırlamanız gerekiyor. Yazımızın konusu dışında olduğu için işin bu kısmına şimdilik değinmeyeceğim. Önemli olan yarattığınız bu veri kaynağının yukarıdaki şekilde Data Servisi'nize aktarmanız.

Bir sonraki adımda ise veri kaynağındaki hangi Entity'lere ne şekilde erişim hakları vereceğiniz. Yani bu data servislerini kullanarak insanlar sadece SELECT mi yapabilecek, yoksa Update veya Delete işlemi de yapabilecekler mi ona karar vermemiz gerekiyor. Bu noktada güvenlik açısından epey dikkatli olmak gerek. Ben şimdilik AllRead diyerek sadece SELECT için veri kaynağındaki tüm tabloları * işareti ile açtım.

Silverlight tarafındaki maceralar.

Servisimiz hazır olduğuna göre artık sıra geldi Silverlight tarafında bu servisi kullanmaya. Başlangıç için normal bir web servisi kullanmaktan pek farklı olmadığını söyleyebilirim. Silverlight projemize sağ tıklayarak "Add Service Reference" diyoruz ve ADO.NET Data Service'imizin SVC dosyasının adresini veriyoruz. Böylece gerekli istemci taraflı proxy yaratılmış oluyor.

Her zamanki gibi veri kaynağımızı kullanmadan önce servis üzerinden bir bağlantı kopyası almamız gerekecektir. Normal şartlarda Silverlight ile SoapClient sınıflarından kopya alırken bu sefer doğrudan DataContext alacağız.

[VB]

Dim Veri As New ServiceReference1.DataClasses1DataContext(New Uri("http://localhost:4351/WebDataService1.svc/"))

DataContext'imizi alırken servisimizin tam yolunu da parametre olarak veriyoruz. Böylece artık bu servis üzerindeki tüm veriye ulaşabiliriz. Sıra geldi sorgularımızı yazmaya. Silverlight tarafında web servislerinin kullanımında da olduğu üzere tüm veri trafiğinin asenkron ilerleyeceğini hatırlarsak aslında sorgularımızı gönderip sonrasında ayrı bir event-listener ile sonucu alacağımızı da tahmin etmek zor değil. ADO.NET Data Services sorgularının URL üzerinden farklı bir syntax ile gittiğini görmüştük fakat elimizde bir DataContext olduğuna göre geri gelen IQueryable nesneleri LINQ ile sorgulayabiliyor olmamız gerekir. Söz konusu LINQ sorguları otomatik olarak Data Services tarafına uygun şekilde çevrilerek gönderilecektir. Sözü daha fazla uzatmadan kodumuzu inceleyelim.

[VB]

Dim Sorgu As System.Data.Services.Client.DataServiceQuery(Of ServiceReference1.Urun) = From gelenler In Veri.Uruns Where gelenler.ID = 2 Select gelenler

Sorgu.BeginExecute(New AsyncCallback(AddressOf Geldi), Sorgu)

[C#]

            System.Data.Services.Client.DataServiceQuery<ServiceReference1.Urun> Sorgu =

                (System.Data.Services.Client.DataServiceQuery<ServiceReference1.Urun>)

                from gelenler in Veri.Uruns where gelenler.ID == 2 select gelenler;

            Sorgu.BeginExecute(new AsyncCallback(Geldi), Sorgu);

Yukarıdaki kodlar bir sorgunun sunucu tarafına gönderilmesini sağlayacak olan kodlar. Sorgumuzu ilk satırda standart LINQ sorgusu olarak yazıyoruz fakat unutmayın ki burada bazı sınırlamalar var. ADO.NET Data Services sorgularında tüm keyword'leri kullanmak mümkün olmuyor. O nedenle eğer buradaki LINQ sorgularında Take vs gibi bazı keyword'leri kullanırsanız Visual Studio hata verecektir.

Yazdığımız sorguyu bir DataSerivceQuery değişkenine eşitliyoruz ve Query nesnemizi yaratırken de geriye ne tür bir nesne döneceğini yine servis üzerinden gelen nesne tanımı ile belirtiyoruz. Artık sorgumuz hazır olduğuna göre BeginExecute ile çalıştırabiliriz. Fakat bu noktada da iki parametreye ihtiyacımız var; birincisi bu sorgu tamamlandığında hangi event çalıştırılacak? Yani bir Callback lazım bize. Asenkron bir Callback yaratarak ilerliyoruz. İkinci parametre ise sorgunun kendisi. Böylece CallBack çalıştığında buradaki sorgunun state'i de geri dönecek.

[VB]

Sub Geldi(ByVal ar As IAsyncResult)

        Dim Sorgu As System.Data.Services.Client.DataServiceQuery(Of ServiceReference1.Urun) = ar.AsyncState

        Dim result = Sorgu.EndExecute(ar)

        MessageBox.Show(result.SingleOrDefault.Adi)

End Sub

[C#]

        void Geldi(IAsyncResult ar)

        {

            System.Data.Services.Client.DataServiceQuery<ServiceReference1.Urun> Sorgu =

                (System.Data.Services.Client.DataServiceQuery<ServiceReference1.Urun>)ar.AsyncState;

            var result = Sorgu.EndExecute(ar);

            MessageBox.Show(result.SingleOrDefault().Adi);

        }

Geldi adındaki asenkron callback'imiz çalıştığında hemen kendisine parametre olarak gelen Result'ın için AsyncState üzerinden Sorgu değişkenimizi alıyoruz. Artık sorgu tamamlandığında göre çalışma işlemini de sonlandırıp sonucu almak gerek. EndExecute metoduna tekrar Callback'e gelen parametreyi verip sonucun bir değişkene aktarılmasını sağlıyoruz ve aldığımız değişken üzerinden istediğimiz veriye ulaşabiliyoruz.

İşte bu kadar...

Data Services yapısı ile Silverlight tarafındaki kodlamanın çok kolaylaştığını söylemek pek doğru olmaz. Elimizde veriyi sağlayan hazır bir web servisi olsaydı çok daha rahat bir kodlama ortamına sahip olabilirdik fakat Data Services bize web servislerine dokunmadan tek bir altyapıya bağlanarak istediğimiz sorguları çalışma zamanında oluşturma şansı tanıyor. Tabi bu sorgular sadece SELECT sorguları olmak zorunda değil, yeri geldiğinde Update, Delete ve Insert de yapabiliriz. Bu makalemizde giriş seviyesinde kalacağımız için şimdilik diğer işlemlere pek dokunmayacağız.

Hepinize kolay gelsin.

Saturday, January 10, 2009 2:53:28 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0 | ADO.NET Data Services  | 
 Friday, January 09, 2009

Bu yazımızda Silverlight 2.0 içerisinde maskeleme (clip) işlemlerine göz atacağız. İlk olarak basit bir maskeleme işleminin XAML içerisinde nasıl yapıldığına baktıktan sonra bu maskeleri nasıl anime edebileceğimize ve programatik yoldan ulaşımına değineceğiz.

Bir maske yaratalım!

Herhangi bir nesneye maske aktarmak demek aslında o nesnenin Clip özelliğine uygun bir şekil aktarmak demektir. Elinizde var olan bir geometri nesnesini alarak bir element'in Clip özelliğine verdiğiniz anda artık söz konusu Geometri nesnesi bir maske görevi görür. Expression Blend içerisinde baktığınızda maskeler nesnelerin birer Property'sine atandığı için ayrı birer obje olarak arayüzde gözükmez.

Expression Blend içerisinde maskelenmeye hazır kontroller.
Expression Blend içerisinde maskelenmeye hazır kontroller.

Yukarıdaki ekran görüntüsünde de görebileceğiniz üzere sahnede bir Image ve bir de Ellipse nesnesi bulunuyor. Bir sonraki adımda amacımız bu Ellipse nesnesini Image için bir maske haline getirmek. Yapacağımız işlem bu iki nesneyi fare ile seçip "Objects and Timeline" kısmında sağ tıklayıp "Path / Make Clipping Path" komutunu vermek. Böylece söz konusu Ellipse artık Image'in Clip özelliğine bir geometri olarak aktarılacak ve ortada Ellipse diye bir nesne kalmayacak.

Maskelenmiş Image kontrolümüz karşınızda.
Maskelenmiş Image kontrolümüz karşınızda.

Artık kontrolümüzü maskeledik ve Ellipse diye bir nesne kalmadı peki arkaplanda XAML tarafında neler oldu? Gelin Blend'in bizim için yarattığı XAML kodunu bir detaylıca inceleyelim.

[XAML]

        <Image Margin="25.032,27,84.032,54.842" Source="1080366_88011245.jpg" Stretch="Fill" Clip="M258.5,130 C258.5,166.17465 212.60919,195.5 156,195.5 C99.390816,195.5 53.5,166.17465 53.5,130 C53.5,93.825348 99.390816,64.5 156,64.5 C212.60919,64.5 258.5,93.825348 258.5,130 z"/>

Gördüğünüz gibi Image nesnesinin uzun bir Clip datası var. Bu data bizim bir önceki adımda yarattığımız Ellipse'in ta kendisi. Aslında bu kodu bu şekilde yazmak yerine daha okunaklı bir şekilde de yazabilirdik. Nasıl mı?

[XAML]

        <Image Margin="7.968,-68,101.032,0" Source="1080366_88011245.jpg" Stretch="Fill" VerticalAlignment="Top" Height="218">

            <Image.Clip>

                <EllipseGeometry Center="200,100" RadiusX="90" RadiusY="60" />

            </Image.Clip>

        </Image>

Peki ne değişti? Nesne basında Clip vermiş olduk. Image nesnesinin Clip özelliğine doğrudan koordinatları girmek yerine ayrı bir element vermeye karar verdik ve bu nedenle de Image.Clip tagları açarak içerisine bir Geometry nesnesi yerleştirdik. EllipseGeometry nesnesi gibi GeometryGroup, LineGeometry, PathGeometry nesneleri de mevcut. Bizdeki örnekte EllipseGeometry'nin Center özelliği maskelenen Image nesnesinin merkez noktasına göre maskenin ne kadar uzaklıkta olacağına dair X ve Y değerlerini verirken RadiusX ve RadiusY'de yatay ve dikey olarak Ellipse'in yarıçapını tanımlıyor. Peki bu iki metod arasındaki diğer farklar nelerdir? Gelin olayın animasyon kısmına bir bakalım.

Maskelere animasyon katalım....

Herhangi bir nesnenin maskesine animasyon verebilmek için Expression Blend içerisinde animasyon modunda sol taraftaki araç çubuğundan Selection aracı yerine "Direct Selection" aracını kullanmalısınız. Söz konusu aracı seçtiğiniz anda seçili nesnenin maskesine ait tanımlı noktaları ekranda görebilirsiniz. Böylece rahatlıkla KeyFrame'ler yaratarak noktaların pozisyonlarını değiştirebilir ve maskeyi anime edebilirsiniz.

Maskemize animasyon verirken.
Maskemize animasyon verirken.

Biz örneğimizde maskedeki tüm noktaları toplu seçerek bir Ellipse şekliden tüm maskenin pozisyonunu değiştiren bir animasyon hazırlıyoruz. Böylece sanki bir ışık ile resme bakılıyormuş gibi resmin üzerinde geziliyor görüntüsü yaratıyoruz. Gelin Blend'in bizim için yarattığı XAML koduna göz atalım.

[XAML]

        <Storyboard x:Name="Storyboard1">

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.StartPoint)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="258.5,130"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="218.937328102718,129.064332728402"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(BezierSegment.Point1)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="258.5,166.174652099609"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="218.937328102718,165.238984828011"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(BezierSegment.Point2)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="212.609191894531,195.5"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="173.046519997249,194.564332728402"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(BezierSegment.Point3)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="156,195.5"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="116.437328102718,194.564332728402"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(BezierSegment.Point1)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="99.3908157348633,195.5"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="59.8281438375813,194.564332728402"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(BezierSegment.Point2)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="53.5,166.174652099609"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="13.937328102718,165.238984828011"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(BezierSegment.Point3)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="53.5,130"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="13.937328102718,129.064332728402"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(BezierSegment.Point1)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="53.5,93.8253479003906"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="13.937328102718,92.8896806287922"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(BezierSegment.Point2)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="99.3908157348633,64.5"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="59.8281438375813,63.5643327284016"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(BezierSegment.Point3)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="156,64.5"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="116.437328102718,63.5643327284016"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[3].(BezierSegment.Point1)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="212.609191894531,64.5"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="173.046519997249,63.5643327284016"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[3].(BezierSegment.Point2)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="258.5,93.8253479003906"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="218.937328102718,92.8896806287922"/>

            </PointAnimationUsingKeyFrames>

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[3].(BezierSegment.Point3)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="258.5,130"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="218.937328102718,129.064332728402"/>

            </PointAnimationUsingKeyFrames>

        </Storyboard>

Animasyonun kodu gördüğünüz gibi epey uzun. Aslında Blend kendi Clip'ini noktalardan yarattığı için mecburen bu noktaları tek tek anime ederek noktaların pozisyonlarını değiştirmek zorunda kalıyor. Bu esnada bizim Image'in XAML kodlarına bakarsan zaten minik bir değişiklik de dikkatimizi çekiyor.

[XAML]

        <Image Margin="57,73.921,52,8.079" Source="1080366_88011245.jpg" Stretch="Fill" x:Name="image">

            <Image.Clip>

                <PathGeometry>

                    <PathFigure IsClosed="True" StartPoint="258.5,130">

                        <BezierSegment Point1="258.5,166.174652099609" Point2="212.609191894531,195.5" Point3="156,195.5"/>

                        <BezierSegment Point1="99.3908157348633,195.5" Point2="53.5,166.174652099609" Point3="53.5,130"/>

                        <BezierSegment Point1="53.5,93.8253479003906" Point2="99.3908157348633,64.5" Point3="156,64.5"/>

                        <BezierSegment Point1="212.609191894531,64.5" Point2="258.5,93.8253479003906" Point3="258.5,130"/>

                    </PathFigure>

                </PathGeometry>

            </Image.Clip>

        </Image>

Söz konusu Clip'in içindeki noktaları anime edebilmek için Blend de kısmen bizim taktiğe geri dönmüş ve bir PathGeometry yerleştirmiş. Oysa biz zamanında Ellipse koymuştuk :) Neden doğrudan o esnada EllipseGeometry koymadın? diye Blend'e sorarsak eminim cevabı basit olacaktır. "Nereden bilebilirim ki bu noktaları ayrı ayrı anime etmeyeceğinizi?" Aslında Blend haklı. Blend her ihtimali düşünmek zorunda çünkü o bir GUI :) Oysa biz kendi örneğimizde maske olarak Ellipse'in şeklini değiştirmeyeceğiz, sadece konumunu değiştireceğiz o nedenle bu sistem bize çok da uygun değil.

Yukarıdaki PointAnimation taglarına bakarsan tek tek Image nesnesinin Clip özelliğindeki değerin alınıp bu değerdeki noktaların Index numarası verilerek bulunduğunu ve pozisyonlarının değiştirildiğini görebilirsiniz. Performans açısından bir sıkıntısı olmasa da oluşan kodun okunabilirliliği çok zayıf olmakla beraber bu gibi bir Clip nesnesinin programatik olarak anime edilmesi de neredeyse imkansız. C# veya VB kodu ile tek tek bu noktaları bulup anime etmek işkenceden farksız olacaktır.

Peki ya bizim teknikle yaparsak?

Bizim esas istediğimiz maskenin konumunun değişmesiydi. Daha önceki kodlarımızda bir EllipseGeometry'yi maske olarak verebilmiştik. Bu EllipseGeometry nesnesinin Center özelliği maskenin konumunu belirliyordu. Bu durumda bizim kodumuzda bu özelliklerin anime edilmesi yeterli olacaktır. Fakat eğer Blend içerisinde bu animasyonu yapacak olursanız bizim EllipseGeometry'yi ısrarlı bir şekilde yukarıdaki gibi bir PathGeometry'ye çevirecek ve yine aynı animasyon kodunu üretecektir. Bu durumda bizim de programatik olarak bu maskeyi anime etmemiz yine zorlaşacaktır.

Sonuç olarak eğer bir nesnenin maskesinin pozisyonunu çok uğraşmadan kod ile anime edebilmek istiyorsanız Blend'in arayüzünden anime etmemeniz gerekiyor.

Programatik olarak maskeye erişmek...

Bir nesnenin maskesine programatik olarak erişmek için söz konusu nesnenin Clip özelliğini alıp uygu Geometry tipine cast edebilirsiniz. Sonrasında elinizde Geometry nesnesi ile ilgilenmeniz yeterli olacaktır. Oysa bir diğer seçenek de XAML içerisinde bu Geometry nesnesine el ile bir isim vermektir.

[XAML]

        <Image Margin="7.968,-68,101.032,0" Source="1080366_88011245.jpg" Stretch="Fill" VerticalAlignment="Top" Height="218">

            <Image.Clip>

                <EllipseGeometry x:Name="Maskesi" Center="200,100" RadiusX="90" RadiusY="60" />

            </Image.Clip>

        </Image>

Gördüğünüz gibi basit bir şekilde bizim EllipseGeometry nesnesine bir isim verdik. Artık kod tarafında bu isim ile EllipseGeometry'ye ulaşabilir ve Center veya RadiusX ve RadiusY özelliklerini değiştirebiliriz.

[VB]

Maskesi.Center = New Point(200, 200)

Böylece tamamen kod ile bu maskeyi anime etmek istediğinizde de rahatlıkla bu noktayı anime ederek maskenin pozisyonunun değiştiği bir animasyon üretebilirsiniz. Örnek bir kodu aşağıda inceleyebilirsiniz.

[VB]

Dim DBL As New PointAnimation

DBL.From = New Point(100, 100)

DBL.To = New Point(200, 200)

DBL.Duration = New TimeSpan(0, 0, 2)

Storyboard.SetTarget(DBL, Maskesi)

Storyboard.SetTargetProperty(DBL, New PropertyPath(EllipseGeometry.CenterProperty))

Dim SB As New Storyboard

SB.Children.Add(DBL)

SB.Begin()

[C#]

PointAnimation DBL = new PointAnimation();

DBL.From = new Point(100, 100);

DBL.To = new Point(200, 200);

DBL.Duration = new TimeSpan(0, 0, 2);

Storyboard.SetTarget(DBL, Maskesi);

Storyboard.SetTargetProperty(DBL, new PropertyPath(EllipseGeometry.CenterProperty));

Storyboard SB = new Storyboard();

SB.Children.Add(DBL);

SB.Begin();

Eğer bu animasyonu XAML tarafında temiz olarak yazmak isterseniz aslında pratik bir şekilde elle de yazabilirsiniz.

[XAML]

        <Storyboard x:Name="Storyboard1">

            <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Maskesi" Storyboard.TargetProperty="(EllipseGeometry.Center)">

                <SplinePointKeyFrame KeyTime="00:00:00" Value="100,100"/>

                <SplinePointKeyFrame KeyTime="00:00:01" Value="200,200"/>

            </PointAnimationUsingKeyFrames>

        </Storyboard>

Animasyonumuz doğrudan Maskesi adındaki EllipseGeometry'yi hedef alarak onun Center property'sini anime ediyor.

Unutmayın ki bizim örneğimizde böyle bir optimizasyon yapabilmemizin nedeni maskenin sadece pozisyonunu değiştirmek istememiz. Eğer maskedeki her bir noktanın konumunu ayrı ayrı birbirinden bağımsız olarak anime etmek isterseniz Blend'in yaptığı teknikten farklı bir seçeneğiniz zaten yok.

Hepinize kolay gelsin.

Friday, January 09, 2009 12:04:28 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, January 08, 2009

Silverlight Toolkit içerisindeki kontrollerin açık kaynak kodları ile beraber dağıtıldığını zaten biliyoruz. Microsoft'tan bağımsız olarak ilerleyen bu projeye ek olarak Silverlight 2'nin dahili gelen MS kontrollerinin de kaynak kodları açıldı! Artık Silverlight 2 Runtime içerisinde bulunan aşağıdaki kontrollerin kaynak kodlarını bilgisayarınıza indirip inceleyebilirsiniz.

ButtonBase, Button, HyperlinkButton, CheckBox, RadioButton, CheckBox, ToogleButton, RepeatButton, RangeBase, Slider, ScrollBar, ProgressBar, Calendar, DataGrid, DatePicker, GridSplitter, TabControl

Tüm kaynak kodlarını aşağıdaki adresten indirebilirsiniz;

http://www.microsoft.com/downloads/details.aspx?FamilyID=EB83ED4C-AC85-4DE9-8395-285628EE2254&displaylang=en

Thursday, January 08, 2009 2:09:23 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, January 07, 2009

Bugün İstanbul Ticaret Üniversitesi'ndeydim. Üniversiteden Imagine Cup'a katılmak üzere hazırlanan bir ekibin isteği üzerine WPF ve Silverlight konulu ikişer saatlik seminerler yapıp sonrasında da ekiple bir odaya kapandık :) Projelerinde karşılaştıkları bazı esaslı sorunlarla ilgili çözümler ürettikten sonra günü sonlandırdık.

İstanbul Ticaret Üniversitesi, Silverlight ve WPF Seminerleri
İstanbul Ticaret Üniversitesi, Silverlight ve WPF Seminerleri

Organizasyondaki katkısından dolayı MSP Bilgehan Gürünlü ve Kemal Can Kara'ya buradan çok teşekkür ediyorum. Ekip gerçekten çok heyecanlı ve en önemlisi bilgiliydi. Umarım Silverlight ve WPF dünyasında aranıza tasarımcılar katmayı da unutmaz ve Imagine Cup'da başarılı olursunuz ;)

Hepinize sevgiler.

Wednesday, January 07, 2009 12:20:29 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0 | WPF  | 
 Tuesday, January 06, 2009

Silverlight içerisinde otomatik olarak farenin çift tıklamasını algılayacak bir sistem bulunmuyor. Çok ciddi bir eksik gibi gözükmese de aslında özellikle iş uygulamaları hazırlarken bu eksik can sıkabiliyor. Aslında bu eksiği gidermenin çok kolay bir yolu var. Çift tıklama sistemi entegre etmek istediğiniz bir kontrol normal tıklama durumunu kontrol ederek bir önceki normal tıklama ile aradaki süreyi ve bir önceki tıklama ile şu anki tıklamanın pozisyonlarını kontrol etmeniz yeterli olacaktır.

[VB]

    Dim SonKonum As Point

    Dim SonTik As Date

 

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        If e.GetPosition(Me).X < SonKonum.X + 10 And e.GetPosition(Me).X > SonKonum.X - 10 Then

            If e.GetPosition(Me).Y < SonKonum.Y + 10 And e.GetPosition(Me).Y > SonKonum.Y - 10 Then

                If DateDiff(DateInterval.Second, SonTik, Now) < 1 Then

                    MessageBox.Show("HO")

                End If

            End If

        End If

        SonKonum = e.GetPosition(Me)

        SonTik = Now

    End Sub

Yukarıdaki kod içerisinde de görebileceğiniz üzere ilk olarak bir önceki tıklama bilgilerini saklamak üzere bir Date bir de Point değişkenimizi global olarak tanımlıyoruz. Bu değişkenlerin sürekli en son tıklamaya ait konum ve zaman bilgilerini saklayacak. Sonrasında MouseLeftButtonDown event-listener'ı içerisinde bir önceki tıklama ile şu anki tıklamanın koordinatlarını karşılaştırıyoruz. Kullanıcı tabi ki biraz fareyi kaydırmış olabilir o nedenle yaklaşık 20 piksellik bir kayma payı verebiliriz. Eğer yeni gelen tıklamanın koordinatları bir önceki ile aynı ise bu sefer de ikinci tıklama anı ile bir önceki tıklama arasında geçen süreyi hesaplıyoruz. Süre bir saniyenin altında ise büyük ihtimal ile bir çift tıklama gerçekleşmiş demektir. Bizim örneğimizde basit bir MessageBox gösteriyoruz, sizin kodlarınızda tabi ki farklı işlemler yapılacaktır.

Tüm bu kontrollerin sonucu olumlu ve olumsuz olsun, en sonunda da Son Tıklama'ya ait bilgileri saklayacak olan değişkenlerimize yeni tıklamanın bilgilerini aktarmayı unutmuyoruz ki bir sonraki tıklamada bu bilgileri "bir önceki" tıklama bilgileri başlığı ile incelenebilsin.

Hepinize kolay gelsin.

Tuesday, January 06, 2009 12:01:06 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, January 05, 2009

Silverlight kullanılan web sitelerin artış ile aslında kullanıcılara da Silverlight yükletme konusunda ısrar giderek artıyor :) Bu konunun bir ısrar olmaması ve kullanıcıların gönül rahatlığı ile Silverlight Runtime'ını yükleyebilmeleri için aslında yükleme sürecinin öncesindeki kullanıcı deneyimi çok önemli.

Eğer istemcide Silverlight yüklü değil ise sizin OBJECT tagları ile sayfaya yerleştirdiğiniz uygulama gösterilmeyecektir. Bunun yerine OBJECT tagları arasındaki HTML kodu kullanıcıya gösterilir. Visual Studio ve Expression Blend ile yeni bir proje yarattığınızda söz konusu HTML kodu varsayılan şekli ile aşağıdaki gibi gelir.

[HTML]

        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">

            <param name="source" value="ClientBin/Carousel.xap"/>

            <param name="onerror" value="onSilverlightError" />

            <param name="background" value="white" />

            <param name="minRuntimeVersion" value="2.0.31005.0" />

            <param name="autoUpgrade" value="true" />

            <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

            </a>

        </object>

Yukarıdaki OBJECT tagları arasında renkli olarak gördüğümüz kısım sadece Silverlight yüklü olmadığında gösterilecektir. Bu kısıma istediğiniz HTML kodunu koyabilirsiniz. Buradaki standart link Silverlight'ın Microsoft sitesinde yükleme sayfasına yönlendirirken diğeri de standart "Install Silverlight" görselini gösterir.

Standart Silverlight Yükleme mesajı.
Standart Silverlight Yükleme mesajı.

Kendi özel "Silverlight Yükle" görselinizi ve mesajınızı hazırlarken kullanıcıları korkutup kaçırmamak adına sizlere birkaç tavsiyem olacak.

  • İnsanlara "Silverlight Yükle" derken neden yüklemelerini istediğinizi belirtin.
  • Kullanıcıların yüklemeden önce de sitenizin nasıl bir şey olduğunu görmeleri sağlayın, merak uyandırın. Özetle Silverlight yüklerlerse nasıl bir şeyle karşılaşacaklarını görsünler ki yüklemeye daha sıcak baksınlar.

Aşağıda bulabileceğiniz örnekte Silverlight ile çalışan bir sitenin Silverlight yüklü olmadığında da nasıl gösterildiğini inceleyebilirsiniz. Standart "Install Silverlight" görseli yerine böyle bir deneyim çok daha çekici olacaktır.

Örnek Silverlight Yükleme Ekranı
Örnek Silverlight Yükleme Ekranı

Hepinize kolay gelsin.

Monday, January 05, 2009 11:32:42 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Saturday, January 03, 2009

Carousel kontrolleri son dönemin modası diyebiliriz. Çoğu yazılımın arayüzünde Carousel kontrolleri görmeye başladık. Özellikle web sitelerinde de neredeyse RIA denildiği anda bir yere bir Carousel konulması gibi bir moda da mevcut. Bu çerçevede Silverlight 2 uygulamalarınızda Carousel yapılarından faydalanmak isterseniz herşeyi sıfırdan yazmanıza gerek yok. Bu yazımda sizlere açık kaynak kodu ile dağıtılan hazır bir Carousel kontrolünü tanıtacağım.

Coolmenu Carousel kontrolü

İlk olarak gelin kullanacağımız kontrolü kendi web sitesinden bir bilgisayarımıza indirelim. Aşağıdaki adresten indirebileceğin kontrolün tüm kaynak kodları ile alıp inceleme şansınız var. Biz şimdilik RC0 için hazırlanmış olan paketi alarak içerisinde Coolmenu.DLL dosyasını kullanacağız. Yani kaynak kodları ile uğraşmayacak doğrudan kontrolün Compile edilmiş halini projelerimize entegre edeceğiz.

http://pagebrooks.com/archive/2008/08/21/coolmenu-a-silverlight-menu-control.aspx

Projemize Carousel ekleyelim!

Projemizde Coolmenu Carousel kontrolünü kullanabilmek için ilk olarak download paketinden Coolmenu.Dll dosyasına Silverlight projemize referans olarak eklemeliyiz. Sonrasında XAML tarafında söz konusu kontrolü sayfaya koyabilmemiz için gerekli namespace tanımlarını yapmamız şart.

[XAML]

<UserControl x:Class="SilverlightApplication8.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300"

   xmlns:SilverlightContrib_Controls="clr-namespace:SilverlightContrib.Controls;assembly=CoolMenu">

    <Grid x:Name="LayoutRoot" Background="White">

        <SilverlightContrib_Controls:CoolMenu x:Name="Carousel"/>

    </Grid>

</UserControl>

Yukarıdaki XAML kodunu incelediğiniz özellikle dikkat etmemiz gereken aslında iki nokta var. Bunlardan ilki xmlns tanımımız. SilverlightContrib_Controls adında tanımladığımız yeni XML namespace'imiz doğrudan Coolmenu assembly'sini hedefliyor. Böylece söz konusu assembly içerisindeki tüm kontrollü XAML içerisinde kullanabileceğiz. Bir sonraki adımda da tanımladığımız NameSpace'i kullanarak CoolMenu kontrolünden bir adet ekrana yerleştirerek adını da Carousel olarak tanımlıyoruz. Bu aşamadan sonrası için kod tarafına geçmemiz ve bu Carousel içerisinde gösterilecek öğeleri tanımlamamız gerek.

[VB]

Dim Foto As New Image

Foto.Source = New Imaging.BitmapImage(New Uri("http://daron.yondem.com/tr/images/vesikalik2.png", UriKind.Absolute))

Carousel.Items.Add(New SilverlightContrib.Controls.CoolMenuItem() With {.Content = Foto})

Foto = New Image

Foto.Source = New Imaging.BitmapImage(New Uri("http://daron.yondem.com/tr/images/vesikalik2.png", UriKind.Absolute))

Carousel.Items.Add(New SilverlightContrib.Controls.CoolMenuItem() With {.Content = Foto})

Foto = New Image

Foto.Source = New Imaging.BitmapImage(New Uri("http://daron.yondem.com/tr/images/vesikalik2.png", UriKind.Absolute))

Carousel.Items.Add(New SilverlightContrib.Controls.CoolMenuItem() With {.Content = Foto})

[C#]

Image Foto = new Image();

Foto.Source = new Imaging.BitmapImage(new Uri("http://daron.yondem.com/tr/images/vesikalik2.png", UriKind.Absolute));

Carousel.Items.Add(new SilverlightContrib.Controls.CoolMenuItem { Content = Foto });

Foto = new Image();

Foto.Source = new Imaging.BitmapImage(new Uri("http://daron.yondem.com/tr/images/vesikalik2.png", UriKind.Absolute));

Carousel.Items.Add(new SilverlightContrib.Controls.CoolMenuItem { Content = Foto });

Foto = new Image();

Foto.Source = new Imaging.BitmapImage(new Uri("http://daron.yondem.com/tr/images/vesikalik2.png", UriKind.Absolute));

Carousel.Items.Add(new SilverlightContrib.Controls.CoolMenuItem { Content = Foto });

Örnek kodlarımız içerisinde sürekli yeni Image nesneleri yaratarak bunları tek tek birer öğe (CoolMenuItem) olarak Carousel kontrolümüze ekliyoruz. Her bir CoolMenuItem'ın Content özelliğine herhangi bir Silverlight nesnesi atayabilirsiniz. Bu ister bizim örneğimizdeki gibi bir resim ister bir video, yani MediaElement olabilir.

Get Microsoft Silverlight
Örnek Carousel Kontrolü (Tıklamayı unutmayın :))

Hepinize kolay gelsin...

Saturday, January 03, 2009 3:22:39 PM (GTB Standard Time, UTC+02:00)  #    Comments [16]   Silverlight 2.0  | 
 Friday, January 02, 2009

Yeni yılda hayatınızı kolaylaştırma yolunda iddialıyım :) Bu sefer de benim işimi çok kolaylaştıran bir aracı sizlerle paylaşacağım.

Visual Studio içerisinde F5'e bastığımızda System Tray'de beliren "ASP.NET Development Server"'ı hatırlarsınız. Aslında adı "Cassini" olan bu server işimizi epeyce kolaylaştırır ve bizim her sererinde IIS'te sitemizi veya uygulamamızı ayarlamamızı gerektirmeden uygulamanın sanal bir sunucu ortamında test edilmesini sağlar.

Peki hiç herhangi bir projenizi doğrudan çalıştırıp görmek istediğinizde mecburen Visual Studio ile açıp F5'e bastığınız oldu mu? :) Veya mecburen IIS'te web site ayarlamak zorunda kaldınız mı? sadece sitenizi çalıştırabilmek için? İşte bu işkence aslında sürekli yaşadığımız bir süreç ve çok kolay bir çözümü var. Biz de Visual Studio gibi gidip Cassini'yi kullanabiliriz.

Aslında Cassini bizim bilgisayarlarımızda WebDev.WebServer.exe olarak yüklü bulunuyor. Tabi ki EXE'yi doğrudan alıp taşıyamazsınız, çok sayıda bağlantılı DLL vs de söz konusu. Ama biz bu EXE'ye doğru parametreleri gönderirsek aynı Visual Studio'nun kullandığı gibi herhangi bir klasördeki dosyaları web sunucudaymış gibi çalıştırabiliyor. Bu EXE'nin nasıl kullanıldığını merak edenleri veya birazdan sizlerle tanıştıracağım uygulamanın nasıl yazıldığını merak edenleri İngilizce blogumdaki bir yazıya davet edebilirim :)

Sağ tıkla sunucudaaymış gibi çalıştır!
Sağ tıkla sunucudaaymış gibi çalıştır!

Gelelim sadede... Infragistics'te çalışan J. Ambrose Little tüm bunları yaparak uygulamayı da bir SETUP paketi şeklinde hazırlamış ve bununla da kalmamış ve bu sistemi işletim sisteminin context menü'süne bağlamış. Yani özetle; herhangi bir klasöre sağ tıklayıp "ASP.NET 2.0 Web Server Here" dediğizde Cassini açılıyor ve söz konusu klasör içerisindeki uygulama server üzerinden çalıştırılıyormuş gibi karşınıza çıkıyor. Aynı Visual Studio'da F5'e basmış gibi :)

Uygulamayı aşağıdaki linkten bilgisayarınıza indirip yükleyebilirsiniz.

Cassini Web Server Launcher - 02012009_1.msi (355 KB)

ASP.NET 2.0 dediğine bakmayın 3.5 SP1 ile herhangi bir sorunu yok.

Hepinize kolay gelsin...

Friday, January 02, 2009 12:57:26 PM (GTB Standard Time, UTC+02:00)  #    Comments [10]   AJAX | ASP.NET | ASP.NET 3.5 | Silverlight | Silverlight 2.0  | 
 Wednesday, December 31, 2008

Veeee yılbaşı geldi :) Yeni bir yıl yeni heyecanlar ve tabi eskitilen bir yıl ve yaşananlar. Neyse geyiği bırakıp konuya dönelim :) Malumunuz yeni yıl gelirken hemen bir E-Kart savaşı başlar :) Herkes birbirine milyonlarca kutlama mesajı gönderir ve bu mesajların içerisinde de E-kartların yeri büyüktür. Ben de bir kaç dakika ayırarak sizler için ufak bir Silverlight 2.0 E-Kart hazırladım.

E-kart'ın kaynak kodlarını da aşağıdaki adresten bilgisayarınıza indirebilirsiniz. Bu vesile ile bloğumu okuyan herkesin yeni yılını da kutluyorum.

E-Kart Kaynak Kodları - 31122008_1.rar (1,83 MB)

Wednesday, December 31, 2008 9:30:28 PM (GTB Standard Time, UTC+02:00)  #    Comments [12]   Silverlight 2.0  | 
 Tuesday, December 30, 2008

WPF veya Silverlight projelerinde Inıt durumu ile PageLoad veya WindowLoad event'ları arasındaki fark bazen ilk bakışta yokmuş gibi varsayılarak kodların doğrudan Init kısmına yazıldığını çok gördüm. Bazen bu durum sorun çıkarmasa da aslında tam olarak Init durumu bitmediği için bazı kaynaklara veya kontrollere ulaşmama hatta bu ulaşıp / ulaşmama durumunun da belli olmaması :) gibi garip hatalar ile karşılaşabilirsiniz. O nedenle benim genel tavsiyem sürekli Loaded event'larının kullanılması ve Init'in sadece ek event-listener tanımlamalarının yapılacağı bir konum olarak saklanması.

Bu çerçevede bir diğer sorun ise Init durumuna yazdığınız kodların aslında hem Blend hem de Visual Studio tarafından Design modundayken çalıştırılıyor olması. Eğer bu bilgiye sahip değilseniz maalesef ki Init durumunda yaptığınız ağır bir işlemin bir anda Visual Studio ve Blend'in arayüzüne de binmesi ve Page.XAML gibi bir dosyayı açtığınız anda yüksek işlemci kullanımları ile karşılaşmanız olası. En basit çözüm bu kodları Init'den çıkarmak ve Loaded'a yerleştirmek olabilir fakat ya Init'i kesinlikle kullanmanız gerekiyorsa?

[C#]

            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false)

            {

 

            }

İşte yukarıdaki gibi bir kontrol ile söz konusu Init kodunun içinde uygulamanın DesignMode'da olup olmadığını kontrol edebilirsiniz. Böylece eğer sayfa Visual Studio veya Blend ile Design modunda açılmış ise bu IF içerisinde kodlar çalıştırılmayacak. Oysa programı F5 ile compile edip çalıştırdığınızda ise herhangi bir sorun ile karşılaşamaycaksınız.

Hepinize kolay gelsin.

Tuesday, December 30, 2008 9:18:36 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Expression Blend | Silverlight 2.0 | Visual Studio 2008 | WPF  | 
 Friday, December 26, 2008

Sonunda hazırlayabildim :) SilverNight'ta çektiğimiz videoların maalesef eğitim kısmını yayınlayamıyorum. Videolarda sunumdaki kodların hiçbiri sağlıklı bir şekilde gözükmüyor. En kısa zamanda başka bir seminerde bu konuyu telafi ederek eğitim kısmının da yayınlanmasını sağlayacağım.

Aşağıda izleyebileceğiniz video ise daha ağırlıklı olarak SilverNight'ın genelinden bahsediyor. Yolculuğumuza çıkışımızdan tutun, ekiplerin video portalını yaparkenki çalışma şekillerine ve SilverNight'ın sonundaki proje sunumları ile oylamaya kadar tüm adımları izleyebilirsiniz.

Uyarmadı demeyin, video 37 dakika sürüyor :)

Hepinize iyi seyirler ;) SilverNight katılımcılarından videoyu bilgisayarına indirmek isteyenler olursa buradan alabilirler.

Friday, December 26, 2008 3:14:43 PM (GTB Standard Time, UTC+02:00)  #    Comments [8]   Silverlight 2.0  | 
 Wednesday, December 24, 2008

Bugün KKTC Doğu Akdeniz Üniversitesi'nde Microsoft Oyun Turu'nun bir ayağını daha gerçekleştirdik. Sevgili XNA uzmanımız Engin Yıldız ile beraber günü birlik gittiğimiz için maalesef zamanımız biraz kısıtlı oldu ve konular iç içe geçti :) Fakat özünde eminim ki salondaki herkes hem Silverlight hem XNA ile oyun programlamanın kendisi için ne kadar kolay veya zor olduğunu anlayarak en azından bu sektöre atılıp atılmama konusunda karar verebilecek bilgiyi edindi.

KKTC Doğu Akdeniz Üniversitesi, Microsoft Oyun Turu
KKTC Doğu Akdeniz Üniversitesi, Microsoft Oyun Turu

Organizasyondaki katkılarından dolayı DAÜ Yazılım Kulübü'nde ve Yazılım Kulübü Başkanı Olcay Kük'e buradan çok teşekkür ediyorum. Süper bir misafirperverlik örneği gösterirdiler yine.

Wednesday, December 24, 2008 1:50:11 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, December 21, 2008

Süper bir geceydi. Neden mi? :) Tabi ki SilverNight yüzünden. Talihliler arasında yer alamayanların unuttuğunu tahmin ettiğim SilverNight etkinliğimizi bu sabah bitirdik. Tüm etkinliği canlı olarak silvernight.ms üzerinden de yayınladık. Gelen SMS'lerden ve maillerden yola çıkarak izleyenlerin %25'inin sorun yaşadığını gördüm :) Herhalde internet bağlantılarından olsa gerek. Beni şaşırtacak şekilde gece yarısı 3'te bile 40'a yakın izleyicimiz varmış! Bugün istatistiklere bakınca şaşırmadım desem yalan olur.

SilverNight başlıyor...
SilverNight başlıyor...

Neler yaptınız? Nasıl yaptınız?

Dün akşam 08.00'da Taksim'den servisimiz kalktı ve Koç Üniversitesi'nde doğru yolculuğumuz başladı. Üniversiteye ulaştığımızda canlı yayın hazırlıklarını da yaptıktan sonra 10.30 gibi bir video portalı yaparken ihtiyaç duyacağımız Silverlight ile ilgili bilgileri aktarmaya başladım. Hem tasarım, hem programlama, hem de veri tabanı bağlantılarına kadar değindik. Hatta hızlıca LINQ konusunu bile işledik. Tabi benim yine gevezeliğim tuttu ve bir baktık ki saat gece yarısı 03.00 olmuş!

Herkes çok heyecanlı :)
Herkes çok heyecanlı :) Hangi grup birinci olacak?

Tabi detayları atlamiyim. Tam gece yarısında pizzalarımız geldi :) Sonra sponsorlarımızdan RedBull geldi :) Güzel bir doping yapmayı unutmadık. Neyse gece yarısı 03.00'a geri dönelim. Hazırlayacağımız video portalının tanımını yaptık, detayları belirledik ve 5 ayrı grup oluştururduk. Her grup kendi portalını yazmaya başladı. Sabah 08.00'da gruplar hazırlamış oldukları portalları tüm gruplara sundular. 5 gruptan 4'ü ortaya bir şeyler çıkarabildi. Oylamalar sonrasında benim de favorim olan "DeveDizayn" grubu birinci oldu. Tam olarak skor tablosu şöyle;

Birincili : Devedizayn
İkincilik : Grup 1 Gece
Üçüncülük: Grup Dinçer
Sonuncu : Komedi Dans Üçlüsü

Tüm etkinliği videoya çektik fakat ekranlar pek iyi çıkmamış maalesef :( Ama ben çoğu videoyu hazırlayarak sizinle buradan paylaşacağım. Minibüs yolculuğumuzdan tutan grupların projeleri yaparkenki halleri ve projelerini sundukları sunumlara kadar hepsinin video kayıtları mevcut :) Eminim izlerken siz de bizim kadar eğleneceksiniz. Tabi tüm bu içeriği hazırlamam için bana biraz zaman vereceğinizden eminim :)

SilverNight sonrası, sabah evlere dağılmadan önce!
SilverNight sonrası, sabah evlere dağılmadan önce!

Şimdilik aktivitenin fotolarından elime ulaşanları sizlerle paylaşıyorum :)

http://cid-8eca4439fd9a640f.skydrive.live.com/browse.aspx/SilverNight%202008%20Istanbul?link=0

Ayrıca her 4 grubun da yapmış olduğu projelerin kaynak kodlarını aşağıdan indirebilirsiniz. Birinci olan grubumuzun projesini CodePlex'e yükleyerek ileriki SilverNight etkinlikleri ile projeyi büyütmeyi de düşünüyoruz :) Yakında siteyi yayına alıp sizlerle adreslerini paylaşacağım.

Birinci Proje - 21122008_01.rar (2,08 MB)
İkinci Proje - 21122008_02.rar (537,82 KB)
Üçüncü Proje - 21122008_03.rar (818,55 KB)
Sonuncu Proje - 21122008_04.rar (515,5 KB)

SilverNight'a katılan herkese çok teşekkürler. Ayrıca özellikle Koç Üniversitesi Bilgisayar Kulübü, sevgili MSP'lerimiz Yiğit Kıran ve Yasemin Avcular'a çok çok teşekkür ediyorum. Sizler olmasaydınız böyle güzel bir gece geçiremezdik. Ayrıca aldığınız hediyeyi de hiç unutamayacağım :)

Bu hediyeyi unutmayacağım :D
Bu hediyeyi unutmayacağım :D

En kısa zamanda etkinlik videoları ile görüşmek üzere ;)

Sunday, December 21, 2008 2:48:57 AM (GTB Standard Time, UTC+02:00)  #    Comments [14]   Silverlight 2.0  | 
 Saturday, December 20, 2008

Bugün Imagine Cup Türkiye Lansmanı'nda "Expression Studio ile Tasarım" oturumunu sundum. Oturuma katılan arkadaşların çoğu hali hazırda daha önce beni izlemiş olmanın avantajını kullanarak neredeyse tüm hamlelerimi tahmin etseler de en azından daha önce dinlemeyenler için faydalı bir saat olduğunu tahmin edebilirim. Bu vesile ile aslında uzun zamandır Expression Studio anlatmadığımın da farkına vardım. Sürekli Silverlight ve WPF anlatırken sadece Expression Blend'den bahsetme şansım oluyor oysa Expression Studio içerisinde Design, Media, Encoder ve Web de çok güzel özelliklere sahip.

Imagine Cup Lansmanı - Expression Studio Oturumum
Imagine Cup Lansmanı - Expression Studio Oturumum

En kısa zamanda daha detaylı bir Expression Studio semineri yapma kararı aldım :) Imagine Cup'a katılmayı düşünen arkadaşların sorularını her zaman mail olarak bekliyorum ;) Yardım gerekirse buralardayım.

Saturday, December 20, 2008 2:08:07 AM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Expression Blend | Expression Design | Expression Encoder | Expression Media | Expression Studio | Expression Web | Seminer | Silverlight 2.0 | WPF  | 
 Wednesday, December 17, 2008

Bugün Abdurrahman – Nermin Bilimli Anadolu Teknik Lisesi'ndeydim. Cevher gibi VB.NET bilen gençlerin arasında 5 saat geçirdim. Tüm bu sürede Silverlight ve WPF dünyasına göz attık, sona doğru da hızlıca bir LINQ girişi yaptık. Meslek liselerinde heyecan beni de bir o kadar heyecanlandırıyor. Zaten bu konuda çok yakında bazı ek duyurular da yapacağım. Ülkemizin bilişim ve özellikle yazılım üretimi ile gelir elde eden bir ülke olabilmesi için meslek liselerinin önemi bence çok büyük. Aşağıdaki fotoğrafa baktığınızda eminim ki sizler de benimle aynı duyguları paylaşacaksınız.

Abdurrahman-Nermin Bilimli Anadolu Teknik Lisesi
Abdurrahman-Nermin Bilimli Anadolu Teknik Lisesi

Organizasyon için sevgili hocalarımıza çok teşekkür ediyorum. Normalde 3 saat olarak planladığımız etkinliği onların da desteği ile 5 saate uzattık. Her şey çok güzeldi. Tek sorun : "Meslek liselerini ziyaret ettikçe kendimi daha yaşlanmış hissetmem" :)

Seminere katılan tüm kardeşlerimi buradan öpüyorum.

Wednesday, December 17, 2008 12:44:50 AM (GTB Standard Time, UTC+02:00)  #    Comments [5]   LINQ | Seminer | Silverlight 2.0 | WPF  | 
 Tuesday, December 16, 2008

Dün detaylarından bahsettiğim Windows Live yeni sürüm hizmetlerinden Live Groups'ta yeni bir grup açtım. Bugün sizlere onu duyurmak istiyorum fakat onun öncesinde gelin beni takip edebileceğiniz diğer medyalardan bahsedelim.

Genelde "Hocam nerede bir sonraki seminer?" "Nasıl?" vs gibi soruları tek tek cevaplamak yerine beni, seminerleri, INETA aktivitelerini vs takip edebilmeniz adına aslında en ana kaynak benim blogum. Blogumu RSS üzerinden takip edebileceğiniz gibi eğer blogun en üstündeki "Mail ile takip et" kısmından  ilerlerseniz mail adresinizle kayıt olup blogdaki değişikliklerden mail ile de haberdar olmayı tercih edebilirsiniz.

Bir diğer seçenek ise twitter üzerinden beni takip etmek. Twitter'ı bir anlamda microblog olarak tutuyorum. Sektörle ilgili kısa haberler, duyuruların yanı sıra bazen seminerleri de oradan anlık olarak duyuruyorum.

Peki tüm bunların yanında Live Groups'ta bir grup açarak amacımız nedir?

http://daronyondem.groups.live.com/ adresinden gruba kayıt olduğunuzda artık daronyondem@groups.live.com adresine mail atarak grubu takip eden herkese ulaşabilirsiniz. Böylece belki de Silverlight ile ilgili takıldığınız bir noktada ben değil de sorunuzu bir başka Silverlight meraklısı cevaplandırabilecek :) Sorulara yetişmekte ciddi sorun yaşadığımı itiraf etmem gerek. Ayrıca bazen çok ilginç haberler veya sizlerin yaptığı Silverlight, WPF uygulamalarını da paylaşmak için grubu kullanabilirsiniz. Özetle yeni yazılım teknolojilerine meraklı olan herkesin birbiri ile iletişimi için Live Groups altyapısını kullanıyor olacağız. Grubun yönetimi bende olsa da yukarıdaki bahsettiğim diğer sistemlerden farklı olarak Live Groups "Daron merkezli" değil. Sizler de birer "yayıncı"sınız artık. Belki de bulduğunuz bir ip ucunu veya çözdüğünüz bir sorunu herkesle paylaşmak isteyebilirsiniz, böylece mail groupta paylaşma şansınız olacaktır.

Tabi tüm bunların yanı sıra olabildiğince duyuruları da gruba taşıyor olacağım. Ayrıca çok yakında Live Groups üzerindeki gruba özel takvimde bir etkinlik takvimi de düzenleyeceğim. Böylece "Bir sonraki seminer nerede?" sorusunun da cevabını sürekli online tutuyor olacağız.

Outlook kullananlar tavsiyem bir klasör oluşturup bir de kural belirleyerek grubun maillerini bir klasöre toplamanız :) takibi çok daha rahat olacaktır.

Hepimize hayırlı olsun ;)

Tuesday, December 16, 2008 12:28:16 AM (GTB Standard Time, UTC+02:00)  #    Comments [2]   live.com | Silverlight 2.0 | WPF  | 
 Sunday, December 14, 2008

Silverlight 2.0 ile beraber gelen DataGrid'in aslında SDK paketi ile beraber geldiğini biliyoruz. Yani normal şartlarda DataGrid Silverlight Runtime içerisinde bulunmuyor. Haricinde bir DLL içerisinde yer alan DataGrid'i referans alarak projenize eklemeniz ve o şekilde ilerlemeniz şart. Durum böyle olunca tabi ki bu kontrolleri yenilemek, upgrade ve update'ler sunmak da kolaylaşıyor.

Silverlight 2 DataGrid için yeni bir Aralık 2008 sürümü yayınlandı. Gelen yenilikler ve değişikliklerle ilgili ufak bir liste yapmak gerekirse;

  • 30'a yakın bug giderildi.
  • Focus alan satırlar ItemsSource değiştiğinde görünmez olmuyor.
  • Sorting yapıldığında artık Selection kaybolmuyor.
  • DataGrid içerisinde Popup açan kontroller artık DataGrid'in editin mode'undan çıkmasına neden olmuyor.
  • Geliştirilmiş FrozenColumn
  • Selection artık CurrentCellChanged event'ı ile güncelleniyor.

Peki nasıl kullanırız?

Eğer Visual Studio içerisinde Toolbox'ı kullanıyorsanız (ki şimdilik Silverlight 2.0'da tavsiye etmiyorum) işiniz biraz zor olacak. Kullanıcınıza ait AppData\Local veya Local Settings\Application Data içerisinde Toolbox ile başlayan tüm dosyaları silmelisiniz. Silverlight 2.0 SDK'yı yüklediğiniz yerdeki System.Windows.Controls.Data.dll ve System.Windows.Controls.Data.Design.dll dosyalarını download edecekleriniz ile değiştirdiğinizde aslında işlem tamamlanmış oluyor. Tabi daha önce bu DLL'leri kullandığınız tüm projelerdeki reference'ları da güncellemeniz şart.

Download adresi : http://www.microsoft.com/downloads/details.aspx?FamilyID=084a1bb2-0078-4009-94ee-e659c6409db0&displaylang=en

Hepinize kolay gelsin.

Sunday, December 14, 2008 10:08:56 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Friday, December 12, 2008

Son zamanlarda çok fazla Virtual Earth ve Silverlight'ın beraber kullanımı ile ilgili mail alıyorum. Bu konuda uzun uzun teknik bir makale yazmaya hazırlanırken bir baktım ki birileri daha hızlı davranmış ve Silverlight 2.0'ın MultiScaleImage altyapısını da kullanan bir Virtual Earth kontrolünü Silverlight için open source olarak hazırlamış.

Deep Earth adını verdikleri altyapı sayesinde rahatlıkla Virtual Earth'ü Silverlight uygulamalarınızda da kullanabiliyorsunuz. Hemen kontrolü indirebileceğiniz adres CodePlex üzerinde şu şekilde ; http://www.codeplex.com/deepearth

Benim tavsiyem ilk başta buradaki demoyu inceleyerek ne kadar güzel bir kullanıcı deneyimi yaratıldığında göz atmanız. Virtual Earth ve Silverlight ikilisi ile muhteşem şeyler yapılabilir. Genelde bu mapping sistemlerinin en büyük dezavantajı DHTML ve JavaScript ile programlanıyor olmasıydı ;)

Unutmadan :) Virtual Earth'ın altyapısını böyle rahat rahat kullanabilmek için tabi ki https://mappoint-css.live.com/mwssignup bu adresten bir Developer Account almanız gerekiyor. Burada verilen bilgileri DeepEarth'e aktararak uygulamanızın Virtual Earth haritalarını web servisi üzerinden çekebilmesini sağlıyorsunuz.

Hepinize kolay gelsin.

Friday, December 12, 2008 6:37:04 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, December 11, 2008

Microsoft'un dünya çapındaki Imagine Cup yarışmasının bu seneki ayağının finali Mısır'da yapılacak. Tabi onun öncesinde Türkiye ayağı ile yarışmacıların Türkiye birinciliğini almaları gerekiyor :)

Imagine Cup 2009 için bu yıl öğrenciler; dünyanın en zorlu sorunlarına, teknoloji ile çözüm bulabilecekleri bir dünya düşlemeye davet ediliyor. Bazılarımız teknolojiyi dünyanın her yerindeki insanlara eğitim şansı kazandırmak için kullanacaktır, ya da sağlık alanında yepyeni ufuklar açmak için. Bazılarımız ise cinsiyetler arası fırsat eşitsizliğini çözmek isteyecektir. Imagine Cup 2009 teması için örnek gösterilen Birleşmiş Milletler Milenyum Hedeflerinin açıklandığı, geçtiğimiz yılların deneyimlerinin aktarıldığı ve teknik oturumların bulunduğu Imagine Cup 2009 Lansmanı 20 Aralık Cumartesi günü Microsoft Istanbul ofisinde gerçekleştirilecek.

Aktiteye katılmak için buradan kayıt olmanız gerekiyor.

Sabah saat 10.00'da başlayacak etkinliğin planına buradan ulaşabilirsiniz. En son teknik oturum benim ;) Konumuz: Expression Studio.

Thursday, December 11, 2008 6:21:04 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Expression Blend | Expression Design | Expression Encoder | Expression Media | Expression Studio | Expression Web | Silverlight | Silverlight 2.0  | 
 Tuesday, December 09, 2008

Bugün SilverNight'ın çekiliş günüydü :) Malum artık çekiliş için kayıtları kapattık ve gözümüzü de kapatıp parmağımızı listede rastgele yerlere basarak çekilişimizi yaptık. :) Tamam, itiraf ediyorum bu kadar ilkel bir çekiliş olmadı ama mantıken aynı işi bizim için .NET Framework'ün Random sınıfı yaptı. Peki kimler mi kazandı? Buyurun liste karşınızda.

Nejat Can Ünlü, Mehmet Turac, Ahmet Enes Dabanlıoğlu, Özge Çimendere, Alp Çoker, Ararat Avşaroğlu, Tarık Kranda, Yağız Gönüler, Mehmet Kurt, Hüseyin Aydın, Sinan Sağer, Sinan Asil, Osman Kucuksonmez, Kemal Can Kara, Cüneyt Değer, Tolga Birsen, Barış Özaydın, Ercan Zengin, Dinçer Uygun, Ali Yalçın, Arif Refik Şenol, Çağlar Araz, Fatih Gençaslan, Ali İncir, Şeref Seçil

Kazanan arkadaşları kutluyorum. Kendilerine bugün içerisinde birer mail ulaşacak ve o maillere cevap vermeleri gerekiyor :) Aksi halde şanslarını kaybedebilirler ve yeni çekilişlerle yedekler belirlemek zorunda kalabiliriz. Eğer böyle bir durum olursa yedekleri tekrar blogdan duyurmayacağım, sadece kendilerine mail atacağım.

Umarım muhteşem bir gece geçirir ve sabahına da video portalımızı yetiştiririz.

Sevgilerle...

Tuesday, December 09, 2008 4:38:12 PM (GTB Standard Time, UTC+02:00)  #    Comments [27]   Silverlight 2.0  | 
 Thursday, December 04, 2008

Silverlight dünyasında 1.0 sürümü ile başlayan video uygulamalarındaki yüksek performans gibi avantajların yenileri 2.0 sürümünde de tabi ki devam ediyor. Bu yenilikler arasında en ilginçlerinden biri Adaptive Streaming. Bugün internet ortamında video yayını dediğimizde en büyük sorunlarımızdan biri farklı bant genişliklerine hitap edebilecek içeriği oluşturmak. Maalesef ülkemizde 1 MBit bağlantıyı baz alarak ilerlemek zorunda kalsak da aslında 4 MBit'e kadar ADSL hatlarının kullananların sayısı hiç de az değil. Peki tüm bu kullanıcılara en uygun kalitede video yayınını nasıl yapabiliriz?

Farklı bant genişliklerine farklı kalitelerde video yayını!

Bu hiç de yabancı olduğumuz bir çözüm değil. Elimizdeki video dosyasını farklı bitrate'lerde encode ederiz ve kullanıcılara sitemize girdiklerinde farklı seçenekler sunarız. Her kullanıcı kendi bağlantısına göre istediği kaliteyi seçer. Peki ya videoyu seyrederken bant genişliğinde değişiklikler olursa? Varsayalım ki kullanıcımız paylaşımlı internet bulunan bir ortamda ve kişisel olarak elde ettiği bant genişliği değişebiliyor. Bu durumda ne yapacağız? Tabi ki "Yükleniyor." mesajları göstereceğiz, yapacak pek bir şey yok! Aslında var!

Adaptive Streaming! Bırakın yayın akışı bant genişliğine uysun!

Silverlight 2.0 ile beraber kullanabildiğimiz Adaptive Streaming teknikleri ile artık videonuzun kalitesi ile kullanıcının bant genişliği arasında ilişki ile ilgilenmeniz gerekmiyor. Adaptive Streaming otomatik olarak kullanıcının bant genişliğini algılayarak uygun kalitedeki video dosyasının sunucudan çekiyor. Hatta bunu sadece video ilk oynatılırken değil video oynatıldığı sürece yapıyor! Böylece videoyu başta kaliteli bir şekilde izleyen bir kullanıcının bant genişliği düştüğünde video duracağına ve "yükleniyor" mesajları gösterileceğine videonun daha düşük kaliteli sürümlerine otomatik geçiş yapılıyor. Tabi ki bu geçişlerin hepsi otomatik olduğu üzere video duraksamıyor ve kullanıcılarımız hiçbir şey hissetmiyor. Peki tüm bunlar için biz ne mi yapıyoruz? Hmm bir kaç düğmeye tıklamak.

Expression Encoder 2 SP 1 ile gelenler!

Adaptive Streaming için video içeriği hazırlamanın birkaç yolu var. Aslında ilki oturup gerekli dosyaları tek tek encode ederek gerekli manifest XML dosyalarını da elle hazırlamak. Fakat bu zahmete girmek yerine doğrudan Expression Encoder 2'yi de kullanabilirsiniz. SP1 ile beraber Expression Encoder'a gerekli Adaptive Streaming şablonları da eklendi.

Adaptive Streaming için seçenekler.
Adaptive Streaming için seçenekler.

Video profili olarak "Adaptive Streaming"i seçtiğinizde varsayılan ayarları ile dört farklı kalitede videonun encode edilmesi sağlanacaktır. İsterseniz ek kalite sekmeleri tanımlayabilir veya var olanları değiştirebilirsiniz. Tüm bu ayarları tamamladıktan sonra sıra geliyor Adaptive Streaming için hangi altyapıyı kullanacağınıza.

Adaptive Streaming için ne kullanalım?
Adaptive Streaming için ne kullanalım?

Adaptive Streaming ile yayın yapmanın birkaç yolu var ama bunların öncesinden şu ufak detaylardan bahsedelim. Adaptive Streaming sadece HTTP üzerinden çalışıyor. Zaten Silverlight'ın MMS üzerinden de HTTP protokolü ile çalıştığını biliyoruz. O nedenle pek bir değişiklik yok fakat ek olarak burada yarattığımız tüm video dosyalarının doğrudan HTTP üzerinden yayınlanması gerektiğini hatırlatmak isterim. Yani dosyalar IIS gibi bir web sunucusunu üzerinden sunulmalı.

Yukarıdaki ekran görüntüsünde de görebileceğiniz üzere Expression Encoder bizden bir seçim daha yapmamızı istiyor. "Output Mode" olarak kastedilen aslında Adaptive Streaming için dosyaların ve Manifest'lerin nasıl hazırlanması gerektiği ile ilgili. Eğer "IIS Smooth Streaming"i işaretlerseniz manifest harici bir XML olarak tutuluyor. "ASF" seçeneği ise duruma göre tek bir dosyada tüm farklı streamleri ve manifesti veya her stream için bir dosya ve dahili manifestleri oluşturuyor.

Ama tüm bunları kullanabilene kadar yaklaşık bir altı ay kadar beklemeniz gerekecek :) Bunun nedeni "Smooth Streaming" için IIS tarafında yüklü olması gereken HTTP Handler'ların daha Microsoft tarafından yayınlanmamış olması. "Smooth Streaming" handlerlarının 2009'un ilk çeyreğinde yayınlanması bekleniyor. Tabi MS'ten önce bu konuda başka bir sunucu altyapısı için kendi HTTP Handler'ını yazan olmaz ise :) sonuçta kodlar açık.

Peki ne yapacak Smooth Streaming?

IIS tarafında çalışacak olan Smooth Streaming altyapısını şu an http://www.smoothhd.com/ adresinden test edebilirsiniz. Tabi gerçekten HD kalitesine ulaşabilmek için bağlantınızın kuvvetli olması şart aksi halde sistem düşük kaliteye otomatik olarak geçecektir.

Smooth Streaming sunucu tarafında video dosyalarını tamamen istek üzerine parçalara bölerek istemciye gönderiyor. Bu parçaları ayrı ayrı 2, 3 saniyelik video dosyaları olarak düşünebilirsiniz. Bu parçalama sistemi sayesinde internetin doğasında yer alan proxy ve cache mekanizmalarından otomatik olarak video içerikleri de faydalanmış oluyor.

İstemci tarafındaki tüm işlemler ise MediaStreamSource sınıfı ile hallediliyor. Bu sınıf ile gelen videodan kaç karenin eksik olduğu ve saniyede kaç karenin mevcut internet hattı üzerinden alınabildiği gerçek zamanlı olarak kontrol edilerek kaynak değişimi yapılabiliyor. Tüm bu işlemleri yapacak olan kodları ayrı bir AdaptiveStream sınıfı olarak Expression Encoder 2 SP1 ile beraber gelen Silverlight 2 video oynatıcılarına dahil edilmiş durumda. İsterseniz haricen bu sınıfları alıp kendi yarattığınız uygulamalara da ekleyebilirsiniz.

Şimdilik bu kadar, IIS 7 için "Smooth Streaming" yayınlandığında işin sunucu tarafına da ayrı bir yazıda değineceğiz.

Hepinize kolay gelsin.

Thursday, December 04, 2008 9:13:41 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Wednesday, December 03, 2008

Bugün Microsoft'un Yazılım Geliştiriciler Zirvesi gerçekleştirildi. Benim de sizlere daha önce duyurduğumuz üzere Silverlight 2.0 oturumunu ben sundum. Ayrıca Live Framework ile ilgili oturuma da konuk konuşmacı olarak katılma şansım oldu :)

Microsoft Yazılım Geliştiriciler Zirvesi, Silverlight 2 Oturumum
Microsoft Yazılım Geliştiriciler Zirvesi, Silverlight 2 Oturumum

45 dakika süren oturumda WCF ile sunucudan veri çekerek bir Silverlight DataGrid'inde gösterip, sıfırdan bir DeepZoom uygulaması yapıp bir de Expression Encoder ile video player yarattık. Her üç demoyu da bu 45 dakikaya sıkıştırmak için yine epey hızlı konuşmak zorunda kaldım fakat katılımcıların hepsinin de yazılımcılar olduğunu düşünürsek sanırım beni anlayabilmişsinizdir :)

Gün boyunca epey yoğun bir trafik vardı ama bir o kadar da zevkliydi. Gelen sorulardan tutun MVP standını ziyaret eden dostlara kadar her şey süperdi. Umarım aktiviteye gelen misafirlerimiz için de bir o kadar faydalı olmuştur etkinlik.

Zirvede kullandığım sunumu aşağıdaki adresten indirebilirsiniz;

Silverlight 2.0 Sunumum - 03122008_2.pptx (298,82 KB)

Hepinize kolay gelsin.

Wednesday, December 03, 2008 11:54:52 PM (GTB Standard Time, UTC+02:00)  #    Comments [12]   Seminer | Silverlight 2.0  | 
 Tuesday, December 02, 2008
Get Microsoft Silverlight

Yarın Microsoft Yazılım Geliştiriciler Zirvesi var. Daha önce size detaylarını aktardığım aktivite için Microsoft Türkiye'ye Silverlight ile bir Vista Gadget'ı hazırladık. Vista Gadget'ları hazırlamanın belki de en zor kısmı JavaScript ile uğraşmaktır. İşte bu dertten Silverlight ile kurtulabiliyoruz ve Gadget geliştirmek gerçekten çok zevkli bir hal alıyor. Tüm bu kolaylıklara ek olarak tek bir Silverlight geliştirip hem Vista Gadget'ı hem de yandaki gibi Widget tadında kullanabiliyorsunuz :)

Hazırladığımız Gadget'ı ve içerisindeki Silverlight uygulamasının kaynak kodlarını aşağıdaki adresten indirebilirsiniz;

Silverlight ile Vista Gadget Kaynak Kodları - 02122008_2.rar (206,82 KB)

Not: Normalde Silverlight uygulaması Gadget olması için yani Windows'ta çalışacak şekilde hazırlandığı için pek optimizasyonu yok o nedenle webden bu şekilde kullanımda boyutu biraz büyük kalıyor :) Şimdilik hoş görün ;)

Tuesday, December 02, 2008 11:02:38 PM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight 2.0 | Vista  | 
 Monday, December 01, 2008

Son üç gündür Isparta, Süleyman Demirel Üniversitesi'ndeydim. Cumartesi günü başladığımız INETA Boot Camp Isparta etkinliğimizde LINQ ve WCF konularını işledik. Pazar günü Microsoft'un Oyun Turu'nun da Isparta ayağını kampımıza ekleyerek dün de bahsettiğim gibi SL 2.0 ile ve XNA ile Oyun Programlama konularını inceledik. Son günümüz olan Pazartesi günü de ASP.NET Dynamic Data Web Site yapılarını göz attık sonra "Silverlight 2.0 ile Data Uygulamaları" ve "WPF" oturumlarımızı tamamladık. Böylece dolu dolu bir üç gün geçirdik.

Isparta, Süleyman Demirel Üniversitesi, INETA Boot Camp
Isparta, Süleyman Demirel Üniversitesi, INETA Boot Camp

Etkinliklere katılan hem konuşmacı arkadaşlarıma hem de sevgili öğrenci kardeşlerime çok teşekkür ediyorum. Geçen öğretim yılında da Süleyman Demirel Üniversitesi'nde gittiğimde blogumda yazmıştım hatta dün de yazmışım :) SDÜ'nün yeri benim için çok ayrı. Yukarıda resimde gördüğünüz tüm öğrencilerin Silverlight ve WPF konulu ödevleri var. Hepsi giriş seviyesini çoktan geçmiş durumda. Bu duruma tabi ki öğretim görevlilerinin katkısı çok büyük.

Özellikle organizasyonun gerçekleşmesindeki katkılarından dolayı sevgili Eğitim Görevlisi dostum Mehmet Albayrak'a çok teşekkür ediyorum.

Son gün yaptığımız bazı örnekleri toparlayıp bir poşete koydum :) aşağıdaki linkten indirebilirsiniz.

Örneklere ait kaynak dosyalar - 01122008_2.rar (2,81 MB)

Monday, December 01, 2008 2:57:22 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   ASP.NET 3.5 | Expression Blend | LINQ | Silverlight 2.0 | WCF | WPF  | 
 Sunday, November 30, 2008

Bugün Isparta, Süleyman Demirel Üniversitesi'nden Microsoft Oyun Turu'nun ikinci ayağını gerçekleştirdik. Son iki gündür ben zaten buralardayım :) Yarın sizlere bu konunun detaylarından da bahsedeceğim. Gelelim bugün neler yaptığımıza; içerik olarak İstanbul'daki ile aynı içeriği sunduk. Günün başında "Silverlight 2.0 ile Oyun Programlama" oturumu yaptık. Bu sefer İstanbul'a kıyasla daha hızlı gitme şansımız oldu. İnanmazsınız belki ama Isparta, Süleyman Demirel Üniversitesi'ndeki öğrencilerin %60'ının neredeyse Silverlight ile ödevleri var :) Hepsi dehşet bir şekilde konu ile ilgili ve en önemlisi hali hazırda "bilgili". Gelen sorular gerçekten çok kalifiyeydi.

Isparta, Süleyman Demirel Üniversitesi, Microsoft Oyun Turu
Isparta, Süleyman Demirel Üniversitesi, Microsoft Oyun Turu

Bir sonraki oturumda da XNA ile Oyun Programlama oturumunu gerçekleştirdik. Yine senaryo aynıydı :) Zaten Süleyman Demirel Üniversitesi'nden bir grup öğrencinin XNA ile programlamaya devam ettiği bir oyun projesi var. Hatta projenin konusunu da bir o kadar muhteşem. Ama şimdilik bu sürprizleri duyurmak istemiyorum :) XNA konusunda da güzel bir oturumun sonrasında sıcak bir şekilde oyun günümüzü tamamladık.

Silverlight ile oyun programlama sunumumu ve bu sefer ufak farklılıklarla sunumda hazırladığımız oyunun kodlarını aşağıdan indirebilirsiniz.

Sunum Dosyası - 30112008_2.pptx (3,29 MB)
Örnek Kaynak Kodları - 30112008_3.rar (3,18 MB)

Sunday, November 30, 2008 2:53:20 AM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Saturday, November 29, 2008

Son dönemde mail olarak aldığım en sık Silverlight development sorunlarından biri ile ilgili hızlı bir çözümü sizlerle paylaşmak istiyorum. Özellikle Silverlight Tools paketini şans eseri eksik yükleyenler veya makinalarına önce RC paketini yükleyenler sonrasında bir anda Debuging konusunda sorunlar ile boğuşmak zorunda kalabiliyorlar. Daha önceside Beta sürümlerini makinelerine yükleyenlerden hiç bahsetmek bile istemiyorum :)

Sonuç itibari ile RC ile beraber gelen Visual Studio araçları rahatlıkla kullanılabilir olsa da bazı makinelerde Silverlight tam olarak Release olduktan sonra Plug-In otomatik olarak kendisini update etmiş ve SL 2.0'ın son halini almış. Bu adımdan sonra kullanıcılar Silverlight Tools paketini yüklediklerinde sistemde zaten SL 2.0 yüklü olduğu için paket içerisinde SL 2.0 Runtime'ı sisteme yüklenmiyor. Oysa o Runtime ile normalde kullanıcılara Update mekanizmaları ile gönderilen Runtime arasında farklılıklar var :)

The silverlight managed debugging package isn't installed.

İşte tam da bu farklılıklar sizin Visual Studio 2008 içerisinde Debuging yaparken Runtime ile Visual Studio arasındaki Debug ilişkisini tutturan farklılıklar :) O nedenle ne yapmanız lazım? Silverlight 2.0'ın Developer Runtime'ını yüklemeniz gerek :) Aksi halde yazımın başlığındaki hata ile ömür boyu uğraşmak zorunda kalabilirsiniz :)

Silverlight 2.0 Developer Runtime (Win) - http://go.microsoft.com/fwlink/?LinkId=119972
Silverlight 2.0 Developer Runtime (Mac) - http://go.microsoft.com/fwlink/?LinkId=119973

Saturday, November 29, 2008 3:37:18 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, November 27, 2008

SilverNight karşınızda!

Uzun süredir hayallerim arasında olan aktivitelerden biriydi SilverNight :) Sonunda her şey hazır ve başvuruları alıyoruz. Hemen yukarıdaki banner'a tıklayarak silvernight.ms adresine ufak bir yolculuk yapıp başvurabilirsiniz.

Nasıl yani?

Şimdi durum şöyle :) Biz programcılar genelde sabahlayan insanlarız. Kod yazmak denildiğinde aklıma hemen gecenin sessiz karanlığı geliyor. Telefonların çalmadığı, maillerin gelmediği o sessizlik :) İşte tam da bu atmosferi yaratabileceğimiz ve PROJE yetiştirebileceğimiz bir aktivite tasarlayalım istedim ve ortaya SilverNight çıktı.

20 Aralık gecesi saat 22.00'da Koç Üniversitesi Rumelifeneri Kampüsü, SOS-180'de buluşuyoruz. Sonrasında 2 saat kadar mini bir Silverlight ve Video uygulamaları konusunda seminer tadında bilgi paylaşımı yapıp hemen sabaha yetiştireceğimiz projeye başlayacağız. Hedefimiz 21 Aralık sabahı saat 08.00'da Silverlight 2.0 ve ASP.NET 3.5 kullanarak hazırladığımız video portalını yayına almak!

Unutmayın bu ciddi bir iş! Projeyi yetiştiremezsek hepimiz işten kovuluruz! Sabaha sitenin kesinlikle yayına açılması gerekiyor.

Başvuru nasıl? nedir?

Maalesef kontenjanımız sınırlı. Yukarıdaki banner'a tıklayarak ulaşabileceğiniz siteden kayıt olmanız gerekiyor. Yapılacak çekiliş sonrası 25 talihli arkadaş bu efsanevi SilverNight'ı yaşama şansına sahip olacak. Ayrıca hazırlayacağımız ve sonrasında açık kaynak kodlu bir şekilde CodePlex.com üzerinden paylaşacağımız Video Portalı'nın ilk yapı taşlarında emeğiniz olacak. Kim bilir belki müşterimiz eklemeler ister ve ileride tekrar bir gece daha sabahlarız?

Ulaşım

Merak etmeyin Rumelifeneri'nin evinize yakın olma ihtimalinin düşük olduğunu biliyoruz. O nedenle 20 Aralık günü Taksim'den servisimiz kalkacak. Daha detaylı bilgiyi 25 talihli arkadaşımıza ayrıca ileteceğiz ;)

Hadi bakalım, başvuruları bekliyorum ;)

Not: Lütfen "hocam bir kıyak geçin biz gelelim" gibi mailler gelmesin :)

Thursday, November 27, 2008 3:34:15 AM (GTB Standard Time, UTC+02:00)  #    Comments [39]   Silverlight 2.0  | 
 Wednesday, November 26, 2008

Bugün YTÜ, Davutpaşa Kampüsü'ndeydim. Güne ağır bir LINQ oturumu ile başladık :) Biraz herkesi sıkıntı bastı :) Sonra yemek molası ile dinlenip WPF ve Silverlight oturumlarına geçtik. Günün sonunda aldığım tepkiler ne mutlu ki her zamanki gibi muhteşemdi. YTÜ'nün Davutpaşa Kampüsü'ndeki enerjisi Beşiktaş Kampüsü'nden açık ara önde :) Böylece mini bir gaz da vermiş olayım :)

YTÜ, Davutpaşa Kampüsü, LINQ, Silverlight ve WPF Seminerleri
YTÜ, Davutpaşa Kampüsü, LINQ, Silverlight ve WPF Seminerleri

Çok eğlendiğim, süper yorumlar almanın yanı sıra seminerler esnasında sorduğum sorulara da burada yer veremeyeceğim derecede fantastik cevaplar aldığım bir gün oldu :) Katılan tüm arkadaşlara çok teşekkürler.

Organizasyondaki katkılarından dolayı sevgili Bahar Göktepe ve Mehmet Cengiz'e çok teşekkürler.

 

Wednesday, November 26, 2008 3:04:24 AM (GTB Standard Time, UTC+02:00)  #    Comments [10]   LINQ | Seminer | Silverlight 2.0 | WPF  | 
 Monday, November 24, 2008

Microsoft Yazılım Geliştiriciler Zirvesi

2008 yılının son günlerinde yaklaşırken yurt dışında Microsoft'un Professional Developer Conference'ı sonrasında Türkiye'de de Microsoft Yazılım Geliştiriciler Zirvesi 3 Aralık'ta Sheraton'da gerçekleşecek. Bu sene "Derinlere dalıyoruz" sloganı ile yola çıkılan günde benim de Silverlight 2.0 oturumum yer alıyor. Aktivite ağırlıklı olarak kurumsal katılımcılara hitap edecek.

Katılım öncesi kayıt olmak için buradan ilerleyebilirsiniz.  

Monday, November 24, 2008 4:12:09 AM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Sunday, November 23, 2008

Deep Zoom konusunda daha önce de makaleler yazmış hatta güzel bir de 3D örneği sizlerle kaynak kodları ile paylaşmıştım. Deep Zoom uygulamalarını ve fotoğraf paketlerini hızlı bir şekilde oluşturmamızı sağlayan Deep Zoom Composer yeni sürümü ile karşımızda. Aşağıdaki adresten uygulamayı bilgisayarınıza indirebilirsiniz.

http://xpression2.members.winisp.net/DZC/Deep%20Zoom%20Composer.msi

Yeni neler var?

En büyük yenilik artık Silverlight DeepZoom'un haricinde JavaScript bazlı DeepZoom projeleri de yaratabiliyor olmamız. Yanlış duymadınız :) DeepZoom işlevselliği sağlayan JavaScript bazlı çıktılardan bahsediyorum. Tabi ki JavaScript ile beslenen bu yapının Silverlight gibi bir işlemci kullanımına sahip olmasını bekleyemeyiz, ayrıca geçişler arası animasyonlar vs de yok. Ama Silverlight'a bir alternatif olarak yerine göre belki uygun bir çözüm de olabilir.

SeaDragon AJAX seçeneği JavaScript bazlı Deep Zoom projesi yaratıyor.
SeaDragon AJAX seçeneği JavaScript bazlı Deep Zoom projesi yaratıyor.

Bunun haricinde arka tarafta bir çok bug'ın giderilmesinin yanı sıra Deep Zoom Composer'ın Image Set'leri oluşturan kodlarının da ayrı DLLler haline getirilmesi gibi işlemler var. Böylece kendi Deep Zoom Composer'ınızı da yazabilirsiniz ;)

Hepinize kolay gelsin.

Sunday, November 23, 2008 2:25:29 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   AJAX | Silverlight 2.0  | 
 Thursday, November 20, 2008

Hatırlarsanız geçen hafta sonu Cumartesi günü Microsoft Türkiye'de Oyun Turu'nun ilk ayağını İstanbul ofisinde gerçekleştirmiştik. Hatta onun sonrasında ben de gaza gelip minik bir oyun yazmış ve sizlerle kaynak kodlarını paylaşmıştım. İtiraf etmeliyim söz konusu oyun tahmin ettiğimden daha çok ses getirdi :)

Aktiviteye katılamayanlara söz verdiğim üzere aktivitenin video kayıtlarını aldık. "Silverlight 2.0 ile Oyun Programlama" oturumunun kayıtlarını sizlerle paylaşıyorum. Aşağıdan hemen izleyebilirsiniz. Ayrıca blogumun SeminerTV bölümünden de isterseniz video dosyasını doğrudan bilgisayarınıza indirebilirsiniz.

Hepinize iyi seyirler ;)

Thursday, November 20, 2008 1:16:22 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Wednesday, November 19, 2008

AutoComplete işlevselliği AJAX günlerinden alışık olduğumuz bir sistem. Herhangi bir TextBox'a kullanıcı yazı yazarken aynı anda uygun alternatifleri göstermek ve aslında arka planda bir arama sistemi kurmak gibi işlemleri uzun zamandır farklı arayüz araçları kullansak da bir şekilde programcılar olarak hazırlayabiliyoruz. Silverlight tarafında ise Silverlight'ın görsel gücünden de faydalanarak çok ilginç çözümler üretmek mümkün. Silverlight dünyasında AutoComplete altyapılarını incelerken Silverlight Toolkit içerisindeki AutoCompleteBox kontrolünü kullanacağız.

Not: Silverlight Toolkit'i kullanabilmeniz için CodePlex üzerindeki adresten kütüphaneyi indirerek içerisindeki Microsoft.Windows.Controls.dll dosyasını projenize referans olarak eklemelisiniz.

En hızlı şekilde AutoCompleteBox kullanımı..

AutoCompleteBox'ın kullanımı aslında çok basit. Hemen bir String Array veya List yaratarak AutoCompleteBox'a bind etmeniz yeterli olacaktır. Tüm filtreleme ve AutoComplete işlemleri otomatik olarak yapılacaktır.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Liste As New List(Of String)

        Liste.Add("ASP.NET")

        Liste.Add("AJAX")

        Liste.Add("Silverlight")

        Liste.Add("WPF")

        AutoComplete1.ItemsSource = Liste

    End Sub

[C#]

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

                List<String> Liste = new List<string>();

                Liste.Add("ASP.NET");

                Liste.Add("AJAX");

                Liste.Add("Silverlight");

                Liste.Add("WPF");

                AutoComplete1.ItemsSource = Liste;

        }

Yukarıdaki kod ile hazırladığımız basit bir uygulamanın aşağıda da XAML kodunu inceleyebilirsiniz.

[XAML]

<UserControl x:Class="SilverlightApplication3.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

    <Grid x:Name="LayoutRoot" Background="White">

      <controls:AutoCompleteBox Height="24" Margin="24,24,144,0" VerticalAlignment="Top" x:Name="AutoComplete1"/>

    </Grid>

</UserControl>

Basit bir AutoComplete örneği.
Basit bir AutoComplete örneği.

AutoCompleteBox'ın özellikleri.

IsTextCompletionEnabled - Bu özellik açık olduğunda kullanıcı yazı yazdıkça sadece alternatifler gösterilmez, ek olarak en yakın alternatif sanki yazılmış gibi TextBox içerisinde de gösterilir. Varsayılan değeri True şeklindedir.

SelectedItem - Eğer kullanıcı AutoCompleteBox'ın açılan ListBox kısmından bir öğe seçerse SelectedItemChanged çalışır ve SelectedItem geriye bir Item döndürür. Kullanıcı ListBox içerisinde yer alan bir Item'ın metnini elle yazmışsa SelectedItem geriye değer döndürmeyecektir.

SearchMode - AutoComplete işlemi yapılırken kaynak veride ne şekilde arama yapılacağına karar veren SearchMode özelliği varsayılan değeri olan StartsWith ile gelir. İsterseniz Contains seçeneğini seçerek doğrudan kaynak verinin içindeki tüm metinlerin içinde arama yapılmasını da sağlayabilirsiniz. Eğer kendi arama sisteminizi entegre edecekseniz None seçeneğini seçmeniz gerekecektir.

MinimumPopulateDelay - Kullanıcı yazı yazarken ne kadar süre sonra alternatiflerin gösterileceğini belirler. Eğer veri kaynağı istemci tarafında bir Silverlight değişkeni ise varsayılan değer olan 0 ile herhangi bir sorun yaşamazsınız. Fakat alternatifleri sunucudan her seferinde çekiyorsanız buradaki bekleme süresini uzatmakta büyük fayda olacaktır.

MinimumPrefixLength - Alternatifler gösterilmeden önce kaç karakterlik verinin girilmiş olması gerektiğine dair ayar bu özellik üzerinden yapılabilir.

Kendi filtreleme mekanizmamızı yazalım.

Bir AutoCompleteBox'ı aslında iki şekilde veri bağlamış olabiliriz. Bunlardan birincisi yazımızın başındaki gibi basit bir metin dizisini AutoCompleteBox'a aktarmak ikincisi ise kendi tanımladığımız nesnelerin bir dizisini bağlamak. Gelin her iki durumda da filtreleme işlemlerini nasıl özelleştirebileceğimize bakalım.

Bir önceki örneğimizin üzerinden yola devam edersek zaten hali hazırda bir String listesini alıp AutoCompleteBox'ımıza bağlamıştık. AutoCompleteBox'ın TextFilter özelliğini değiştirirek filtreleme işleminin tam olarak nasıl yapılacağına karar verebiliriz. Bizim yapacağımız örnekte kullanıcının yazdığı metin ile başlayan değil de biten öğeleri göstermeye çalışacağız.

[VB]

    Function Filtreleme(ByVal Search As String, ByVal item As String)

        If item.ToString.EndsWith(Search) Then

            Return True

        Else

            Return False

        End If

    End Function

[C#]

        public bool Filtreleme(string Search, string item)

        {

            if (item.ToString().EndsWith(Search)) {

                return true;

            }

            else {

                return false;

            }

        }

Yukarıdaki fonksiyonumuzu filtreleme işlemlerini yapmak için kullanacağız. Gelen iki parametreden ilki kullanıcının TextBox içerisine yazdığı metin, ikincisi ise o an fonksiyonumuza aktarılan ana kaynak veriden gelen bir Item. Burada kafalar biraz karışabilir o nedenle biraz daha detaya inelim. AutoCompleteBox filtreleme işlemini yaparken elindeki verinin içindeki her bir öğeyi tek tek bizim filtreleme fonksiyonumuza verecek ve söz konusu öğenin gösterilip gösterilmeyeceğine dair bir cevap bekleyecek. Yani eğer veri kaynağında 10 adet öğe varsa bu fonksiyon 10 defa çağrılacak.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Liste As New List(Of String)

        Liste.Add("ASP.NET")

        Liste.Add("AJAX")

        Liste.Add("Silverlight")

        Liste.Add("WPF")

 

        AutoComplete1.TextFilter = New Microsoft.Windows.Controls.AutoCompleteSearchPredicate(Of String)(AddressOf Filtreleme)

        AutoComplete1.ItemsSource = Liste

    End Sub

[C#]

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

                List<String> Liste = new List<string>();

                Liste.Add("ASP.NET");

                Liste.Add("AJAX");

                Liste.Add("Silverlight");

                Liste.Add("WPF");

 

                AutoComplete1.TextFilter = new Microsoft.Windows.Controls.AutoCompleteSearchPredicate<string>(Filtreleme);

                AutoComplete1.ItemsSource = Liste;

        }

Hazırladığımız filtreleme fonksiyonunu tabi ki AutoCompleteBox'ın TextFilter'ına da aktarmamız gerek. Yukarıdaki kodlardaki kalın satırlarda söz konusu aktarma işleminin nasıl yapıldığını inceleyebilirsiniz. TextFilter bizden bir AutoCompleteSearchPredicate istiyor, biz de kendisine istediğini veriyoruz :)

Peki ya AutoCompleteBox'a kendi yarattığımız nesne türlerinden bir liste bağlamış olsaydık bu filtreleme işlemini nasıl yapacaktık. Böyle bir durumda TextFilter yerine ItemFilter'ı kullanmak zorunda kalacaktık. Gelin ilk olarak örneğimizde ilerleyebilmek için Kitap adında kendi sınıfımızı tanımlayalım.

[VB]

    Public Class Kitap

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

        Private PFiyat As Double

        Public Property Fiyat() As Double

            Get

                Return PFiyat

            End Get

            Set(ByVal value As Double)

                PFiyat = value

            End Set

        End Property

 

    End Class

[C#]

        public class Kitap

        {

            public string Adi { get; set; }

            public double Fiyat { get; set; }

        }

Şimdi bu sınıflar üzerinden yola çıkarak Silverlight tarafında birkaç kitap yaratıp AutoCompleteBox'larımıza DataBind edeceğiz.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Liste As New List(Of Kitap)

        Liste.Add(New Kitap With {.Adi = "ASP.NET AJAX", .Fiyat = 25})

        Liste.Add(New Kitap With {.Adi = "ADO.NET", .Fiyat = 35})

        Liste.Add(New Kitap With {.Adi = "WPF", .Fiyat = 15})

        Liste.Add(New Kitap With {.Adi = "Silverlight", .Fiyat = 25})

 

        AutoComplete1.ItemFilter = New Microsoft.Windows.Controls.AutoCompleteSearchPredicate(Of Object)(AddressOf Filtreleme)

 

        AutoComplete1.ItemsSource = Liste

    End Sub

[C#]

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

 

                  List<Kitap> Liste = new List<Kitap>();

        Liste.Add(new Kitap  {Adi = "ASP.NET AJAX", Fiyat = 25});

        Liste.Add(new Kitap  {Adi = "ADO.NET", Fiyat = 35});

        Liste.Add(new Kitap  {Adi = "WPF", Fiyat = 15});

        Liste.Add(new Kitap  {Adi = "Silverlight", Fiyat = 25});

 

        AutoComplete1.ItemFilter = new Microsoft.Windows.Controls.AutoCompleteSearchPredicate<Object>(Filtreleme);

 

        AutoComplete1.ItemsSource = Liste;

        }

Kodumuz içerisinde çok büyük değişiklikler yok. Bu sefer bir String listesi yerine Kitap listesi yaratıyor ve AutoCompleteBox'ın ItemsSource'una eşitliyoruz. Filtreleme işlemi için yine Filtreleme adında bir metod kullanacağımız için ItemFilter özeliğine de söz konusu metodu bağlıyoruz. Aradaki en önemli fark elimizdeki Predicate'in artık Object türünü taşıyor olması.

[VB]

    Function Filtreleme(ByVal Search As String, ByVal item As Object)

        If CType(item, Kitap).Fiyat < CInt(Search) Then

            Return True

        Else

            Return False

        End If

    End Function

[C#]

        public bool Filtreleme(string Search, object item)

        {

            if (((Kitap)item).Fiyat < int.Parse(Search)) {

                return true;

            }

            else {

                return false;

            }

        }

Filtreleme metodumuzun ikinci parametresi artık Object tipinde. Biz aslında buradaki değişkenin bir Kitap nesnesi olduğunu biliyoruz çünkü AutoCompleteBox tek tek kendisine verilen öğeleri bu filtreleme fonksiyonuna iletecektir. Bu nedenle elimizde gelen objeyi Kitap tipine cast edip bu sefer de kitapların fiyatları üzerinden filtreleme yapıyoruz. Kullanıcıların TextBox içerisinde sayısal bir fiyat gireceğini ve bu fiyatın altındaki kitapların listeleneceğini varsayalım.

Bu şekilde uygulamamızı çalıştırırsak ufak bir karışıklık olacaktır. AutoCompleteBox'a bağladığımız veri Kitap'lardan oluşuyor. Peki AutoCompleteBox bu Kitap nesnelerinin hangi özelliğini ekrana nasıl getirecek? Örneğin kitabın adını mı yoksa fiyatını mı gösterecek AutoComplete esnasında? İşte bu noktada da bizim XAML tarafına geçip birkaç işlem yapmamız gerek.

[XAML]

<UserControl x:Class="SilverlightApplication3.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

  <UserControl.Resources>

    <DataTemplate x:Key="DataTemplate1">

      <Grid>

        <TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Path=Fiyat}" TextWrapping="Wrap"/>

      </Grid>

    </DataTemplate>

  </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">

      <controls:AutoCompleteBox Height="24" Margin="24,24,144,0" VerticalAlignment="Top" x:Name="AutoComplete1" ItemTemplate="{StaticResource DataTemplate1}"/>

    </Grid>

</UserControl>

Artık bizim AutoCompleteBox'ımızın ItemTemplate'ini değiştirmemiz ve özelleştirmemiz gerekiyor. Böylece tam olarak gelen veriden hangi öğelerin nerelerde nasıl gösterileceğine karar verebiliriz. Yukarıdaki kod içerisinde AutoCompleteBox'ın ItemTemplate özelliğinin değiştirildiğini görebilirsiniz. DataTemplate1 adında yarattığımız DataTemplate'i UserControl.Resources içerisine koyup kullanabiliyoruz. DataTemplate içerisinde ise bir Grid ve TextBlock bulunuyor. Söz konusu TextBlock doğrudan Fiyat adında bir Field'e DataBind edilmiş durumda. Hatırlarsanız bizim Kitap sınıfımızın Fiyat adında bir Property'si vardı. Böylece AutoCompleteBox'a kendisine verilen verilerden her birinin Fiyat özelliğinin DataTemplate içerisindeki bu TextBlock'un Text'ine bağlanmasını sağladık. Tüm bu işlemleri Visual Studio içerisinde XAML yazarak yapabileceğiniz gibi isterseniz Expression Blend'in arayüzünden de tabi ki daha rahatlıkla yapabilirsiniz. Tek yapmanız gereken AutoCompleteBox'a sağ tuş tıklayıp gelen menüden "Edit Other Templates / Edit ItemTemplate" demek. Böylece tasarım modunda Blend içerisinde de DataTemplate'in görselliğini değiştirebilirsiniz.

Artık filtreleme işlemlerini bitirdik, filtreleme esnasından Kitapların sadece fiyatlarının gözükmesini de sağladık. Fakat neden sadece fiyatları gözüksün ki? Kullanıcı TextBox içerisinde 25 yazdığınzda 25YTL'den ucuz kitapların hem adı hem fiyatı yazsa? Ve bunların arasından bir kitap seçilince fiyatı otomatik olarak TextBlock içerisine yerleşse daha güzel olmaz mı? AutoCompleteBox'ın açılan kısmının görselliğini ne de olsa yukarıda değiştirmiştik, gelin şimdi ikinci bir TextBlock ekleyerek onu da Kitap nesnelerinin Adi özelliğine bağlayalım.

[XAML]

    <DataTemplate x:Key="DataTemplate1">

      <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{x:Null}" Orientation="Horizontal">

        <TextBlock Text="{Binding Path=Adi}" Foreground="#FFFF0000" Height="Auto" Width="Auto"/>

        <TextBlock Text="{Binding Path=Fiyat}" Foreground="#FF838383" Height="Auto" Width="Auto"/>

        <TextBlock Text="YTL" TextWrapping="Wrap" Foreground="#FF838383" Height="20" Width="20"/>

      </StackPanel>

    </DataTemplate>

Gördüğünüz gibi DataTemplate'i değiştirerek aslında işimizi çözmüş olduk. Geriye tek bir sorun kalıyor. Kullanıcı herhangi bir Item'ı ListBox içerisinden seçtiğinde TextBox'ın içine ne yazılacak? Kitap nesnesinin Adi mı? yoksa Fiyatı mı? Tabi ki bizim örneğimizde Kitap nesnesinin fiyatı yazılacak aksi halde filtreleme mekanizmamızla çakışacaktır.

[VB]

  Public Class Kitap

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

        Private PFiyat As Double

        Public Property Fiyat() As Double

            Get

                Return PFiyat

            End Get

            Set(ByVal value As Double)

                PFiyat = value

            End Set

        End Property

 

        Public Overrides Function ToString() As String

            Return Me.Fiyat

        End Function

 

    End Class

[C#]

        public class Kitap

        {

            public string Adi { get; set; }

            public double Fiyat { get; set; }

 

            public override string ToString()

            {

                return this.Fiyat.ToString();

            }

        }

Bu da ne şimdi? dediğinizi duyar gibiyim. Maalesef AutoCompleteBox'ın ListBox'tan seçili öğelerin hangi özelliklerinin alınacağına dair bir ayarı yok. Aslında arka planda AutoCompleteBox kendi içerisinde bir öğe seçildiğinde o öğeyi ToString() metodu ile alıp TextBox içerisine yerleştiriyor. Bu durumda bizim de ToString metodunu Override etmemiz her şeyi çözecektir. Artık herhangi bir Kitap nesnesi üzerinden ToString çalıştırılırsa kitabın fiyat bilgisi verilecek.

Özelleştirilmiş bir AutoCompleteBox örneği.
Özelleştirilmiş bir AutoCompleteBox örneği.

Hepinize kolay gelsin.

Wednesday, November 19, 2008 8:03:42 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, November 18, 2008

Silverlight ilk çıktığı günlerde en çok şaşırdığımız noktalar biri "Label" adında bir kontrolün bulunmamasıydı. İşlevsellik olarak aynı çözümü sunan TextBlock kontrolünü çok kısa bir sürede keşfetmiş olsak da neden isminin değiştiğini pek anlayalamıştık. Bugünlerde Silverlight Toolkit paketi ile beraber özel bir Label kontrolü geldi.

Nedir TextBlock ile Label'ın farkı?

Aslında kaba tanımı ile TextBlock kontrolü Label'ın yapı taşıdır. Bir Label kontrolü ControlTemplating desteklerken TextBlock desteklemez. Zaten Label Template'leri oluştururken biz de TextBlock'lardan faydalanacağız. Özetle Label'lar gelişmiş TextBlock kontrolleridir de diyebiliriz. Sözü daha çok uzatmadan gelin neler yapabildiğimize göz atalım.

Not: Silverlight Toolkit'i kullanabilmeniz için CodePlex üzerindeki adresten kütüphaneyi indirerek içerisindeki Microsoft.Windows.Controls.dll dosyasını projenize referans olarak eklemelisiniz.

Bir Label kontrolünü Silverlight Toolkit'in referans alınmış olduğu herhangi bir projede rahatlıkla kullanabilirsiniz. Expression Blend içerisinde "Asset Library" kısmında "Custom Controls" sekmesinde Label kontrolünü bulabilirsiniz. TextBlock'larda da oluğu gibi herhangi bir Label içerisine yazı yazmak için Content özelliğinden faydalanabilirsiniz.

[XAML]

<UserControl x:Class="SilverlightApplication2.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

    <Grid x:Name="LayoutRoot" Background="White">

      <controls:Label HorizontalAlignment="Left" VerticalAlignment="Top" Content="Deneme Amaçlı Metin"/>

    </Grid>

</UserControl>

Basit bir şekilde Label kontrolünün kullanımına dair yukarıdaki XAML kodunu inceleyebilirsiniz. Bir TextBlock ile Label kontrolünü birbirinden ayıran özelliklerden ilki Label kontrolünün BorderBrush alabiliyor olması. Hatta sadece bu kadarla kalmayıp bir Label'ın hangi kenarlarında Border bulunacağına da karar verebiliyorsunuz.

Label kontrolünün BorderBrush ayarları.
Label kontrolünün BorderBrush ayarları.

Aynı şekilde isterseniz bir Label için Background da belirleyebilirsiniz. Fakat makalemizin başından beridir bahsettiğimiz Label'ın en önemli özelliği aslında ControlTemplating'e olanak tanıması. Gelin şimdi Expression Blend içerisinde Label kontrolümüze sağ tıklayarak gelen menüden "Edit Control Parts / Create Empty" komutunu verelim. Böylece hali hazırda sahnede olan Label'ın görselliği yok varsayılarak bizim Label kontrolünün yapısını tekrar tasarlayabilmemiz sağlanacak. Bunun için ilk aşamada karşınıza gelen pencerede bu şablona bir de isim vermeniz gerek. Unutmayın hazırlanan şablonlar sonrasında birden çok Label'a linklenerek merkezi bir yerden kullanılabilir.

Label kontrolü için yeni bir ControlTemplate yaratıyoruz.
Label kontrolü için yeni bir ControlTemplate yaratıyoruz.

ControlTemplate'imizi yarattıktan sonra Blend bizi otomatik olarak Template tasarımına götürecektir. Bu sahnede otomatik olarak gelen Grid nesnesini bir Canvas'a çevireceğiz. Bu seçimi tamamen örneğin kolay ilerlemesi için yapıyoruz. Siz kendi tasarımlarınızda farklı Layout kontrolleri tabi ki kullanabilirsiniz.

ControlTemplate tasarımımız bitmek üzere.
ControlTemplate tasarımımız bitmek üzere.

Tasarımımızda Canvas'ın içerisinde bir Rectangle koyarak Fill özelliğine de Radial bir GradientBrush atadık. Rectangle'ın önünde de bir TextBlock koyuyoruz. Label içerisinde metni gösterecek olan bu TextBlock kontrolü olacak. Label kontrolünün Content özelliğine verilen değerlerin otomatik olarak şablon içerisinde bu TextBlock'un Content'ine aktarılmasını sağlamalıyız. Bunu da ancak TemplateBinding ile yapabiliriz.

Blend arayüzünden TemplateBinding ayarlarımızı yapıyoruz.
Blend arayüzünden TemplateBinding ayarlarımızı yapıyoruz.

Blend'in arayüzünde şablonumuzu tasarlarken TextBlock kontrolümüzü seçtikten sonra ekranın sağında kalan "Properties" sekmesinden söz konusu TextBlock'un Content özelliğini ayarladığımız yerin hemen yanındaki ufak kareye tıklıyoruz. Gelen menüden "Template Binding" komutunu verdikten sonra Blend bize ana kontrolün hangi özelliğinin şablondaki bahsi geçen özelliğe bağlanacağını soruyor. Tabi biz de hemen Content özelliğini seçiyoruz. Böylece Label kontrolünün Content özelliğini şablonun içindeki TextBlock'un Content özelliğine bağlamış olduk.

Template tasarımı modundan çıkalım.
Template tasarımı modundan çıkalım.

Artık tasarımımızı tamamladığımızda göre şablon tasarım modundan çıkıp ana uygulamaya geri dönebiliriz. Artık Label kontrolünün Content'ini değiştirdiğinizde ayarladığınız görsellik içindeki Textblock'a yerleştiğini görebilirsiniz. En güzel de yeni bir Label eklediğinizde aynı şablonu kullanmasını sağlayabilirsiniz.

Hazırladığımız şablonu istediğimiz Label kontrolünde kullanabiliriz.
Hazırladığımız şablonu istediğimiz Label kontrolünde kullanabiliriz.

Uygulamanıza yeni bir Label ekledikten sonra hazırladığınız şablonu bu Label üzerinde de kullanmak istiyorsanız doğrudan söz konusu Label'a sağ tuş ile tıklayarak gelen menünden "Edit Control Parts / Apply Resource" diyerek şablonunuzu adı ile seçebilirsiniz. Böylece geri dönüp bu şablonda bir değişiklik yaptığınızda birden çok Label'da değişiklik yapmış olacaksınız. Merkezi yönetim :)

Yaptığımız tüm işlemlerin sonucunda aşağıdaki XAML kodu yaratılıyor.

[XAML]

<UserControl x:Class="SilverlightApplication2.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

  <UserControl.Resources>

    <ControlTemplate x:Key="DenemeSablon" TargetType="controls:Label">

      <Canvas>

        <Rectangle Height="50" Width="200" Stroke="#FF000000">

          <Rectangle.Fill>

            <RadialGradientBrush>

              <GradientStop Color="#FF000000"/>

              <GradientStop Color="#FFFFFFFF" Offset="1"/>

            </RadialGradientBrush>

          </Rectangle.Fill>

        </Rectangle>

        <TextBlock TextWrapping="Wrap" HorizontalAlignment="Stretch" Canvas.Top="17" Canvas.Left="45.348" Foreground="#FFFFFFFF" Text="{TemplateBinding Content}"/>

      </Canvas>

    </ControlTemplate>

  </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">

      <controls:Label HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="#FFFF0000" BorderThickness="10,0,5,0" Template="{StaticResource DenemeSablon}" Content="Tamamen Denemedir"/>

    </Grid>

</UserControl>

Yukarıdaki kodda özellikle önemli olan birkaç nokta var. İlk olarak nasıl olmuş da Label'ımız UserControl.Resources altındaki DenemeSablon adlı şablona bağlanmış? TemplateBinding'in kodu nasıl yazılmış? Tüm bunların cevaplarını kod içerisinde kalın yazılı bölümlerde bulabilirsiniz.

Label'a DataBinding nasıl yapılır?

Bir Label'e neden DataBind yapmak isteyelim? Sonuçta sadece Text göstermeyecek mi? Ve bu Text'in değişme şansı da yok ki TwoWayBinding vs gereksin? Tüm bu soruların cevabı aslında yukarıdaki ControlTemplating ile de alakalı. Bir Label düşünün ki kendisine Bind edilmiş nesneye göre şekil alabiliyor? Ne dersiniz?

Bir önceki örneğimizden devam edelim. Varsayalım ki Label'ımızda bir ürünün adını göstereceğiz fakat ürünün satış miktarına göre de Label'ın arkasında Gradient'ın (Aslında Rectangle) şeffaflaşmasını veya görünür olmasını istiyoruz. Bunun için ilk olarak gelin kontrolümüzün tasarımını biraz değiştirelim.

DataBind yapacağımız Label kontrolünün şablonunu biraz değiştirdik.
DataBind yapacağımız Label kontrolünün şablonunu biraz değiştirdik.

Sadece renklerde biraz değişiklik yaptık. Böylece arkadaki Rectangle tamamen şeffaf olsa da yazı görünebilecek. Şimdi geçelim kod tarafına ve bu Label'a nasıl veri bağlarız ona bakalım.

İlk olarak Label'a bağlayacağım Urun'ümüzün bir sınıf olarak programatik anlamda tanımlamamız gerekiyor.

[VB]

    Public Class Urun

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

        Private PSatis As Double

        Public Property Satis() As Double

            Get

                Return PSatis

            End Get

            Set(ByVal value As Double)

                PSatis = value

            End Set

        End Property

 

    End Class

[C#]

    public class Urun

    {

        public string Adi { get; set; }

        public double Satis { get; set; }

    }

Gördüğünüz üzere Urun sınıfımızın iki Property'si var. Bunlardan ilki ürünün ismini saklayacak olan Adi, diğeri ise Satis miktarı. Özellikle Satis Property'sinin Double olarak tanımlandığına dikkat edelim. Herhangi bir Convertor kullanmadan bu Property'si Bind edeceğimiz için Opacity ile uyumlu şekilde 1 ile 0 arasında Double değerler taşımalı.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Etiket.DataContext = New Urun() With {.Adi = "Bir ürün adı", .Satis = 0.5}

    End Sub

[C#]

    private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e)

    {

        Etiket.DataContext = new Urun { Adi = "Bir ürün adı", Satis = 0.5 };

    }

Kodumuzda basit bir şekilde yeni bir ürün yaratarak Etiket adındaki Label kontrolümüze DataContext özelliği üzerinden bağlıyoruz. Peki Adi ve Satis Property'leri Label içerisinde neleri etkileyecek? İşte bunun için ayrıca XAML tarafında ayarlar yapmamız gerek.

Rectangle'ın Opacity'sinin DataBinding ayarlarını yapıyoruz.
Rectangle'ın Opacity'sinin DataBinding ayarlarını yapıyoruz.

Blend tarafında Label kontrolünün şablonuna tekrar geri dönüyoruz. Daha önce yarattığımız ControlTemplate'i açarak üzerinde değişiklikler yapmamız gerekiyor. İlk olarak şablon içerisinde Rectangle'ı seçerek Properties tabından Opacity'sinin yanında ufak kareye tıklıyoruz ve gelen menüden "Custom Expression" komutunu seçiyoruz. Böylece artık binding ile ilgili ayarı doğrudan el ile yazacağız.

DataBinding için Custom Expression yazıyoruz.
DataBinding için Custom Expression yazıyoruz.

Yazdığımız Custom Expression ile artık Label kendi içindeki Rectangle'ın Opacity değerinin kendisine verilen datadan geleceğini ve bağlanması gereken Property'nin adının da Satis olduğunu biliyoru. Aynı işlemi ControlTemplate içerisindeki TextBlock için de yaparak bu sefer TextBlock'un Content özelliğini Adi Property'sine {Binding Adi} Custom Expression'ı ile bağlamamız gerek.

Tüm bu işlemleri yaptıktan sonra uygulamayı çalıştırdığınızda bağladığınız verideki ürün adının TextBlock içerisine yerleştiğini ve gelen satış bilgisine göre de arkadaki Rectangle'ın şeffaflığının belirlendiğini görebilirsiniz. Böylece gelen veriye göre görselliğini değiştiren bir Label tasarlamış olduk.

Hepinize kolay gelsin.

Tuesday, November 18, 2008 5:57:33 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, November 17, 2008

WPF'den Silverlight dünyasına geçince eksiğini hissettiğimiz kontrollerin Silverlight Toolkit projesi ile sağlanmaya çalışıldığına dair daha önceki yazılarımda ufak ipuçları vermiştim. Bu sefer de yine Toolkit içerisinde ViewBox kontrolünü inceleyeceğiz. ViewBox hali hazırda WPF içerisinde bulunan bir Layout kontrolü. Silverlight tarafında ise herhangi bir muadilinin olmaması bazı durumlarda ciddi sıkıntı yaratabiliyor.

Peki nedir ViewBox?

İster WPF ister Silverlight tarafında olun sahnenin planını Layout kontrolleri dediğimiz kontroller ile düzenlemek durumundasınız. Bu kontrollerin her birinin birbirinden farklı özellikleri var. Tüm bu özellikleri göz önünde aldığımızda ViewBox'ın eşsiz olduğu nokta içerisindeki tüm nesneleri vektörel olarak görsel anlamda tekrar boyutlandırabiliyor olması. Birkaç görsel örnek ile konuyu netleştirelim.

Not: Silverlight Toolkit'i kullanabilmeniz için CodePlex üzerindeki adresten kütüphaneyi indirerek içerisindeki Microsoft.Windows.Controls.dll dosyasını projenize referans olarak eklemelisiniz.

Grid içerisinde 5 farklı Ellipse'in değişen durumları.
Grid içerisinde 5 farklı Ellipse'in değişen durumları.

Yukarıdaki gibi bir Grid içerisinde bulunan nesneler Grid'in kenarlarından olan uzaklarına ve farklı hizalama bilgilerine göre konumlandırılırlar. Bu nedenle Grid'in boyutu değiştiğinde nesnelerin kenarlara olan uzaklıklarını sabit tutabilmek adına nesneler garip şekillerde boyutlandırılır. Oysa biz bu Grid'in boyutlandırırken içindeki görselliği doğrudan aynı şekilde büyütmesini istiyorduk hem de vektörel olarak. Maalesef Silverlight 2.0 ile beraber hali hazırda gelen ve bu işlevselliği sağlayacak hiçbir Layout kontrolü yok! Tabi bu durum "Böyle bir Layout kontrolü yazılamaz" anlamına gelmiyor :) Nitekim yazmışlar ve Silverlight Toolkit içerisinden de biz ViewBox kontrolünü alıp kullanabileceğiz.

ViewBox kontrolümüzü kullanalım.

Silverlight Toolkit'i projenize referans olarak aldıktan sonra Expression Blend içerisinde doğrudan "Asset Library"'de "Custom Controls" tabında "ViewBox" kontrolünü bulabilirsiniz. Bir önceki bölümdeki görsel örneğimizde kullandığımız Grid'i gelin bir ViewBox içerisine yerleştirelim.

[XAML]

<UserControl x:Class="SilverlightApplication1.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

    <Grid x:Name="LayoutRoot" Background="White">

        <controls:Viewbox Margin="24,24,176,108">

          <Grid Height="Auto" Width="Auto">

            <Ellipse Margin="8,8,8,8" Fill="#FFFF0000" Stroke="#FF000000"/>

            <Ellipse Height="16" HorizontalAlignment="Left" Margin="56,40,0,0" VerticalAlignment="Top" Width="32" Fill="#FFFFFFFF" Stroke="#FF000000"/>

            <Ellipse Height="16" HorizontalAlignment="Right" Margin="0,40,48,0" VerticalAlignment="Top" Width="32" Fill="#FFFFFFFF" Stroke="#FF000000"/>

            <Ellipse Margin="88,80,88,80" Fill="#FFFFFFFF" Stroke="#FF000000" Width="20" Height="20"/>

            <Ellipse Height="40" Margin="56,0,48,24" VerticalAlignment="Bottom" Fill="#FFFFFFFF" Stroke="#FF000000"/>

          </Grid>

        </controls:Viewbox>

    </Grid>

</UserControl>

Yukarıdaki kod içerisinde de görebildiğiniz üzere elimizdeki Grid'i doğrudan alıp bir ViewBox içerisinde yerleştirdik. Böylece artık ViewBox'ı tekrar boyutlandırdığımızda içerisinde tüm görseller vektörel olarak bir bütün şeklinde kabul edilecek ve o şekilde tekrar boyutlandırılacak.

ViewBox güzelliği.
ViewBox güzelliği.

Gördüğünüz gibi görselde hiçbir değişiklik yok. Elimizdeki çizim vektörel olduğu için büyüdüğünde de herhangi bir görsel bozulma olmuyor. Tabi ViewBox'ı her durumda kullanmak da doğru olmayacaktır. Örneğin Silverlight ekranınızda bir Button varsa (veya herhangi bir kontrol) ve bu kontrolün dinamik olarak boyutlandırılmasını istiyorsanız ViewBox yerine Grid'i tercih etmelisiniz. Çünkü Grid Button'un Height ve Width gibi özellikleri üzerinden Button'a boyut verirken ViewBox doğrudan Button'un görselliği üzerinden vektörel olarak büyütecektir.

ViewBox ve Grid farkı.
ViewBox ve Grid farkı.

ViewBox özellikleri...

Bir ViewBox kontrolü içerisinde görsellerin nasıl boyutlandırılacağı ile ilgili verebileceğimiz kararlar var. Bunlardan ilki Strech özelliği. Gelin Strech özelliğine verebileceğimiz değerler arasındaki farklara bir örnek ile bakalım.

ViewBox'ın Strech özellikleri arasındaki farklar.
ViewBox'ın Strech özellikleri arasındaki farklar.

Farklar sanırım görselde açık bir şekilde belli oluyor. None değerini verdiğimiz Strech özelliği ViewBox içerisindeki görsellerin boyutlandırılmamasını sağlıyor. Uniform değeri en/boy oranını koruyarak ViewBox'ın içerisinde tam sığacak şekilde görseli büyütürken UniformToFill ise yine en/boy oranını korusa da bu sefer ya eni ya da boyu her şekilde ViewBox'ın içine en büyük değeri ile yerleştiriyor. Strech özelliğine doğrudan Fill değerini verirseniz bu sefer görselin en/boy oranı korunmadan tamamen ViewBox'ın içerisine yayılıyor.

Ayrıca isterseniz ViewBox'ın VerticalAlignment ve HorizontalAlignment özellikleri ile de UniForm modunda ViewBox içerisindeki görselin nasıl hizalanacağına karar verebilirsiniz.

StretchDirection özelliği.

Şu ana kadar ViewBox içerisinde görsellerin sürekli büyüdüğünü gördük fakat isterseniz ViewBox'ın boyutunu ufaltarak aynı şekilde elinizdeki görseli küçültebilirsiniz de. Bazı durumlarda ise ViewBox içerisindeki görselin sadece gerektiğinde büyütülmesini veya sadece küçültülmesini isteyebilirsiniz. Bu gibi durumlarda gerekli sınırlamaları yapmak için doğrudan StretchDirection özelliğini kullanabilirsiniz.

Eğer StretchDirection değeri UpOnly olursa ViewBox içerisindeki görsel gerektiğinde sadece büyütülecektir. ViewBox kendi içindeki görselden daha fazla ufaltılırsa içindeki görseli kesinlikle ufaltmayacaktır. Aynı şekilde DownOnly özelliği de ViewBox'ın kendi içerisindeki görseli gerektiğinde sadece ufaltmasını sağlayacaktır. StretchDirection özelliğinin varsayılan değeri Both olarak geldiği için normal şartlarda hem ufaltma hem de büyütme yapar.

Hepinize kolay gelsin.

Monday, November 17, 2008 4:30:02 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, November 16, 2008

Dünkü oyun günündeki katılımcılar bilirler :) Beni de Silverlight 2.0 ile Oyun Programlama alanında ekstra bir heyecan sarmıştık. Tabi bu heyecanı soğutmadan hızlı bir şekilde koda dökmek gerek. O nedenle seminerde yaptığımız oyun üzerinden kabaca devam ederek bazı özellikler ekledim. Artık adam akıllı oynanabilir bir oyun oldu :) Aşağıda beğenilerinize sunuyorum.

Get Microsoft Silverlight

Oyunun tüm kaynak kodlarını da aşağıdan indirebilirsiniz.

Silverlight 2.0 Oyun Kaynak Kodları - 16112008_1.rar (2,58 MB)

Hepinize kolay gelsin.

Sunday, November 16, 2008 4:41:54 PM (GTB Standard Time, UTC+02:00)  #    Comments [25]   Silverlight 2.0  | 
 Saturday, November 15, 2008

Bugün Microsoft İstanbul ofisinde Oyun Turu'nun ilk ayağını gerçekleştirdik. Güne "Oyun Sektörü" ile ilgili genel bir oturumun sonrasında Silverlight 2.0 ile Oyun Programlama konusu ile giriş yaptık. Oyunumuzu yazarken yarattığımız buglar nedeniyle epey eğlenceli anlar yaşadığımızı itiraf etmeliyim. Öğle arasından sonra ise XNA konusunda uzman konuşmacımız Engin Yıldız ve süpriz konuşmacımız :) sevgili Cem Demir sahne aldı. Neden mi sürpriz? eh sürpriz :)

Microsoft Oyun Turu, İstanbul
Microsoft Oyun Turu, İstanbul

Kaçıranlar üzülmesin, Silverlight 2.0 ile Oyun Programlama kısmını doğrudan benim SeminerTV'ye koyacağım :) Diğer yandan çok yakında oyun programlama konusunda yazılarla beraber bir de kaynak kodları ile hazırladığım bir oyunu paylaşmayı düşünüyorum. Hatta bu oyun seminerde yazdığımız oyunun biraz daha rötuşlanmış hali de olabilir :) Yakında başka illerde de Oyun Turu'na devam edeceğiz.

Hepinize kolay gelsin.

Saturday, November 15, 2008 1:03:42 AM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Friday, November 14, 2008

Bugün Bursa, Uludağ Üniversitesi'ndeydim. Silverlight 2.0 ve WPF konularını inceledik. Gelen sorular gerçekten muhteşemdi, özellikle Bursa'daki kurumsal katılıma teşekkür etmem gerek. Yeniliklere bu kadar heyecanla yaklaşmaları ve hafta içi iş günlerinde ofislerini bırakıp beni dinlemeye gelmelerini emin olun hayranlıkla karşıladım. Öğrenci kardeşlerimiz de tabi ki ayrı heyecanlıydı, seminerin yarattığı etkinin olabildiğince uzun süre hayatta kalmasını diliyorum :)

Bursa, Uludağ Üniversitesi, Silverlight ve WPF Semineri
Bursa, Uludağ Üniversitesi, Silverlight ve WPF Semineri

Aktivitenin organizasyonu için sevgili Muhammed Medeni Baykal'a teşekkürlerimi iletiyorum. Ayrıca Muhammed'e yardım ettiğini de bildiğim birçok öğrenci dostuma buradan sevgiler ve teşekkürler :) Hepiniz muhteşemdiniz.

Friday, November 14, 2008 12:49:27 AM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0 | WPF  | 
 Thursday, November 13, 2008

Mart ayında sizleri Silverlight T-Shirt'üm ve sonrasında da Tish-O ile tanıştırmıştım. Böylece sizler de isterseniz SilverMan T-Shirt'ünden sipariş verebilecektiniz :) Eh birileri siparişleri vermiş :) FaceBook'taki Fan Club'ımın da kurucuları olan Ahmet Enes Dabanlıoğlu ve Fatih Gençaslan heyecanları ile gerçekten beni etkilediler. Arkadaşlar bu heyecanı satır satır kodlara dökmeniz dileği ile ;)

The Silver Team :)
The Silver Team :)

Thursday, November 13, 2008 12:30:41 AM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight | Silverlight 2.0  | 
 Wednesday, November 12, 2008

Layout kontrolleri XAML ile arayüzler oluştururken "olmazsa olmazlar" listemizin en başında geliyor. Silverlight 1.0'daki Canvas kontrolünden sonra 2.0'da birçok kontrol yardımımıza yetişse de maalesef WPF'deki zenginliğe ulaşamamıştı. Bu eksikliği Silverlight Toolkit karşılıyor ve paket içerisindeki WrapPanel aynı WPF içerisindeki işlevsellikleri Silverlight için de sağlıyor.

Silverlight Toolkit DLL'lerinden Microsoft.Windows.Controls.DLL dosyasını Silverlight 2 projenize referans olarak ekledikten sonra WrapPanel kontrolünü Blend 2 içerisinde Asset Library'de "Custom Controls" tabında bulabilirsiniz.

Expression Blend 2 içerisinde Silverlight Toolkit'ten WrapPanel.
Expression Blend 2 içerisinde Silverlight Toolkit'ten WrapPanel.

Bu noktadan sonra Blend içerisinde doğrudan bir WrapPanel'i sahneye yerleştirebilirsiniz. Peki nedir WrapPanel? WrapPanel içerisindeki kontrolleri bir sepete atırılmış gibi sürekli toplayarak kendi içine sığdırmaya çalışan bir kontroldür. Gelin örnekler ile tam olarak nasıl çalıştığına göz atalım.

WrapPanel içerisinde birden çok nesne.
WrapPanel içerisinde birden çok nesne.

Yukarıdaki görselde sahnede bir WrapPanel yer alıyor. Söz konusu WrapPanel içinde toplam 6 tane Button var. Bu Button'ların konumları ile ilgili hiçbir ayar yapmadık. Düğmeleri WrapPanel içerisinde attıkça WrapPanel kendisi ilk başta düğmeleri yan yana koymaya başladı sonra yer kalmayınca alt satıra attı ve alt satıra düğmeler dizmeye başladı. İşte WrapPanel'in mantığı da budur. İçerisinde bulunan nesneleri sırası ile toparlayarak konumlandırır.

[XAML]

<UserControl x:Class="SilverlightApplication23.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

    <Grid x:Name="LayoutRoot" Background="White">

 

      <controls:WrapPanel Margin="39,35,141,93">

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

      </controls:WrapPanel>

 

    </Grid>

</UserControl>

Örneğimizin XAML kodunu da yukarıda bulabilirsiniz. Gördüğünüz gibi WrapPanel içerisindeki düğmelerin hiçbirinin konumlandırma bilgisi yok. Düğmelerin içerisinde yazılacak yazılar dışında hiçbir özellikleri set edilmiş değil.

WrapPanel'in Orientation özelliği Vertical yapılınca...
WrapPanel'in Orientation özelliği Vertical yapılınca...

İsterseniz bir WrapPanel'in içerisindeki nesnelerin ekranın üstüne doğru değil de soluna doğru da toparlanmalarını sağlayabilirsiniz. Bunun için WrapPanel'in Orientation özelliğini Vertical olarak ayarlamanız yeterli olacaktır. Böylece sıralama işlemi dikey olarak yapılacak ve dikey boy doldurulduğunda yeni bir kolon yaratılarak hizalama devam edecektir.

[XAML]

    <controls:WrapPanel Margin="39,35,141,142" Orientation="Vertical">

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

      </controls:WrapPanel>

WrapPanel içerisinde nesnelerin hizalama ayarlarına dikkat!

WrapPanel içerisindeki nesnelerin her biri kendi satır ve sütunları içerisinde hizalandırılabilirler. Stretch modunda olan nesnelerin oluşan bir kolon veya sütun içerisinde tüm nesnelerin en geniş veya en yüksek olan nesneye uyum sağlayacaktır. Bu nedenle eğer bir satır veya sütun içerisinde nesnelerin orijinal büyüklüklerinde kalmalarını istiyorsanız hizalamalarını kesinlikle tek tek ayarlamalısınız.

Farklı hizalamalara sahip nesneler!
Farklı hizalamalara sahip nesneler!

Yukarıdaki görselde ikinci düğmenin dikey hizalamalası değiştirilerek kendi özgün boyutunda gösterilmesi sağlanmıştır. Söz konusu düğmenin bulunduğu satırın yüksekliğini arttıran isen birinci düğmedir.

[XAML]

      <controls:WrapPanel Margin="39,35,141,142" Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">

        <Button Content="Button" Width="134" Height="50" HorizontalAlignment="Left" VerticalAlignment="Top"/>

        <Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

        <Button Content="Button"/>

      </controls:WrapPanel>

Nerelerde kullanılabilir?

WrapPanel'in belki de en sık kullanıldığı basit yerlerden biri harici kontrollerdeki diğer Layout kontrollerinin yerini alarak farklı görsellikler sağlama noktasıdır. Örneğin normal şartlarda içerisindeki öğelerin dikey veya yatay olarak tek bir satır veya sütunda gösterilebileceği bir ListBox kontrolünün Layout kontrolünü değiştirerek ListBox içerisinde tüm nesnelerin ekrana sığacak şekilde bir WrapPanel içerisinde toplanmasını sağlayabilirsiniz.

Standart bir ListBox.
Standart bir ListBox.

Yukarıda gördüğünüz standart ListBox içerisinde öğeler dikey olarak sıralanmış durumda. Oysa bu öğelerin uzunlukları kısa ve belki de "Deneme 1" ile "Deneme 2" yan yana konabilirdi. Böylece çok daha fazla öğe aynı anda ekranda gösterilirken kullanıcının çok daha hızlı şekilde aradığı şeye ulaşması sağlanabilirdi. Bu detayların haricinde görsel olarak da daha güzelbir sonuç alabiliriz.

Bu durumda bizim yapmamız gereken  yukarıda hazırladığımız standart ListBox'ın Layout kontrolünü değiştirmek. Bunun için Expression Blend içerisinde kontrolü seçerek sağ tuş tıklayıp aşağıdaki görselde görebileceğiniz menüye doğru hızlı bir yolculuk yapıyoruz.

ListBox'ın Layout kontrolünü değiştireceğiz.
ListBox'ın Layout kontrolünü değiştireceğiz.

ListBox'ın içerisinde normal şartlarda bir Grid Layout kontrolü bulunuyor. Bu kontrolü silerek yerine bir WrapPanel koymamız gerekecek.

Grid yerine WrapPanel karşınızda.
Grid yerine WrapPanel karşınızda.

WrapPanel'i koyduktan sonra WrapPanel'in genişliğini de ListBox'ınızın genişliğine eşitlemeyi unutmayın. Bunu dinamik arayüzlerde LayoutUpdated eventlarında yapabilir veya XAML tarafında bir Binding ile çözebilirsiniz.

ListBox içerisinde WrapPanel.
ListBox içerisinde WrapPanel.

Yukarıdaki görselde WrapPanel ile ListBox'ın iş ortaklığının sonucunu görebilirsiniz. ListBox içerisinde nesneler mümkün oldukça yan yana alınarak yukarıya doğru toplanmışlar. Bizim örneğimizde nesne sayısı artık az geldiği için ListBox'ın scroll barları da gözükmüyor.

Hepinize kolay gelsin.

Wednesday, November 12, 2008 11:10:33 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, November 10, 2008

14 Kasım'da Bursa, Uludağ Üniversitesi'nde Silverlight ve WPF anlatıyor olacağım. Aktivite tamamen halka açık ve ücretsiz. Kayıt için aşağıdaki adreste takip edebilirsiniz;

http://tinyurl.com/yazilim-atolyesi

Etkinliğimiz Uludağ Üniversitesi Mühendislik - Mimarlık Fakültesi 2. Kat / Ahmet Rasim Büyüktür Salonu Görükle Kampüsü'nde olacak ve sabah 11.00'da başlayarak 17.00'da sonlanacak.

Bursa civarından herkesi bekliyorum ;)

Monday, November 10, 2008 12:36:23 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Seminer | Silverlight 2.0 | WPF  | 
 Sunday, November 09, 2008

Yıldız Teknik Üniversitesi Bilişim Kulübü, bu yıl 8.'sini düzenleyeceği Bilişim Günleri Etkinliği'ni 12-14 Kasım 2008 tarihleri arasında Yıldız Teknik Üniversitesi Merkez Kampüsü Oditoryum Salonunda gerçekleştirilecek. Katılım halka açık ve tamamen ücretsiz.

Etkinlik içerisinde ben de 12 Kasım günü saat 14.15-17.15 arasında Silverlight 2.0 ve 17.30-18.30 arasında da WPF'ten bahsedeceğim. Etklinliğin tam programına Bilişim Kulübü web sitesinden ulaşabilirsiniz.

Sunday, November 09, 2008 12:29:11 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0 | WPF  | 
 Saturday, November 08, 2008

Bugün Afyon Kocatepe Üniversitesi'ndeydim. Sabahtan başlayarak Silverlight 2.0, WPF, LINQ ve ASP.NET Dynamic Data konularına değinerek zevkli bir gün geçirdik. Günün sonunda tadına vardığım Afyon kaymağı ve ekmek kadayıfı süper ikilisi aslında neredeyse oturumları uzatarak Afyon'a yerleşmeme bile sebep olacaktı :)

Kocatepe Üniversitesi 2. Bilişim Günleri oturumlarımın sonundan bir kare.
Kocatepe Üniversitesi 2. Bilişim Günleri oturumlarımın sonundan bir kare.

Aktivite boyunca yardımlarından dolayı teşekkür etmem gereken o kadar çok kişi var ki kesinlikle atladığım kardeşlerim olacaktır. İster üniversite dahilinde öğretim görevlisi olsun ister öğrenci olsun aktivitede emeği geçen herkese ve tabi ki tüm katılımcılara çok teşekkürler. Muhteşem bir aktiviteydi. Organizasyondaki katkılarından dolayı sevgili Sadık Oral'a özellikle teşekkür ediyorum.

Herkese çok teşekkürler.
Rektör Yardımcısı Prof. Dr. Belkıs Özkara - Daron Yöndem

Saturday, November 08, 2008 1:26:58 PM (GTB Standard Time, UTC+02:00)  #    Comments [5]   ASP.NET 3.5 | LINQ | Silverlight 2.0 | WPF  | 
 Friday, November 07, 2008

Renklerin birbirine uyumu özellikle biz yazılımcılar için pek anlaşılamayan bir sistemi tanımlar :) Kişisel olarak ben bir renk yığınındaki renklerin birbirine uyumlu olup olmadığını anlayabilsem de "Buyur uyumlu 3 renk seç" derseniz pek de başarılı olamam. Belli ki bu durum genel geçer bir sorunu tanımlıyor ki RD, Jonas Folloseo birazdan sizlere detaylarından bahsedeceğim uygulamayı hazırlamış. Uygulama özünde Adobe'nin Kuler sitesinin API'larını kullanıyor. Kuler'dan hızlı bir şekilde bahsetmek gerekirse tasarımcıların birbirleri ile uyumlu renk şemalarını paylaştıkları bir Web 2.0 portalı diyebiliriz.

Colorful Expression

Aşağıdaki adresten indirebileceğiniz uygulama toplam 3 bölümden oluşuyor.

http://www.codeplex.com/colorful

Birincisi Colorful WPF adında tek başına çalışabilen bir WPF uygulaması. Bu uygulama içerisinde birbirleri ile uyumlu renk şemalarını inceleyebilir ve aramalar yapabilirsiniz. Unutmayın ki sistem Kuler'ın API'larından faydalanıyor yani programı ancak online durumdayken kullanabilirsiniz. Colorful WPF'in en güzel özelliği herhangi bir renk şemasının altındaki düğmeler aracılığı ile hızlı bir şekilde bu renkleri kullanabilmenizi sağlayacak XAML Brush kodlarını alabiliyor olmamız.

Colorful WPF içerisinde birbiri ile uyumlu renklerin bir listesi.
Colorful WPF içerisinde "silver" kelimesi aratıldığında çıkan birbiri ile uyumlu renklerin bir listesi.

Yukarıdaki ekran görüntüsünde yer alan en üstteki "Silver" adındaki renk şemasının altındaki "Swatches" düğmesine tıkladığımda doğrudan aşağıdaki XAML kodu panoya kopyalanıyor ve rahatlıkla Silverlight veya WPF projelerinde kullanabiliyoruz.

<SolidColorBrush x:Key="SilverColor1" Color="#FF474143" />

<SolidColorBrush x:Key="SilverColor2" Color="#FFA69E9D" />

<SolidColorBrush x:Key="SilverColor3" Color="#FFE7E2DA" />

<SolidColorBrush x:Key="SilverColor4" Color="#FFFFFFFF" />

<SolidColorBrush x:Key="SilverColor5" Color="#FFE7E8E7" />

Expression Design ve Blend Add-In

Colorful Expression içerisindeki renk şablonlarını isterseniz doğrudan Expression Design veya Blend içerisinde de kullanabiliyorsunuz. Bunun için download paketi içerisinden program adına uygun klasörün içindeki 2 DLL dosyasını programların bilgisayarlarınızda yüklü oldukları konumlara kopyalamanız gerek. Sonrasında aşağıdaki şekilde hem Blend hem de Design'ı çalıştırdığınızda Colurfull Expression'ı doğrudan Blend veya Design içerisinde de kullanabilirsiniz.

Blend.exe –addin:Colorful.Blend.AddIn.dll
Design.exe –addin:Colorful.Design.AddIn.dll

Expression Design içerisinde Colorful paneli.
Expression Design içerisinde Colorful paneli.

Yukarıdaki ekran görüntüsünde Colurful Expression'ın doğrudan Expression Design içerisinde kullanılabildiğini görebiliyorsunuz. Aynı şekilde Blend 2 içerisinde de rahatlıkla Colurful paneline ulaşılabiliyor.

Expression Blend 2 içerisinde Colorful paneli.
Expression Blend 2 içerisinde Colorful paneli.

Blend içerisinde Colorful panelinin kullanımı ile ilgili Design'a kıyasla ek avantajlar da söz konusu. Sahneye sürükleyip bıraktığınız bir renk şablonu aslında arka planda birer SolidColorBrush olarak sayfanın Resource'larına ekleniyor. Böylece bu renkleri istediğiniz kadar farklı yerlerde rahatlıkla merkezi olarak kullanabiliyorsunuz.

Colorful'un yarattığı XAML kodları otomatik olarak karşımızda.
Colorful'un yarattığı XAML kodları otomatik olarak karşımızda.

Hepinize kolay gelsin.

Friday, November 07, 2008 3:02:52 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Expression Blend | Expression Design | Silverlight 2.0 | WPF  | 
 Wednesday, November 05, 2008

Silverlight Toolkit konusunda yazılarıma devam edeceğimden bahsetmiştim. Bu yazımızda Silverlight Toolkit ile beraber gelen theming (renk şablonları) yapısına göz atacağız. Hali hazırda Toolkit ile beraber gelen şablonların nasıl kullanılabildiğini inceleyeceğiz.

Yarattığımız yeni bir Silverlight 2.0 projesini Blend 2 ile açtıktan sonra ilk aşamada hemen Silverlight Toolkit içerisindeki gerekli DLL'leri referans almamız gerekiyor. Toolkit paketini bilgisayarınızda açtığınızda içinde Themes adında bir klasör olduğunu göreceksiniz. Bu klasör içerisinde her bir DLL farklı bir renk şablonunu temsil ediyor. İsterseniz hepsini referans olarak ekleyebilir veya sadece kullanacaklarınızı projenize dahil edebilirsiniz. Örneğimizde ben hepsini referans olarak alacağım ki aradaki farkları görelim.

Blend 2 içerisinde projeye referans eklerken.
Blend 2 içerisinde projeye referans eklerken.

Themes klasöründeki tüm DLL'leri referans olarak aldıktan sonra bir de Toolkit paketinin ana klasöründeki Microsoft.Windows.Controls.Theming.dll dosyasını referans olarak almalısınız.

Tüm hazır Theme'ler kontroller şeklinde Asset Library'de.
Tüm hazır Theme'ler kontroller şeklinde Asset Library'de.

Tüm DLL'leri doğru şekilde projenize referans olarak eklediğinizde Blend 2 içerisinde Asset Library'nin Custom Controls bölümünde her bir Thema için ayrı bir kontrol göreceksiniz. Bu kontrollerin kullanımı biraz garip :) Herhangi bir thema'dan etkilenmesini istediğiniz tüm kontrolleri bu yukarıdaki thema kontrolleri içerisine koymanız gerekiyor. Yani aslında bir anlamda kendileri birer LayoutControl gibi davranıyorlar.

Blend içerisinde Theme kontrollerinin yapısı.
Blend içerisinde Theme kontrollerinin yapısı.

Yukarıdaki ekran görüntüsünde gördüğünüz üzere ExpressionDarkTheme'den etkilenmesini istediğimiz tüm kontrolleri bir Canvas içerisinde kendisine teslim etmişiz. Theme kontrolleri aslında içlerine sadece bir kontrol alabiliyorlar o nedenle Canvas gibi ayrı bir LayoutControl daha kullanmamız gerekiyor.

Bu yapı sayesinde bir uygulamada birden çok şablonu farklı uygulama bölümlerinde kullanabilirsiniz. Örneğin bir Grid'in iki kolonu içerisinde farklı Theme kontrolleri koyarak bu kontrollerin içerisinde söz konusu şablonlardan faydalanabilir ve bu şekilde farklı kombinasyonlar ile de çalışabilirsiniz.

Toolkit içerisinde hazır renk şablonları.
Toolkit içerisinde hazır renk şablonları.

Yukarıdaki şablonlar doğrudan Toolkit içerisinde hazır olarak gelen şablonların örnekleri. Tasarımcıların ne kadar hoşuna gider bilemiyorum :) ama yazılımcıların çok işine yarayacağından eminim. İsteyenler Toolkit paketi içerisinde Themes/XAML klasöründe bu tasarımların XAML kodlarını da bulabilirler.

Hepinize kolay gelsin.

Wednesday, November 05, 2008 2:58:00 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, November 04, 2008

Uzun süredir gerçekleştirmek istediğim özel etkinliklerden biriyle daha karşınızdayım :) Silverlight 2.0 ile ilgili giriş seviyesi seminerler yaptık, eğitimler yaptık vs Ama özel konulara hiç değinemedim. Bu konulardan biri de Silverlight 2.0 ile oyun programlama ve fizik motorlarıydı :)

Microsoft Oyun Programlama Turu

Adından da anlaşılacağı üzere Microsoft Türkiye'nin organizasyonunu üstlendiği bir tur ile farklı illerde oyun programlama üzerine seminerler yapacağız. Seminer serisinde Silverlight 2.0 ile oyun programlamanın yanı sıra XNA ile hem Windows hem de XBOX ortamına oyun programlama konusu da yer alıyor. Aktivitelere katılanları minik bir de sürpriz bekliyor :) ama ip ucu vermeyeceğim.

Turun ilk ayağı İstanbul'da Microsoft'un Levent'teki yeni ofisinde 15 Kasım, Cumartesi günü gerçekleşecek. Detayları buradan inceleyebilirsiniz.

Aktiviteye katılmak isteyenlerin kayıt olması gerekiyor, aman unutmayın.

Tuesday, November 04, 2008 11:40:00 AM (GTB Standard Time, UTC+02:00)  #    Comments [13]   Silverlight 2.0  | 
 Monday, November 03, 2008

Silverlight 2.0 ile beraber gelen XAP dosyaları özellikle farklı kontrol kütüphanelerinin de kullanılması ve bolca imajlar ile giderek şişmeye başlıyor. Özünde birer ZIP dosyası olduğunu bildiğimiz XAP dosyalarını aslında biraz daha sıkıştırma şansımız var. İzlemeniz gereken yol çok basit, XAP dosyasının içeriğini açıp tekrar harici bir program ile en yoğun seçenekleri seçerek ZIP şeklinde sıkıştırmanız gerekiyor. Sonrasında uzantıyı tekrar XAP yapabilirsiniz. Böylece ortalama %20'ye yakın XAP dosyalarının ufaldığını göreceksiniz.

Peki her seferinde bu işlemi tekrar tekrar yapacak mıyız?

Projenizi her Compile ettiğinizde tekrar bu işlemi yapmak ciddi sıkıcı olabilir. O nedenle aslında bu işleri otomatik olarak uygulayan bir yapı kurmak gerek. Çok uğraşmayacağız çünkü zaten bu işlemi otomatik olarak yapan bir uygulama Rob Houweling tarafından yazılmış :)

ReXapper - 03112008_2.rar (50,53 KB)

  • Uygulamayı yukarıdan indirdikten sonra aşağıdaki işlemleri sırayla yapmanız gerekiyor.
  • Uygulamayı bilgisayarınızda hiç silmeyeceğiniz bir konuma kopyalayın.
  • Yarattığınız herhangi bir SL 2.0 projesini açın ve "Solution Explorer" içerisinde projeye sağ tuş tıklayıp "Properties" penceresine ulaşın.
  • "Build Events" sekmesine geçerek "Post build event" kısmına aşağıdaki kodu bilgisayarınızdaki ReXapper uygulamasının konumuna göre yapıştırın.
    • C:\Laptop\DEPO\ReXapper.exe -xap "$(TargetDir)$(TargetName).xap"

ReXapper ile daha ufak XAP dosyaları!
ReXapper ile daha ufak XAP dosyaları!

Artık Visual Studio içerisinde projenizi her Compile ettiğinizde otomatik olarak tekrar XAP dosyası sıkıştırılacaktır. Benim ilk denememde 178KB'lık bir proje 144KB'a indi.

Hepinize kolay gelsin.

Monday, November 03, 2008 1:09:49 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Sunday, November 02, 2008

Bugün güzel bir Pazar gününü Expression Encoder'a SP1 ile beraber gelen video şablonlarını inceleyerek ve özelleştirerek değerlendirdim. Hatırlarsanız daha dün size bu müjdeyi vermiştim. Encoder ile beraber gelen şablonlardan Galeri şablonunu çekip çevirip istediğim hale getirmek hiç de zor olmadı. Projede MS ekibi OOP'ın tüm nimetlerinden faydalanmış.

Peki bu kadar uğraştım da ne yaptım? Uzun zamandır aklımda olan, blogumun SeminerTV bölümünü yeniledim! Artık tüm bölüm Silverlight 2.0 ve hala isteyenler videoları doğrudan izleyebileceği gibi Download düğmesi de Silverlight player içerisinde mevcut.

Buyurun, siz de test edin. Ben IE7, 8, FireFox, Opera, Chrome.. hepsinde süper çalışıyor.

http://daron.yondem.com/tr/formatpage.aspx?path=seminertv.format.html

Sunday, November 02, 2008 7:04:10 PM (GTB Standard Time, UTC+02:00)  #    Comments [8]   Silverlight 2.0  | 
 Saturday, November 01, 2008

Güzel haberlerim var. Expression Encoder 2 sonrasında Silverlight 2 çıkmasına rağmen maalesef Encoder'dan aldığımız şablonlar hala Silverlight 1 kullanıyordu. Bu nedenle ben bazı projelerde sıfırdan Silverlight 2 player'ları yazmak zorunda kaldım. Ama artık karşımızda Expression Encoder 2 için SP1 var, ve beraber Silverlight 2 playerlar geliyor!

http://www.microsoft.com/downloads/details.aspx?FamilyId=A29BE9F9-29E1-4E70-BF67-02D87D3E556E&displaylang=en

Ayrıca SP1 ile beraber Video ve Audio Overlay, yani bir videonun PIP olarak başka bir video üzerine konması veya videonun sesini değiştirmek de kolaylıkla yapılabiliyor. Yavaş yavaş Encoder olmaktan Editor olma yolunda ilerliyor gibi ürün :)

Expression Encoder artık Express!

Bir diğer sürpriz de Expression Encoder'ın Express sürümü! Aynı Visual Studio dünyasında olduğu gibi Expression Encoder'ın da Express sürümü tamamen ücretsiz olacak. 30 günlük deneme sürümünü indirerek kullandığınızda 30 günün sonunda sizden ya bir Key girmeniz ya de Express moduna geçmeniz istenecek. Yani ayrıca bir Express sürümü sunulmuyor, sadece Trial'ın periodu birince Express haline dönüşüyor. Peki Express sürümde normal kıyasla neler eksik?

  • Gelişmiş video ve audio profil ayarları
  • Preprocessing paneli
  • Gelişmiş codec ayarları paneli
  • Özelto XML ve PRX profilleri
  • Sadece aşağıdaki profiller kullanılabilir;
    • Streaming Broadband
    • Web Server Broadband
    • Streaming 512k DSL
    • Web Server 512k DSL
    • Streaming 256k DSL
    • Web Server 256k DSL
  • MPEG2 import edebilme
  • Canlı encoding
  • A/B karşılaştırma modu
  • Yukarıda sayılı özellikleri kullanan Job veya Preset dosyalarını açabilme.

Expression Encoder trial, Express veya DreamSpark sürümlerinde maalesef MPEG2 Decode özelliği yok. Bunu ancak harici K-Lite gibi codec paketleri kullanarak halledebilirsiniz.

Saturday, November 01, 2008 11:56:02 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Expression Encoder | Silverlight 2.0  | 
 Friday, October 31, 2008

Bugün Fatih Üniversitesi'nde Silverlight ve WPF anlattım. Gerçekten çok sıcak bir atmosfer vardı üniversite içerisinde, kendimi bir an bir üniversitede olduğuma ikna etmem gerekti :) Ben mi yanlış yerden girdim bilmiyorum ama hemen girişte bir mısırcı bir de ananas zaten seyyar satıcı kıvamında iç mekan işportalarından :) görünce (son dönemde bunlar moda zaten) epey şaşırdım diyebilirim. Öğrenciler adına sevindim tabi ki.

Fatih Üniversitesi Silverlight ve WPF Seminerleri
Fatih Üniversitesi Silverlight ve WPF Seminerleri

İlginç anlar yaşadığım hatıralar edindiğim bir seminer oldu. WPF örneği olarak Yahoo Mesenger'ı gösterirken IBM'den sevgili dostum Arden'in mesaj atıp "En büyük IBM" demesinden tutun :) Dinleyici arkadaşlardan birinin "3D nedir?" sorusuna kadar (hala bu sorunun ciddi mi şaka mı olduğunu anlamış değilim:D) hoş anlar yaşadım diyebilirim.

Aktivitenin organizasyonunda özellikle sevgili Muhammed Medeni Baykal, Ahmet Aydin, Bilgehan Berberoglu, Umit Samimi, Erdin Sarpkaya ve Ahmet Eralp'e çok teşekkür ediyorum.

Hepiniz kalın sağlıcakla ;)

Friday, October 31, 2008 11:53:56 AM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Seminer | Silverlight 2.0 | WPF  | 
 Wednesday, October 29, 2008

Sonunda söz verdiğim gibi elime ulaşan tüm INETA Capital Hit fotoğraflarını sizlerle paylaşıyorum. Aşağıdaki adresten tüm fotoğraflara ulaşabilirsiniz. Hala elinde fotoğraf olanlar bana mail atabilirler, mail atılamayacak boyutta fotoğrafları olanlar da yine mail atarlarsa fotoğrafları yükleyebilecekleri FTP alanları da sağlayabilirim.

http://cid-e780a156a6bd0e34.skydrive.live.com/browse.aspx/INETA%20Capital%20Hit%202008 

Ayrıca bir de DeepZoom projesi hazırladım :) Tabi biraz mofikasyon ile hafif bir 3D ortam yaratmak da hoş oldu. Projenin çalışır halini aşağıda inceleyebilirsiniz. "Kıvırt" düğmesine dikkat :) Ayrıca fotoğraflara siz yaklaştıkça arkadakileri görebilmeniz adına fotoğraflar teker teker görünmez olacak. "Ölümüne detay" CheckBox'ını işaretlerseniz fotoğrafların tüm detaylarına kadar zoom yapabilirsiniz.

Biliyorum nasıl oldu bu iş diyorsunuz? :) Buyurun sizinle yukarıdaki projenin kaynak kodlarını da paylaşıyorum. Siz de kullandığınız yerleri benle paylaşırsanız çocuğunun ilk "baba" deyişini duyan baba gibi sevinebilirim :)

3D DeepZoom Projesi Kaynak Kodları29102008_1.rar (50,57 KB)

Hepinize kolay gelsin.

Wednesday, October 29, 2008 3:27:32 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Seminer | Silverlight 2.0  | 
 Tuesday, October 28, 2008

Silverlight 2.0 ile beraber gelen kontrol sayısı 1.0'a kıyasla ciddi miktarda arttı. Fakat hala eksikler var! İşte bu eksikleri Silverlight sürümleri arasında doldurabilmek adına yeni bir proje CodePlex üzerinde yayında. Proje aslında uzun süredir geliştiriliyor. Fakat daha yeni yeni stabil kontroller sunmaya başladı. Aslında eski AJAX Control Toolkit'e benzetebileceğimiz bir yapıda ilerleyen Silverlight Toolkit unutmamak gerek ki doğrudan Microsoft tarafından geliştirilmiyor, tamamen açık kaynak kodları ile gönüllü programcılar tarafından ilerletilen bu projede bazı kontroller stabil olarak işaretlenmişken bazıları ise hala "Preview" konumundalar.

İşte bu kütüphane içerisinde stabil olarak işaretlenmiş olan kontrollerden belki de en acil ihtiyaç duyacağımız TreeView kontrolünü bu yazımızda inceleyeceğiz.

Nasıl yüklenir?

Silverlight Toolkit içerisinde kontrollerden herhangi birini kullanabilmek için ilk olarak tabi ki söz konusu kütüphaneyi CodePlex üzerinden indirmeliyiz. Hemen aşağıdaki adresten son paketi indirebilirsiniz;

http://www.codeplex.com/Silverlight/Release/ProjectReleases.aspx?ReleaseId=18804

Paketi bilgisayarınıza indirdiğinizde Binaries klasörü içerisinde bulunan Microsoft.Windows.Controls.dll dosyasını yeni yarattığınız bir Silverlight projesine Visual Studio içerisinde referans olarak eklemeniz gerekiyor. Paket içerisinde bulunan diğer DLL'lere ve dosyalara ileriki makalelerimizde değineceğiz.

Unutmayın, referans ekleme işlemini doğrudan Silverlight projenize yapmanız gerek. Silverlight projenizle aynı Solution içerisinde bulunan ASP.NET proje ile herhangi bir ilişkimiz yok.

Bu işlemi tamamladıktan sonra artık Expression Blend tarafına geçerek kontrollerimizi kullanmaya başlayabiliriz. Eğer Expression Blend ile değil de Visual Studio tarafında XAML kodlarını yazmak isterseniz tek tek XAML içerisinde NameSpace tanımlarını yapmanız gerekecektir.

Expression Blend ile projemizi açtıktan sonra "Asset Library"e gidip "Custom Controls" tabına geçtiğimizde TreeView kontrolü karşımıza çıkıyor.

TreeView kontrolü Expression Blend içerisinde karşımıza çıkıyor!
TreeView kontrolü Expression Blend içerisinde karşımıza çıkıyor!

TreeView kontrolünü Blend içerisinde projenizde herhangi bir XAML dosyasına eklediğinizde XAML koduna dönüp bakarsanız aşağıdaki şekilde gerekli NameSpace tanımlarının da yapılmış olduğunu göreceksiniz. Eğer Blend kullanmasaydık bu işlemleri Visual Studio içerisinde elle yapmamız gerekecekti.

[XAML]

<UserControl x:Class="SilverlightApplication7.Page"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="400" Height="300" xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls">

    <Grid x:Name="LayoutRoot" Background="White">

 

      <controls:TreeView Margin="74,43,133,137"/>

 

    </Grid>

</UserControl>

Nasıl kullanılır?

Bir TreeView aslında birden çok TreeViewItem içerir. İsterseniz bu TreeViewItem'ları doğrudan Expression Blend içerisinde sürükle & bırak tekniği ile TreeView içerisine yerleştirebileceğiniz gibi isterseniz doğrudan kod ile databind işlemleri de yapabilirsiniz.

[XAML]

      <controls:TreeView Margin="74,43,133,137">

        <controls:TreeViewItem Header="Deneme1"/>

        <controls:TreeViewItem Header="Denem 2"/>

        <controls:TreeViewItem Header="Deneme 3">

          <controls:TreeViewItem Height="100" Width="100" Header="İçinde!"/>

        </controls:TreeViewItem>

      </controls:TreeView>

Yukarıdaki kod içerisinde birden çok TreeViewItem içeren bir TreeView görüyorsunuz. TreeView altında toplam üç adet TreeViewItem varken son TreeViewItem içerisinde bir tane daha TreeViewItem var. Böylece iç içe açılarak devam eden sonsüz döngüde bir ağaç yapısı oluşturmak mümkün.

TreeViewItem'ların Header özelliğine gözükecek metin değerini girebileceğiniz gibi aslında farklı Silverlight kontrollerini de Header içerisine koyma şansınız var.

[XAML]

      <controls:TreeView Margin="74,43,133,137">

        <controls:TreeViewItem Header="Deneme1"/>

        <controls:TreeViewItem Header="Denem 2"/>

        <controls:TreeViewItem Header="Deneme 3">

        <controls:TreeViewItem Height="100"

                              Width="100">

          <controls:TreeViewItem.Header>

            <Image Height="50"

                  Width="50"

                  Source="Tree.jpg" />

          </controls:TreeViewItem.Header>

        </controls:TreeViewItem>

        </controls:TreeViewItem>

      </controls:TreeView>

Yukarıdaki kod içerisinde de görebileceğiniz gibi TreeViewItem'lardan birinin Header'ında bir Image nesnesi, yani fotoğraf var. Siz uygulamalarınızda farklı fantaziler yaparak isterseniz MediaElement aracılığı ile video bile koyabilir veya belki de TreeView içerisine bir DataGrid veya Calendar bile koyabilirsiniz.

Gelelim tüm bu işlemlerin kod ile nasıl yapıldığına. Varsayalım elimizde TreeView'de göstermek istediğimiz bir veri var. İlk olarak bu veriyi uygun şekilde düzenlememiz gerek. Bizim örneğimizde Fiyati ve Adi gibi özelliklere sahip bir sınıf kullanalım. Her bir TreeViewItem bu sınıf üzerinden oluşturulacak.

[VB]

    Class Urun

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

        Private PFiyati As Integer

        Public Property Fiyati() As Integer

            Get

                Return PFiyati

            End Get

            Set(ByVal value As Integer)

                PFiyati = value

            End Set

        End Property

 

        Private PList As List(Of Urun)

        Public Property Liste() As List(Of Urun)

            Get

                Return PList

            End Get

            Set(ByVal value As List(Of Urun))

                PList = value

            End Set

        End Property

 

        Public Sub New()

            Me.PList = New List(Of Urun)

        End Sub

    End Class

[C#]

        public class Urun

        {

            public string Adi { get; set; }

            public int Fiyati { get; set; }

            public List<Urun> Liste { get; set; }

 

            public Urun()

            {

                this.Liste = new List<Urun>();

            }

        }

Gördüğünüz gibi sınıfımızın Adi ve Fiyati özellikleri haricinde bir de List tipinden Liste adında Property'si var. Bunun nedeni aslında çok basit. Her bir TreeViewItem'ın kendi içinde birden çok TreeViewItem olabilir demiştik. Bizim her bir ürünümüzün için de bu şekilde birden çok ürün saklanabiliyor olacak. Verimizi bu şekilde üretip TreeView'e DataBind ettiğimizde TreeView geri kalanı halledecek.

Gelin şimdi de bizim için deneme amaçlı olarak geçici veri yığını yaratacak bir kod yazalım.

[VB]

    Function Veriyarat() As List(Of Urun)

        Dim Liste As New List(Of Urun)

        For x As Integer = 0 To 10

            Dim BirUrun = New Urun With {.Adi = "Ürün" & x, .Fiyati = Rnd() * 1000}

            For y As Integer = 0 To 5

                BirUrun.Liste.Add(New Urun With {.Adi = "Ürün" & y, .Fiyati = Rnd() * 1000})

            Next

            Liste.Add(BirUrun)

        Next

        Return Liste

    End Function

[C#]

       public List<Urun> Veriyarat()

        {

            Random RastGele = new Random();

            List<Urun> Liste = new List<Urun>();

            for (int x = 0; x <= 10; x++) {

                Urun BirUrun = new Urun { Adi = "Ürün" + x.ToString(), Fiyati = RastGele.Next(0,1000) };

                for (int y = 0; y <= 5; y++) {

                    BirUrun.Liste.Add(new Urun { Adi = "Ürün" + y.ToString(), Fiyati = RastGele.Next(0, 1000) });

                }

                Liste.Add(BirUrun);

            }

            return Liste;

        }

Kodumuz içerisinde toplam 10 adet içerisinde 5'er ürün bulunan ürün yaratılıyor. Şimdi tüm bu listeyi alarak doğrudan TreeView'ın ItemsSource özelliğine aktaracağız. Siz örneklerinizde farklı sınıflar ve farklı veri kaynakları kullanabilirsiniz. Özellikle LINQ2SQL veya Data Services kullandığınızı düşünürsek zaten elinize bu şekilde hazır nesneler gelecektir.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Agac.ItemsSource = Veriyarat()

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Page_Loaded);

        }

 

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            Agac.ItemsSource = Veriyarat();

        }

Veri bağlantımızı yaptık. Fakat bu TreeViewItem'lar nasıl yaratılacak? Fiyati ve Adi adındaki özelliklerin içindeki değerler nerede gösterilecek? İşte bu noktada XAML tarafına geçerek bir ItemTemplate düzenlememiz gerekiyor. Böylece TreeView kendisine bağlanan veriye göre TreeViewItem'lar yaratırken nasıl bir görsellikten yola çıkacağını ve bu görsellik içerisinde gelen veriden hangi değerlerin nerelere yerleştirileceğini anlayabilecek.

[XAML]

    <controls:TreeView Margin="74,43,133,137"

                      x:Name="Agac">

      <controls:TreeView.ItemTemplate>

        <controls:HierarchicalDataTemplate ItemsSource="{Binding Liste}">

          <StackPanel Orientation="Horizontal">

            <TextBlock Text="{Binding Adi}"

                      Margin="5,0,0,0"

                      HorizontalAlignment="Left"

                      FontSize="10" />

            <TextBlock Text="{Binding Fiyati}"

                      Margin="5,0,0,0"

                      HorizontalAlignment="Left"

                      FontSize="10" />

          </StackPanel>

        </controls:HierarchicalDataTemplate>

      </controls:TreeView.ItemTemplate>

    </controls:TreeView>

Yukarıdaki XAML kodu ile aslında uygulamamızı sonlandırmış olduk. Peki neler yaptık? İlk olarak TreeView'ın ItemTemplate'i içerisinde yine Toolkit içerisinden gelen HierarchicalDataTemplate nesnesini yerleştirdik. Bu nesne bizim kod tarafında yarattığımız nested yapıyı algılayarak iç içe TreeViewItem'ların yaratılmasını sağlayacak fakat DataBind yaptığımız sınıfların hangi Property'sinin başka nested TreeViewItem'ların verilerini sakladığını anlayabilmesi için söz konusu Property'nin adını vermemiz lazım. Hatırlarsanız bizde Urun sınıfının Liste adında bir property'si vardı ve tüm alt öğeleri o saklıyordu. Biz de burada HierarchicalDataTemplate 'e ItemsSource olarak Liste'yi Bind ediyoruz. Geri kalanı kendisi halledecektir.

HierarchicalDataTemplate içerisinde doğrudan her bir TreeViewItem'ın Header bilgisini girer gibi istediğiniz Silverlight kontrollerini kullanabiliyorsunuz. Burada yapacağınız tasarım her TreeViewItem için kullanılacaktır. Tabi bunu yaparken Binding'lerimizi de unutmuyoruz ve yerine göre Fiyati ve Adi özelliklerini istediğimiz kontrollerin istediğimiz özelliklerine Bind ediyoruz. Bizim örneğimizde bir StackPanel içerisinde Fiyati ve Adi özelliklerini gösterecek iki farklı TextBlock bulunuyor.

DataBind TreeView örneğimiz bitti.
DataBind TreeView örneğimiz bitti.

Tüm verimizi bağladığımıza göre yeri geldiğinde seçili öğeyi nasıl yakalarız? Her bir TreeView'ın kendi SelectedItemChanged event'ı var. Bu event çalıştığında söz konusu TreeView'ın SelectedItem özelliğinden seçili öğeyi alabilirsiniz. En önemlisi SelectedItem size aslında DataBind esnasında bağlanan verinin içerisinde bulunan nesneyi döndürüyor. Yani bizim örneğimizde SelectedItem'ı aldığımda elimize Urun tipinden bir nesne gelecek. Gönül daha ne ister? :)

Hepinize kolay gelsin.

Tuesday, October 28, 2008 4:35:54 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Saturday, October 25, 2008

Uzun bir süredir Silverlight anlatıyorum, 1.0 , 1.1 Alpha, 2.0 Beta 1, 2.0 Beta 2 derken RC ve RTW ile bugünlere kadar geldik. Bu süreçte onlarca seminer verdim, ücretsiz tam gün eğitimler yaptık ve bana hep sordunuz "Tam eğitim almak istersek nereye gideceğiz?" Bir türlü cevap veremedim size "Eğitim kurumlarına başvurun" dedim ve geçtim. Bu süreçte aslında birçok eğitim kurumu ile toplantı yaptım ve Silverlight eğitimleri açmaları için onları teşvik ettim. Bazıları sıcak baktı, bazıları soğuk, bazısı açtı ama duyurmadı :) her neyse.

Bundan bir ay önce BTAkademi ekibinden Sefer Algan ve Oğuz Yağmur ile bir toplantım oldu ve bu konuyu da konuştuk. Silverlight 2.0 eğitimi açmak istediklerini ve benim eğitmen olarak bulunup bulunamayacağımı sordular. Tabi ki cevabım "Evet" oldu. Maalesef hala sektörde Silverlight uzmanları kaynamıyor ve üzerimdeki sorumluluğun farkındayım. Bu çerçevede yeri geldiğinde ücretli eğitimleri de bilgiyi paylaşmanın bir yolu olarak görüyorum. Birazdan bahsedeceğim eğitim tam 36 saat sürüyor ve maalesef bu uzunluktaki eğitimleri ücretsiz yapmak pek mümkün olmuyor. Ben bugüne kadar en uzun bir konuyla ilgili 18 saatlik ücretsiz eğitim verdim.

Gelelim sadede...

Eğitim programı hazırlandı, ücreti BTAkademi belirledi ve duyurdu. Buradan detayları inceleyebilirsiniz. Umarım faydalı olur. Şimdi eminim bazılarınız aklında sorular belirecek;

Soru:Hocam sizin kendi şirketiniz yok muydu? Oradan eğitim verseniz?
Cevap: Eğitmenlik benim kişisel hobim. Şirket ise para kazandığım yer. Eğitmenliği birinci elden gelir kaynağı veya ticaret konusu olarak görmüyorum kendi adıma. O nedenle işi hali hazırda yapan kurumlarda yer alıp, bilgimi aktarıp çekilmeyi tercih ediyorum.

Soru:Hocam ücretsiz eğitimler falan bitti mi artık?
Cevap: Yooo, alakası yok. Bu konu ayrı, o konular ayrı. Ücretli eğitim sadece ayrı bir ihtiyaç. Birbirlerine karıştırmamak gerek. Olanağı olan var olmayan var. Ha bu eğitimden para kazanmayacak mıyım? Tabi ki kazanacağım :) herhalde BTAkademi hayrına eğitim vermemi siz de anlamsız bulurdunuz. Amaç "ticari" olunca her yönden öyle olmalı ve oluyor. Bu çerçevede belki kazandığımla biraz daha kilo alırım :P O kilolarla da ücretsizlere devam ederiz :)

Hepinize kolay gelsin.

Saturday, October 25, 2008 9:23:24 PM (GTB Standard Time, UTC+02:00)  #    Comments [6]   Silverlight 2.0  | 
 Monday, October 20, 2008

Hafta sonunu Ankara'da geçirdik. Neden mi? INETA Capital Hit zamanıydı! Atladık INETA minibüsümüze :) yollara düştük. Maceralarımızla ilgili videolar ve fotoğraflar çok yakında bu blogda :)

İki kocaman gün boyunca dopdolu bir programla Çankaya Üniversitesi'nde iki yüz elli kişilik bir ekip olarak yattık kalktık diyebilirim. Yine her zamanki gibi benim için muhteşem zevkliydi.

Pazar akşamı saat yedide Capital Hit'i sonlandırdık.
Pazar akşamı saat yedide Capital Hit'i sonlandırdık.

Aktiviteye katılan tüm konuşmacı dostlarıma binlerce teşekkür. Ayrıca Çankaya Üniversitesi Bilişim Kulübü ve sevgili MSP, Çağrı Erdoğan'a da çok teşekkürler. Bir organizasyonda ancak bu kadar başarılı bir misafirperverlik sergilenebilirdi.

Tabi ki her şey bu kadarla bitmiyor! Elimde birçok fotoğraf, minibüs yolculuğumuzdan videolar ve panel kaydımız var. Hepsini büyük bir hızla hazırlamaya çalışıyorum. En kısa zamanda sizlerle buradan paylaşacağım.

Şimdilik aşağıdaki sunumlarla idare edelim :)

AdoNet Data Services / Burak Selim Şenyurt - 20102008_1.pptx (1,01 MB)
LINQ / Uğur Umutluoğlu - 20102008_2.pptx (750,29 KB)
WCF / Burak Selim Şenyurt - 20102008_3.pptx (460,14 KB)

Not: Bu sefer ben hiç sunum kullanmadım, doğrudan demolarla ilerledim. O nedenle sunum paylaşamıyorum.

Monday, October 20, 2008 6:24:54 PM (GTB Standard Time, UTC+02:00)  #    Comments [9]   .NET Framework 3.5 | ASP.NET 3.5 | Expression Blend | Haberler | IIS 7.0 | LINQ | Seminer | Silverlight 2.0 | WCF | WPF  | 
 Sunday, October 19, 2008

Photoshop hayatımızın o kadar göbeğine oturmuş durumda ki dilimize bir fiil olarak girdiğini bile söyleyebiliriz, "photoşoplanmıştır o!" gibi deyimler pek de yabancı değil :) Bu yazıda size Photoshop'tan DeepZoom projeleri Export etmenizi sağlayacak bir Plug-In'den bahsedeceğim.

İlk olarak aşağıdaki adresten "HD View Utilities" paketini bilgisayarınıza yüklemelisiniz. Bu paket içerisinde Photoshop Plug-In'i de bulunuyor.

http://research.microsoft.com/research/downloads/details/345a52c3-fe44-4045-94b4-4b26a93a907c/details.aspx

Yükleme işlemini tamamladıktan sonra yüklemeyi yaptığınız konumda HDView.8be adında bir dosya bulacaksınız. Bu dosya doğrudan bir Photoshop Plug-In dosyasıdır. Dosyayı alarak Photoshop'un bilgisayarınızda kurulu olduğu klasörde Plug-Ins\Import-Export konumuna kopyalamanız gerek. Tüm bunları tamamladığınızda artık herhangi bir dosya Photoshop içerisinde açıkken doğrudan File / Export menüsünde bulabilirsiniz.

Photoshop içerisinden Silverlight 2.0 DeepZoom çıktısı!
Photoshop içerisinden Silverlight 2.0 DeepZoom çıktısı!

Aşağıda Elazığ gezimden Palu dağında çekmiş olduğum panoramik fotoğrafı inceleyebilirsiniz :) Fotoğrafın bilgisayarımdaki kayıtlı hali 45MB.

Sunday, October 19, 2008 3:42:19 PM (GTB Standard Time, UTC+02:00)  #    Comments [6]   Photoshop | Silverlight 2.0  | 
 Saturday, October 18, 2008

HD Photo mantığı aslında adından da az çok anlaşılabileceği üzere yüksek çözünürlüklü (High Definition) fotoğraf yayını ile ilgili bir kavram. Daha önceki yazılarımdan birinde sizlere Image Composition Editor'dan bahsetmiştim. Ücretsiz bir araç olarak hem DeepZoom projeleri hem de 360 derece HD View çıktıları alabiliyordu. Normalde HD View'ın istemci tarafında çalışabilmesi için ayrı bir Plug-In kullanılması gerekirken artık ekip bu işlevselliği Silverlight tarafına taşımış ve DeepZoom ile 360 derece görüntü sistemini birleştirmiş. Tek yapmanız artık Image Composition Editor içerisinde DeepZoom seçeneğini seçerek Export almak.

Buyurun size 360 derecelik bir manzara...

Saturday, October 18, 2008 2:51:57 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, October 15, 2008

Bugün sizlerle yeni bir açık kaynak kodlu Silverlight 2.0 uygulamamı paylaşacağım. Hatırlarsanız bundan aylar önce Silverlight 1.0 ile bir Twitter Widget hazırlamış ve sizlerle kaynak kodlarını paylaşmıştım. Şimdi de 2.0 ile yeni bir Widget hazırladım. Bu sefer Widget'ın TwitXR desteği gibi ilginç özellikleri var

Bir Widget hikayesi...

Silverlight 2.0 ile geliştirme yapmanın 1.0'a kıyasla çok sayıda avantajı var fakat unutmayalım ki artık .NET tarafındayız ve JavaScript ile olduğu kadar low level kod yazmıyoruz. Ne demek istediğimi makale boyunca daha net anlayacağınızdan eminim. Peki size neler anlatacağım?

Uygulamanın içindeki kodların açıklamalarını zaten kodlar içerisindeki yorum satırlarında bulabilirsiniz. Yorum satırlarını İngilizce yazdım çünkü uygulamayı yurt dışı ile de paylaşacağım. Önemli olan ve benim özellikle değinmek istediğim noktalar bir Widget hazırlarken karşılaştığım duruma özel sorunlarla ilgili. Gelin daha fazla konuşmak yerine sorunlara el atalım.

Twitter API saçmalığı!

Twitter'ın çok güzel bir XML API yapısı var. Sorunlardan ilki bu API için ister Flash ister Silverlight hiç fark etmez ClientAccessPolicy dosyası konmamış, yani Cross-Domain-Request yasak! Durum böyle olunca sunucu tarafında bir proxy oluşturarak veriyi kendi sunucunuzaalıp kendi Widget'ınıza aktarmanız gerekiyor, ama bunu da yapamıyoruz çünkü şöyle bir saçmalık mevcut; istemci başına bir saatte 70 request sınırı var. Eeee? Tüm requestleri benim Web Server'ım yapacak sonuçta tüm ziyaretçiler için, 70 kesinlikle kabul edilebilir bir sınır değil. Büyük ihtimal ile Windows uygulamaları falan düşünülmüş.

Sonuç olarak Silverlight 1.0 Widget'da kullandığımız Remote Script Injection ile Cross-Domain-Reqest taktiğini Silverlight 2.0 da da kullanmamız gerek. Dinamik olarak sayfaya bir script tagı ekleyip twitter sitesinden JavaScript alıp sitemizde çalıştırıyorduk. Parametre olarak da bizim istediğimiz veriler geliyordu. İşte sorular;

Silverlight 2.0 ile dinamik Script tagları sayfaya nasıl eklenir?

        'Insert our dynamic Script Tag to get Cross Domain Data

        Dim MyDoc As HtmlDocument = HtmlPage.Document

        Dim ScriptTag = MyDoc.CreateElement("script")

        ScriptTag.SetAttribute("type", "text/javascript")

        ScriptTag.SetAttribute("src", "http://twitter.com/statuses/user_timeline/" & InitParams("twitterid") & ".json?callback=TwitterIncData&count=" & InitParams("count"))

        MyDoc.Body.AppendChild(ScriptTag)

Yukarıdaki kod ile rahatlıkla dinamik olarak bir Script tagı yaratıp özelliklerini de ayarlayıp içerisinde bulunduğumuz sayfanın Body'sine ekleyebiliyoruz. Böylece uzaktaki dosya çağrılacaktır. Twitter adresinin içindeki parametrelerin konumuzla şimdilik alakası yok. Ama bu adres üzerinden gönderdiğimiz callback parametresi Twitter'dan data gelince sayfamızda çalıştırılacak olan JavaScript'in ta kendisi. Peki bu durumda data gelince çağrılan JavaScript'ten bizim Silverlight 2.0'ın nasıl haberi olacak?

JavaScript'ten Silverlight 2.0 fonksiyonları nasıl çağrılır?

Buyurun makalemi okuyun : http://daron.yondem.com/tr/PermaLink.aspx?guid=a1426eb0-7120-4a66-9d5c-de5027fd59ed

Şimdi veri geldi elimize ama gelen veri JSON! Bunu nasıl olacak da anlaşılabilir bir hale çevireceğiz ve .NET nesneleri şeklinde kullanabileceğiz?

JSON verisi Silverlight 2.0'a nasıl alınır?

Buyurun bir makale daha: http://daron.yondem.com/tr/PermaLink.aspx?guid=457fbb28-892e-4a37-b7d3-cb297d97020b

Ama ben yukarıdaki makalede anlatılanı yapmadım, JSON'dan çekmek istediğim veri belli olduğu için ve twitter'ın JSON formatı basit olduğu için doğrudan aşağıdaki kod ile gelen her JavaScript nesnesine ScriptObject muamelesi yaptım.

        For x As Integer = 0 To CInt(InitParams("count")) - 1

            AllData.Add(New TwitPost(JSON.GetProperty(x).GetProperty("text").ToString, JSON.GetProperty(x).GetProperty("created_at").ToString, JSON.GetProperty(x).GetProperty("id").ToString))

        Next

Yukarıda JSON değişkeninin içerisinde doğrudan JavaScript tarafından gelen JSON objesi bulunuyor. GetProperty metodu ile herhangi bir diziden istediğimiz öğeyi ve özelliklerini tek tek alabiliyorum.

Bir sonraki sorunumuz hangi Twitter hesabından veri çekeceğimiz Widget'ı kullananların nasıl karar verebileceği. Bunun için Silverlight 2.0'ın sayfaya yerleştirildiği Object taglarının parametrelerini kullanacağız.

Parametreli Silverlight 2.0 dosyaları kullanımı nasıl olur?

Buyurun size bir makale : http://daron.yondem.com/tr/PermaLink.aspx?guid=4834596e-b5ec-450f-8e3c-cfba929d958e

Twitter'dan data alma işleminin Widget'ın bulunduğu sayfa tamamen yüklendikten sonra başlasın istiyoruz. Bun durum data yüklendikten sonra DOM'a ulaşıyor olmamızdan kaynaklanıyor, eğer sayfa tam yüklenmemişse daha DOM listeleri sabitlenmemiş olabilir.

HTML / DOM eventlarını Silverlight 2.0 ile nasıl yakalarım?

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim MyDoc As HtmlDocument = HtmlPage.Document

        HtmlPage.Window.AttachEvent("onload", AddressOf DocLoaded)

    End Sub

 

    Private Sub DocLoaded(ByVal sender As Object, ByVal e As EventArgs)

      

    End Sub

Yukarıdaki kod ile yaratmış olduğunuz bir event-handlerı nasıl sayfanın eventların veya bulduğunuz herhangi bir HTML nesnesinin eventlarına ekleyebileceğinizi görebilirsiniz. Kullanım şekli epey basit.

Bir sonraki adımda bir TextBlock içerisine farklı formatlarda yazı eklemek istiyoruz. Bunda zor ne var? diyebilirsiniz :) Ama bir TextBlock'un Text özelliğine baktığınızda String tipinde olduğunu görüyorsunuz. Peki buna nasıl bir formatlama bilgisi aktarabiliriz ki? Aktaramayız :) Aslında TextBlock'un bir de Inlines diye bir dizisi var. Bunun içerisinde satır içi Item'lar saklanıyor. Eğer Inlines ile ilgili bir ayarlama yapılmamışsa ve doğrudan Text özelliği set edilmiş ise arkaplanda otomatik olarak bir Inline Item yaratılarak bu diziye ekleniyor. Tüm bunlar programatik olarak da yapılabilir.

Bir TextBlock'un içindeki belirli bir metnin rengi programatik olarak nasıl değiştirilir?

            Dim Span As New Documents.Run

            Span.Text = AllText.Substring(0, AllText.IndexOf(FoundURLs.Item(0).Value))

            Span.Foreground = CType(App.Current.Resources("PostTextForeGround"), SolidColorBrush)

            Current.Inlines.Item(0) = Span

            Span = New Documents.Run

            Span.Text = FoundURLs.Item(0).Value

            Span.Foreground = CType(App.Current.Resources("PostTextLinkForeGround"), SolidColorBrush)

 

            Span.TextDecorations = TextDecorations.Underline

            Current.Inlines.Add(Span)

            Span = New Documents.Run

            Span.Text = AllText.Substring(AllText.IndexOf(FoundURLs.Item(0).Value) + FoundURLs.Item(0).Value.Length, AllText.Length - (AllText.IndexOf(FoundURLs.Item(0).Value) + FoundURLs.Item(0).Value.Length))

            Span.Foreground = CType(App.Current.Resources("PostTextForeGround"), SolidColorBrush)

            Current.Inlines.Add(Span)

Yukarıdaki kod içerisinde Current değişkeni aslında bir TextBlock. Bu TextBlock içerisinde URL'i alıp URL'den öncesini ayrı bir Run olarak, URL'i ayrı bir Run olarak, kalanı da ayrı bir Run olarak TextBlock'un Inlines dizisine ekliyoruz. Böylece her bir Run için görsel olarak farklı ayarlar yapabiliyoruz.

Yazımın en başında TwitXR desteği derken ne demek istediğimi biraz anlatıyım. Twitter ile TwitXR beraber çalışan sitelerdir aslında. TwitXR üzerine yolladığınız bir resim ve yazı otomatik olarak Twitter'a da aktarılır. Bizim Widget Twitter'dan Post'ları alırken kontrol edecek eğer o Post TwitXR'dan gelmişse uygun fotoğrafı da bularak gösterecek. Tüm bu hikayede benim istediğim nokta TwitXR'dan alınan resim istemciye yüklenirken yüklemenin durumundan haberdar olmaktı. Yani resmi istedim ama tam olarak yüklendi mi yoksa indiriliyor mu?

Remote Image yüklerken Progress göstermek!

Başından beridir Remote-Request'e izin verilmiyor ve Policy dosyaları yok diyoruz! Bu durumda benim normal bir WebClient sınıfı ile resmi indirmem ve sonra gelen Stream'i Image nesnesine bağlayıp sahneye koyma şansım yok. Mecburen Image'ı doğrudan Image nesnesine bağlamak zorundayım, ancak bu şekilde remote resim alabiliyorum. Ama bunu yaparken de zaten Imaging.BitmapImage sınıfını kullanmak zorundayım ve bu sınıfın kendine özel bir DownloadProgress'i var :)

 WithEvents PhotoDownload As New Imaging.BitmapImage

 

    'The Photo for the PhotoFrame has been downloaded.

    Private Sub PhotoDownload_DownloadProgress(ByVal sender As Object, ByVal e As System.Windows.Media.Imaging.DownloadProgressEventArgs) Handles PhotoDownload.DownloadProgress

        If e.Progress = 100 Then

            GetBig(MousePos.Y)

        End If

    End Sub

 

    'Play the anim when the mouse is on

    Private Sub Clickable_MouseEnter(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseEventArgs)

            PhotoDownload.UriSource = New Uri(MyPhoto, UriKind.Absolute)

            Photo.Source = PhotoDownload

    End Sub

Yukarıdaki kod içerisinde PhotoDownload adındaki BitmapImage'e fotoğrafın URL'ini veriyorum ve sonra da Photo adında Image UIElement nesneme Source olarak veriyorum. Böylece Silverlight resmi BitmapImage ile indirerek Image nesnesine bağlayıp göstermeye çalışıyor. Bu esnada BitmapImage'ın DownloadProgress'i çalışıyor. İlginç bir şekilde bu Progress event'ı içerisindeki Progress özelliği 1 ile 0 arasında olması gerekirken ya 0 ya da 100 döndürüyor. Normalde 0 = indirilemedi ve 1 = indirildi anlamına gelmeliydi. Sanırım bu bir BUG :) Her neyse bir işimizi şimdilik halletik. Unutmayın buradaki Progress WebClient'taki biri Double değil, Integer. Yani aslında bir Progress değil de Status değeri veriyor.

Şeffaf uygulama ve Overlay Sorunu

Aslında uygulama fonunu şeffaf yapmak çok kolay. Buyurun makalesi : http://daron.yondem.com/tr/PermaLink.aspx?guid=b334e195-feb7-4411-a77d-b6f07d482068

Esas sorun ben şeffaf olan yerlerin sadece şeffaf gözükmesini değil aynı anda o şeffaflığın arkasındaki HTML'in de kullanılabilir olmasını istiyorum. İşte bu olmuyor! Hedefim Widget içerisinde herhangi bir Post'un fare ile üzerine gelince yana doğru sayfanın üzerine taşacak şekilde uygulamanın genişlemesi ve orada da postun fotosunun gözükmesi. Tabi tüm uygulama gelişmeyecek sadece fotoğrafın gözükeceği bir kısım açılacak. Şeffaf fon kullanıldığında görsel olarak bir sorun yok gibi gözükse de bir bakıyorsunuz ki şeffaf olmasına rağmen uygulama alanınız fotoğrafın gösterileceği yerleri de kapsadığı yani sayfaya taştığı için o kısımlardaki HTML kontrolleri çalışmıyor. Bu konu maalesef Flash'ta daha iyi çözülmüş durumda, Flash'ta şeffaf olan yerler gerçekten şeffaf :(

Peki nasıl çözeriz, dinamik olarak Silverlight uygulamasının sayfadaki kapladığı alanı yine kodlarımız ile düzenlememiz gerek. Silverlight'ın OBJECT taglarına bir ID değeri vererek bunun üzerinden OBJECT'in genişliğini değiştirebiliriz.

        HtmlPage.Document.GetElementById("TwitterSLWidget").SetAttribute("width", "360px")

Bu kod ile kullandığımız OBJECT tagları aşağıdaki gibi.

                <object style="position:absolute; z-index: 2;" id="TwitterSLWidget" data="data:application/x-silverlight-2,"

                    type="application/x-silverlight-2">

                    <param name="source" value="ClientBin/TwitterWidget.xap" />

                    <param name="initParams" value="twitterid=daronyondem,count=10,twitxrid=daronyondem" />

                    <param name="onerror" value="onSilverlightError" />

                    <param name="background" value="Transparent" />

                    <param name="pluginbackground" value="Transparent" />

                    <param name="windowless" value="true" />

                    <param name="background" value="white" />

                    <param name="minRuntimeVersion" value="2.0.31005.0" />

                    <param name="autoUpgrade" value="true" />

                    <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                        <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"

                            style="border-style: none" />

                    </a>

                </object>

Widget'ı nasıl kullanırız?

Birazdan kaynak kodları ile beraber Widget'ı sizinle paylaşacağım. Ama onun öncesinde hemen Widget'ı nasıl kullanırız ona bakalım.

            <div id="TwitterSLWidgetHost">

                <object style="position:absolute; z-index: 2;" id="TwitterSLWidget" data="data:application/x-silverlight-2,"

                    type="application/x-silverlight-2">

                    <param name="source" value="ClientBin/TwitterWidget.xap" />

                    <param name="initParams" value="twitterid=daronyondem,count=10,twitxrid=daronyondem" />

                    <param name="onerror" value="onSilverlightError" />

                    <param name="background" value="Transparent" />

                    <param name="pluginbackground" value="Transparent" />

                    <param name="windowless" value="true" />

                    <param name="background" value="white" />

                    <param name="minRuntimeVersion" value="2.0.31005.0" />

                    <param name="autoUpgrade" value="true" />

                    <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

                        <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"

                            style="border-style: none" />

                    </a>

                </object></div>

Yukarıdaki HTML kodunu sayfanıza yerleştirmeniz gerekiyor. Özellikle koyu olan yerlere dikkat. daronyondem yerine kendi Twitter ve TwitXT hesaplarınızın adlarını yazmanız gerek. count kısmına da koç Post gözüksün istiyorsanız onu yazabilirsiniz. OBJECT ve DIV taglarının ID'leri çok önemli. Bu ID'ler kodlarda kullanılıyor, eğer değiştirirseniz kodları da tekrar düzenleyip XAP dosyasını Compile etmeniz gerekecektir.

       function TwitterIncData(object)

        {

        document.getElementById("TwitterSLWidget").Content.Page.IncData(object);

        }

Son olarak yukarıdaki kodu da sayfanızda uygun bir JavaScript dosyasına veya tagları arasında koymanız ve XAP dosyasını sunucuya kopyalamanız yeterli olacaktır.

Kaynak Kodlar

Tüm projenin kaynak kodlarını aşağıdaki adresten indirebilirsiniz. Proje epey karışık oldu, özellikle Remote Script Injection kullandığımız için Cross-Browser uyumluluğu konusunda sıkıntılar var. Diğer yandan Overlay konusunda da farklı tarayıcılarda sorunlar var. O nedenle şimdilik ben ancak IE 7 desteği sunabiliyorum, uğraşacak pek zaman olmadı. Eğer siz uygulamayı diğer tarayıcıları da destekleyecek şekilde modifiye ederseniz beni haberdar etmeniz yeterli. Böylece mini bir açık kaynak projesi olmuş olur.

Makaledeki tüm kodlar VB :) çünkü uygulamadan kesip yapıştırdım. Uygulamayı da malum VB ile yazdım :) C#'cılara selamlar :)

Silverlight 2.0 Twitter / TwitXR Widget
Kaynak Kodlar ve Proje - 15102008_1.rar (558,89 KB)

Hepinize kolay gelsin.

Wednesday, October 15, 2008 10:28:42 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, October 14, 2008

Silverlight 2.0 sonunda yayınlandı. Bana çook uzun gelen bu bekleyişin sonunda hem bazı şeyleri tekrar ederek hem de SL 2.0 ile ilgili yeni bilgiler vererek bu dünyaya giriş yolunda başlangıç noktasında olanlar için bir rehber hazırlamaya karar verdim. Buyurun beraber ilerleyelim.

Silverlight 2.0 Runtime

Silverlight uygulamalarının istemci tarafında yani tarayıcı içerisinde çalışabilmesi için sistemde Silverlight 2.0 RunTime'ın yüklü olması gerekiyor. Bu paket şu anda 4MB büyüklüğünde ve otomatik olarak RunTime'ı yükleyecek mekanizmalar zaten Silverlight projelerine dahil ediliyor. Bu RunTime şu anda tüm tarayıcılarda çalışıyor ve Windows, Mac sürümleri mevcut. Windows Mobile, Linux ve Symbian konusunda çalışmalar devam ediyor.

Silverlight 'ın çalışabilmesi için sunucu veya istemci tarafında kesinlikle .NET Framework yüklü olması gerekmiyor!

Gelen yenilikler...

Silverlight 2.0 ile beraber artık Silverlight uygulamaları programlarken VB, C#, JavaScript, IronPyhton ve IronRuby dillerini kullanabilirsiniz.

1.0 sürümünde eksik olan ana form kontrollerinin RunTime'a eklenmesinin yanı sıra Layout kontrolleri, Calendar gibi özel kontroller ve DataGrid gibi veri kontrolleri de kullanımımıza sunuluyor. Tüm bu kontrollerin tasarımları ile ilgili WPF'den de alışık olduğumuz şablonlama yapısı kullanılabilir.

Silverlight 2.0 ile REST, WS*/SOAP, POX, RSS, ve HTTP kullanılarak farklı verilere ulaşmak mümkün. Bu çerçevede Cross-Domain-Request için de Policy File aracılığı ile destek sağlanıyor.

Aslında Silverlight 2.0 ile gelen Core CLR .NET'te alışık olduğumuzdan pek farklı değil. İstemci tarafında çalışacağımız için HTML/DOM entegrasyonu, LINQ ve özellikle XLINQ gibi tüm yapılar Silverlight 2.0 içerisinde de mevcut.

Gelecek neler getirecek?

AJAX Control Toolkit'i hatırlayanlarınız vardır. Aynı şekilde WPF için de bir control toolkit çıkarıldı. Şimdi de sıra Silverlight tarafında. "Silverlight Control Pack" adı verilen paket CodePlex üzerinden yayınlanacak TreeView gibi güzel kontroller olacak. Paket tamamen açık kaynaklı olarak yayınlanacak.

Eclipse özellikle Cross-Platform bir yazılım geliştirme aracı olarak bilinen IDE'lerden biri. Microsoft sponsorluğunda ilerleyen Soyotec'e ait bir proje ile Eclipse'e Silverlight geliştirme entegrasyonu uygulanacak. Ek olarak Microsoft Silverlight XAML'ının "Open Specification" olarak duyurdu, yani isteyenler bu XAML kodunu üreten veya yazan yazılımlar üretebilecekler.

Araçlar nerede?

Her zamanki gibi Visual Studio üzerinde "Silverlight Tools" paketini kurmanız gerekiyor. Bu paket ile beraber Silverlight SDK, proje şablonları, Intellisense desteği gibi noktlar Visual Studio'ya dahil oluyor. Sonrasında tabi ki Silverlight 2.0 uygulamalarını tasarımı için de Expression Blend'e ihtiyacımız var. Blend'in son yayınlanan sürümü olan 2.0 sürümü sadece Silverlight 1.0 destekliyor. Blend 2'ye Silverlight 2.0 desteğinin gelmesi için Blend 2 SP1'in yüklenmesi gerek. Silverlight 2.0 Beta 2 günlerini hatırlayan Blend 2.5'i de hatırlayacaklardır, artık 2.5 diye bir şey yok :)

Silverlight Tools for Visual Studio 2008 SP1 (72.1MB)
Microsoft Expression Blend 2 Service Pack 1 (17.8MB)
Deep Zoom Composer (3.8MB)

Silverlight 2.0 Tools paketi artık Visual Studio'nun Express sürümlerini de destekliyor. Yani Silverlight uygulamaları programlamak için çok kuvvetli ücretsiz bir alternatifiniz var.

Nasıl öğrenebilirim?

Silverlight 2.0 öğrenebilmeniz için başta Silverlight 2.0'ın desteklediği programlama dillerinden birini öğrenmeniz gerek. Bu noktada ağırlıklı olarak C# ve VB karşımıza çıkacaktır. Aşağıdaki adreste benim şu anda Silverlight 2.0 ile ilgili toplam 55 makalem var.

http://daron.yondem.com/tr/formatpage.aspx?path=liste.format.html#Silverlight

Makaleleri incelemeye başlarken Silverlight 2.0 seminerlerime ait videoları de SeminerTV bölümünden edinebilirsiniz. Çok yakında Silverlight 2.0 ile ilgili farklı detaylara yönelik seminer, ücretsiz eğitimleri de blogumdan duyuracağım.

Hepinize kolay gelsin!

Tuesday, October 14, 2008 11:06:29 AM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Expression Blend | Silverlight 2.0 | Visual Studio 2008  | 
 Thursday, October 09, 2008

Silverlight 2.0'ın RC0 olması ile beraber tabi ki her şey yenilendi. ve bu yenilikleri takiben "Offline Documentation" paketinin de yenilenmesinin zamanı gelmişti. Aşağıdaki linkten Silverlight 2.0'ın tüm SDK paketini internete bağlı olmadan da kullanılabilecek CHM formatında indirebilirsiniz.

http://go.microsoft.com/fwlink/?LinkID=127106

Özellikle Vista kullanıcıları için ufak bir uyarıda bulunmak istiyorum. Vista'da CHM dosyalarını açtığınızda ekran boş kalıyorsa hemen dosyaya sağ tuş tıklayarak "Properties" kısmına geçip "Unblock" düğmesine basın. Sonrasında dosyayı tekrar açtığında herhangi bir sorun olmayacaktır.

Hepinize kolay gelsin.

Thursday, October 09, 2008 5:31:49 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, October 06, 2008

Panoramic fotoğraf çekmek benim en sevdiğim hobilerimden biridir. Fotoğraf çekmeyi zaten severim, hatta çoğu turistik gezimin amacı fotoğraf çekmektir. Kulağa garip gelebilir fakat sadece fotoğrafını çekmek için gittiğim yerler var :) Neyse, konuya dönelik. Çektikten sonra baktığımda en mutlu olduğum fotoğraflar genelde ya panoramik ya da makro fotoğraflardır. Panoramik derken tabi ki binlerce dolarlık cihazlardan bahsetmiyorum, standart bir fotoğraf makinesi ile birden çok fotoğrafın çekilerek bilgisayarda birleştirilmesinden bahsediyorum. Eh benim fotoğrafçılığım bu kadar :)

Peki neden bu kadar geyik yaptım? Panoramik fotoğraf birleştirmek konusunda Exposure ayarlaması da yapabilen ücretsiz "adam akıllı" program yok :) (tu). Artık var.

Microsoft Research ekibinin yayınladığı ücretsiz bir araç olan Microsoft Image Composite Editor birden çok fotoğrafı alarak Exposure geçişlerini de ayarlayabiliyor. Yazılımın gerçekten ilginç özellikleri var.

Uygulama;

  • Silverlight DeepZoom projesi çıktısı verebiliyor, büyük panoramik fotolar için süper!
  • Photoshop Layer'lı PSD dosyası çıktısı alınabiliyor.
  • 360 derecelik birleştirme yapabiliyor.
  • HD Video web sitesi yaratabiliyor.
  • 64 bit destekli sürümü ile müthiş performans sunabiliyor.
  • GPU'nuzu kullanabiliyor!

Programı bilgisayarınıza indirmek ve hemen kullanmak için aşağıdaki adresi ziyaret etmeniz yeterli.

http://research.microsoft.com/ivm/ice.html

Monday, October 06, 2008 9:18:34 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Sunday, October 05, 2008

.NET Framework'ün ufak bir paketini içerse de Silverlight ile web tarayıcısı içerisinde büyük mucizeler yaratmak mümkün. .NET'in JavaScript gibi scripting dillerine kıyasla işlemci kullanımındaki hakimiyetini de düşündüğümüzde istemci tarafında yapacağımız işlemlerin yoğunluğun artacağı kesin. Tüm bu işlemler süresince tabi ki kullanıcıları da bilgilendirmemiz gerekiyor. AJAX ile az çok web tarafında da alıştığımız "Loading" GIF'lerinin yerine Silverlight tarafında RC0 ile beraber artık ProgressBar kontrolümüz var.

<UserControl x:Class="SilverlightApplication7.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <ProgressBar Height="28"

                VerticalAlignment="Top"

                Margin="40,58,29,0"/>

  </Grid>

</UserControl>

Standart bir ProgressBar'ı yukarıdaki XAML kodu ile uygulamanıza ekleyebilirsiniz. Aslında Silverlight içerisinde ProgressBar'ın Winforms'daki muadilinden ilk bakışta pek bir farkı yok. ProgressBar'ın Value özelliği o anki değeri, Maximum özelliği ise alabileceği en yüksek değeri tanımlıyor.

Gelin ufak bir örnek yapmak için bir DispatcherTimer kullanalım. Timer'ımızın iki saniyede bir ProgressBar'ı biraz ilerletsin. Böylece işlem yapılıyormuş gibi ProgressBar'ı izleyebilelim.

Partial Public Class Page

    Inherits UserControl

 

    WithEvents Timer As New System.Windows.Threading.DispatcherTimer

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Progress.Maximum = 20

        Timer.Interval = New TimeSpan(0, 0, 2)

        Timer.Start()

    End Sub

 

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer.Tick

        Progress.Value += 1

    End Sub

End Class

Yukarıdaki kod ile Progress adındaki ProgressBar'ımızı oynattığımızda aşağıdaki görüntü ile karşılaşıyoruz.

ProgressBar iş başında.
ProgressBar iş başında.

Eğer gerçekten yapılacak işlemin ne kadar süreceği bilmiyorsanız ve bir şekilde bu bilgiyi kullanıcıya gösterme şansınız yoksa bu sefer de işlemin sürdüğüne dair bir gösterge olarak ProgressBar'ı kullanmak için IsIndeterminate özelliğini True olarak ayarlayabilirsiniz.

<ProgressBar Height="28"

            VerticalAlignment="Top"

            Margin="40,58,29,0"

            x:Name="Progress"

            IsIndeterminate="True"/>

Böyle bir durumda ProgressBar içerisinde sürekli olarak aynı animasyon çalıştırılacaktır.

ProgressBar sonsuz döngüde!
ProgressBar sonsuz döngüde!

ProgressBar'ın görselliğini değiştirmek için Foreground ve Background özelliklerinden faydalanabilirsiniz. Foreground özelliği ProgressBar içerisinde dolu kısımları etkilerken Background ise ProgressBar'ın boş olan kısımlarını etkileyecektir.

<ProgressBar

            x:Name="Progress">

  <ProgressBar.Background>

    <ImageBrush

                ImageSource="Garden.jpg"/>

  </ProgressBar.Background>

</ProgressBar>

Örneğin yukarıdaki kod ile aşağıdaki şekilde bir ProgressBar'ın fonuna bir fotoğraf yerleştirebilirsiniz. Hatta Background için bir ImageBrush yerine VideoBrush kullanarak farklı uygulamalar da oluşturulabilir. Burada özellikle Indeterminate ile ilgili dikkat etmek gerek. Indeterminate aktif hale geldiğinde Silverlight içerisinde ProgressBar'ın ForeGround'u ile tüm kontrol kaplanıyor ve üzerinden beyaz dikey Gradient'lar animasyon ile geçiriliyor. Bu sistem ancak ProgressBar'ın ControlTemplate'i özelleştirilebilirse değiştirilebiliyor aksi halde tüm standart ProgressBar kontrolleri bu şekilde çalışıyor.

Hepinize kolay gelsin.

Sunday, October 05, 2008 8:05:41 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Thursday, October 02, 2008

Silverlight 2.0 RC0 ile gelen yeni kontrollerden biri de ComboBox kontrolü. Bu yazımızda Combobox'ın kullanımına, görsel düzenlemelerin nasıl yapıldığında göz atacağız. İlk olarak yeni bir Silverlight projesi yaratalım ve Expression Blend 2 içerisinden Asslet Library'de bir Combobox bularak sahneye yerleştirelim.

<UserControl x:Class="SilverlightApplication5.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <ComboBox HorizontalAlignment="Left"

              VerticalAlignment="Top"

              Width="157"

              Margin="38,43,0,0"/>

  </Grid>

</UserControl>

Yukarıdaki XAML kodu sahnede boş bir Combobox yaratacaktık. Combobox içerisine XAML kodu ile yeni öğeler eklemek istersek Combobox'ın Items dizisine ComboBoxItem'lar eklememiz gerekecek.

<ComboBox HorizontalAlignment="Left"

          VerticalAlignment="Top"

          Width="157"

          Margin="38,43,0,0">

  <ComboBox.Items>

    <ComboBoxItem Content="İlk Seçenek"></ComboBoxItem>

    <ComboBoxItem Content="İkinci Seçenek"></ComboBoxItem>

    <ComboBoxItem Content="Son Seçenek"></ComboBoxItem>

  </ComboBox.Items>

</ComboBox>

Her ComboBoxItem'ın ayrıca bir de IsSelected özelliği var. Böylece uygulama ilk çalıştırıldığında ve ComboBox sahneye ilk geldiğinde hangi Item'ın seçili olacağına karar verebilirsiniz.

<ComboBox HorizontalAlignment="Left"

          VerticalAlignment="Top"

          Width="157"

          Margin="38,43,0,0">

  <ComboBox.Items>

    <ComboBoxItem IsSelected="True"

                  Content="İlk Seçenek"></ComboBoxItem>

    <ComboBoxItem Content="İkinci Seçenek"></ComboBoxItem>

    <ComboBoxItem Content="Son Seçenek"></ComboBoxItem>

  </ComboBox.Items>

</ComboBox>

Tabi çoğu zaman bizler uygulamalarımızda bu şekilde seçenekleri XAML kodu içerisine gömmeyeceğiz. Genelde bir veri kaynağımız olacak ve veri kaynağındaki listelerin ComboBox içerisinde gösterilmesini tercih edeceğiz. Bu durumda gelin şimdi de ComboBox'a nasıl veri bağlayabileceğimizi inceleyelim.

İlk olarak Urun adında sınıfımızı tanımlayalım ve bu sınıf üzerinden örneğimizde kullanacağımız geçici veriyi üretelim.

[VB]

Class Urun

 

    Private PAdi As String

    Public Property Adi() As String

        Get

            Return PAdi

        End Get

        Set(ByVal value As String)

            PAdi = value

        End Set

    End Property

 

 

    Private PFiyat As Integer

    Public Property Fiyat() As Integer

        Get

            Return PFiyat

        End Get

        Set(ByVal value As Integer)

            PFiyat = value

        End Set

    End Property

 

End Class

[C#]

        public class Urun

        {

            private string PAdi;

            public string Adi

            {

                get { return PAdi; }

                set { PAdi = value; }

            }

 

 

            private int PFiyat;

            public int Fiyat

            {

                get { return PFiyat; }

                set { PFiyat = value; }

            }

        }

Uygulamamız ilk çalıştırıldığında yukarıda tanımladığımız Urun sınıfından nesneler yaratarak bir List değişkenine ekleyeceğiz. Sonra da bu listeyi ComboboxUrunler adını verdiğimiz Combobox'ımıza bağlayacağız.

[VB]

Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

    Dim Urunler As New List(Of Urun)

    Urunler.Add(New Urun With {.Adi = "Ürün Adi1", .Fiyat = 1000})

    Urunler.Add(New Urun With {.Adi = "Ürün Adi2", .Fiyat = 2000})

    Urunler.Add(New Urun With {.Adi = "Ürün Adi3", .Fiyat = 3000})

    Urunler.Add(New Urun With {.Adi = "Ürün Adi4", .Fiyat = 4000})

 

    comboboxUrunler.DisplayMemberPath = "Adi"

    comboboxUrunler.ItemsSource = Urunler

End Sub

[C#]

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            List<Urun> Urunler = new List<Urun>();

            Urunler.Add(new Urun { Adi = "Ürün Adi1", Fiyat = 1000 });

            Urunler.Add(new Urun { Adi = "Ürün Adi2", Fiyat = 2000 });

            Urunler.Add(new Urun { Adi = "Ürün Adi3", Fiyat = 3000 });

            Urunler.Add(new Urun { Adi = "Ürün Adi4", Fiyat = 4000 });

 

            comboboxUrunler.DisplayMemberPath = "Adi";

            comboboxUrunler.ItemsSource = Urunler;

        }

Combobox'ın ItemsSource özelliğine aktardığımız liste otomatik olarak Combobox'ın içerisine tüm öğelerin yerleştirilmesini sağlayacaktır fakat bizim yarattığımız Urun sınıfının hangi özelliğinin Combobox içerisinde gösterileceğini belirlememiz gerekiyor. Bunun için ComboBox'ın DisplayMemberPath özelliğine istediğimiz Urun sınıfının bir özelliğinin adını atıyoruz. Böylece ComboBox kendisine atanan dizideki her öğenin söz konusu özelliğindeki veriyi kullanıcıya gösterecektir.

Eğer veri bağlantısı sonrası ComboBox içerisinde seçili olacak öğeyi belirlemek isterseniz kullanabileceğiniz iki yöntem var.

[VB]

        comboboxUrunler.SelectedItem = (From gelenler In Urunler Where gelenler.Adi = "Ürün Adi2").SingleOrDefault

        comboboxUrunler.SelectedIndex = Urunler.IndexOf((From gelenler In Urunler Where gelenler.Adi = "Ürün Adi2").SingleOrDefault)

[C#]

comboboxUrunler.SelectedItem = (from gelenler in Urunler where gelenler.Adi == "Ürün Adi2" select gelenler).SingleOrDefault();

comboboxUrunler.SelectedIndex = Urunler.IndexOf((from gelenler in Urunler where gelenler.Adi == "Ürün Adi2" select gelenler).SingleOrDefault());

Bunlardan ilki doğrudan ComboBox'ın SelectedItem özelliğini tanımlayarak seçili öğeyi belirlemek. Yukarıdaki kod içerisinde elimizde diziden istediğimiz Item'ı bir LINQ sorgusu ile bularak söz konusu Item'ın SelectedItem olması gerektiğini belirlemiş oluyoruz. Bir diğer seçenek ise doğrudan seçili olacak Item'In Index numarasını SelectedIndex değerine aktarmak.

ComboBox içerisinde kullanıcı bir Item seçtiğinde ise doğrudan ComboBox'ın SelectionChanged event'ı çalıştırılacaktır. Böylece doğrudan SelectedItem özelliği üzerinden seçili öğeyi alabilir ve bu öğleyle ilgili bilgilere ulaşabilirsiniz. Bizim örneğimizde seçili öğenin tipinin de Urun olduğunu bildiğimiz için doğrudan Urun sınıfına Cast ederek seçili öğeye ait tüm bilgilere ulaşabiliyoruz.

[VB]

Private Sub comboboxUrunler_SelectionChanged(ByVal sender As Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles comboboxUrunler.SelectionChanged

    MessageBox.Show(CType(comboboxUrunler.SelectedItem, Urun).Fiyat)

End Sub

[C#]

        void comboboxUrunler_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

            MessageBox.Show(((Urun)comboboxUrunler.SelectedItem).Fiyat.ToString());

        }

Hepinize kolay gelsin.

Thursday, October 02, 2008 2:43:27 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, October 01, 2008

Silverlight 2.0 RC0 öncesinde Silverlight içerisinde özellikle kullanıcı girişlerinde şifrelerin yazılacağı bir TextBox oluşturmak epey zahmetli bir işti. Bunun için normal bir TextBox'ı sahneye yerleştiriyor sonra da bu TextBox'a tüm karakterleri * olan bir font bağlıyorduk. RC0 ile beraber artık bu işleme özgü bir PasswordBox kontrolümüz var. Bu yazımızda PasswordBox'ın kullanımına hızlıca değineceğiz.

Expression Blend 2 içerisinde PasswordBox kontrolü.
Expression Blend 2 içerisinde PasswordBox kontrolü.

Yeni bir Silverlight projesi yarattıktan sonra Expression Blend 2 içerisinde Asset Library bölümünde PasswordBox'ı bulabilirsiniz. Tasarım arayüzünden yukarıdaki şekilde bir PasswordBox alarak sahneye yerleştirdiğinizde XAML dosyasında aşağıdaki gibi bir kod ile karşılaşacaksınız.

<UserControl x:Class="SilverlightApplication4.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

      <PasswordBox Height="25" Margin="28,38,136,0" VerticalAlignment="Top"/>

    </Grid>

</UserControl>

Kodumuzda PasswordBox bir Grid içerisinde bulunduğu için Margin'i ayarlanmış durumda. Bu şekilde hazırlanan basit bir uygulamayı çalıştırdığınızda PasswordBox içerisine girdiğiniz her karakter bir nokta ile gösterilecektir.

PasswordBox'ın varsayılan görünümü.
PasswordBox'ın varsayılan görünümü.

PasswordBox'ın noktalarla doldurduğu karakterlerin yerine farklı bir karakter seçmek için PasswordBox'ın PasswordChar özelliğinden faydalanabilirsiniz. Bu özelliğe aktardığınız karakter PasswordBox içerisine yazılan her karakterin gösteriminde kullanılacaktır.

<UserControl x:Class="SilverlightApplication4.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <PasswordBox PasswordChar="*"

                Height="25"

                Margin="28,38,136,0"

                VerticalAlignment="Top"/>

  </Grid>

</UserControl>

Programatik olarak da yukarıda bahsettiğimiz tüm özelliklere VB veya C# kodunuz ile ulaşabilirsiniz.

Hepinize kolay gelsin.

Wednesday, October 01, 2008 1:32:52 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Sunday, September 28, 2008

Bu yazımızda Silverlight 2.0 RC0 ile Silverlight uygulaması içerisinde minik bir ekran koruyucusu yapacağız. Aslında amacımız ekran korumak değil tabi ki, istediğimiz şey kullanıcı Silverlight uygulamasını kullanmadığında farklı bir içerik göstermek. Bu belki bir reklam, belki farklı bir "Ekrana Geri Dön Kullanıcı" sesli mesajı veya çok daha farklı bir uyarı sistemi olabilir. Özellikle veritabanı üzerinden veri alarak bu veriyi düzenleyen bir Silverlight uygulamasını düşünürsek belki de kullanıcı uzun süre ekran başında değilse verileri sunucuya göndererek kaydetmek için doğru zamanı yakalamışız demektir. Bu sistemin kullanılabileceği diğer örnekleri sizin hayal gücünüze bırakıyorum.

Animasyonlarımızı hazırlayalım

Örneğimizde görsel olarak herhangi bir ek öğe yer almayacak. Kullanıcı fareyi hareket ettirmezse bir süre sonra uygulamanın ana Grid'inin rengini siyaha çevireceğiz. Kullanıcı fare ile herhangi bir hareket yaptığı anda ise tekrar söz konusu Grid'i beyaza çevireceğiz. Siz örneklerinizde çok daha farklı işlemler yapabilirsiniz. Şimdi gelin bu iki animasyonla beraber oluşan XAML kodumuza göz atalım.

<UserControl x:Class="SilverlightApplication2.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <UserControl.Resources>

    <Storyboard x:Name="Gitti">

      <ColorAnimationUsingKeyFrames BeginTime="00:00:00"

                                    Storyboard.TargetName="LayoutRoot"

                                    Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">

        <SplineColorKeyFrame KeyTime="00:00:01"

                            Value="#FF000000"/>

      </ColorAnimationUsingKeyFrames>

    </Storyboard>

    <Storyboard x:Name="Geldi">

      <ColorAnimationUsingKeyFrames BeginTime="00:00:00"

                                    Storyboard.TargetName="LayoutRoot"

                                    Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">

        <SplineColorKeyFrame KeyTime="00:00:01"

                            Value="#FFFFFFFF"/>

      </ColorAnimationUsingKeyFrames>

    </Storyboard>

  </UserControl.Resources>

  <Grid x:Name="LayoutRoot"

        Background="White">

 

  </Grid>

</UserControl>

Gördüğünüz gibi kodumuzda yer alan iki animasyon da LayoutRoot adındaki Grid'in rengini bir saniyede değiştirmeyi hedefliyor. Animasyonlardan Geldi adındaki Storyboard Grid'in rengini beyaza alırken, Gitti adındaki ise Siyah'a götürüyor. Kullanıcı fareyi hareket ettirmediğinde yani ekran başından gittiğinde Gitti, geri geldiğinde ise Geldi animasyonunu oynatacağız.

DispatcherTimer yetiş imdadımıza!

Farenin kullanıcı tarafından hareket ettirilip ettirilmediği sürekli kontrol etmek yerine aslında bizim ana bir Timer'a ihtiyacımız var. Varsayalım ki beş saniye boyunca herhangi bir hareket olmamışsa ekranı karartacağız. Bu durumda farenin oynatıldığı son harekette bu beş saniyelik sayacı başlatmamız gerek. Biz hangi fare hareketinin son hareket olduğunu anlayamayacağımız için aslında farenin her hareketinde sayacımızı başlatmalıyız fakat sonrasında eğer fare tekrar hareket ettirilirse sayacı durdurup baştan başlatmamız gerek.

İlk olarak Timer olarak kullanacağımız DispathcerTimer'ı global olarak tanımlayalım.

[VB]

WithEvents Kontrol As New System.Windows.Threading.DispatcherTimer

[C#]

System.Windows.Threading.DispatcherTimer Kontrol = new System.Windows.Threading.DispatcherTimer();

Uygulama ilk olarak istemciye yüklendiğinde hemen elimizdeki Timer'ın Interval yani tekrar aralığını düzenleyerek Timer'ı başlatmamız gerekiyor.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Kontrol.Interval = New TimeSpan(0, 0, 5)

        Kontrol.Start()

    End Sub

[C#]

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            Kontrol.Interval = new TimeSpan(0, 0, 5);

            Kontrol.Start();

        }

Eğer fare hareket etmezse yukarıdaki Timer sonuna kadar çalışacak ve doğal olarak Timer'ın Tick event'ı çalıştırılacaktır. Fakat bu süreçte eğer fare oynatılırsa bizim bu Timer'ı durdurup baştan başlatmamız gerek ki sayacımızı da bir anlamda sıfırlamış olalım. Uygulamamızın MouseMove durumunu yakalamamız yeterli olacaktır.

[VB]

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        Kontrol.Stop()

        Kontrol.Start()

    End Sub

[C#]

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            Kontrol.Stop();

            Kontrol.Start();

        }

Sıra geldi Timer'ın Tick eventına gerekli kodu yazmaya. Aslında bu noktada yazacağımız tek kod bizim Gitti animasyonunu çalıştıracak olan kod olacak. Böylece uygulama kullanıcının fareyi beş saniyedir oynatmadığını algılamış ve gerekli işlemi yapmış olacak.

[VB]

    Private Sub Kontrol_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Kontrol.Tick

        Gitti.Begin()

        Gitmis = True

    End Sub

[C#]

        void Kontrol_Tick(object sender, EventArgs e)

        {

            Gitti.Begin();

            Gitmis = true;

        }

Kod içerisinde ilginizi çeken nokta eminim ki Gitmis değişkenidir. Gitmis değişkeni uygulamamızda global olarak tanımlayacağımız bir Boolean değişkeni. Bu değişkeni ScreenSaver yapımızın çalışıp çalışmadığını kontrol etmek için kullanacağız. Böylece MouseMove durumunda daha önce eğer ekran karartılmış ise ekranı aydınlatabileceğiz. Gelin MouseMove durumundaki yeni kodumuzu da inceleyelim.

[VB]

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        Kontrol.Stop()

        Kontrol.Start()

        If Gitmis Then

            Gitmis = False

            Geldi.Begin()

        End If

    End Sub

[C#]

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            Kontrol.Stop();

            Kontrol.Start();

            if (Gitmis)

            {

                Gitmis = false;

                Geldi.Begin();

            }

        }

Gördüğünüz gibi fare her oynatıldığında sayacımızı sıfırlarken daha önce ekran karartılmış mı kontrol ediyoruz. Eğer karartılmış ise hemen aydınlatma işlemini başlatıyoruz ve tabi ki Gitmis değişkenimizi de False olarak ayarlıyoruz.

Uygulamamızın tam kodu aşağıdaki şekilde sonlanıyor;

[VB]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    WithEvents Kontrol As New System.Windows.Threading.DispatcherTimer

    Dim Gitmis As Boolean = False

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Kontrol.Interval = New TimeSpan(0, 0, 5)

        Kontrol.Start()

    End Sub

 

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        Kontrol.Stop()

        Kontrol.Start()

        If Gitmis Then

            Gitmis = False

            Geldi.Begin()

        End If

    End Sub

 

    Private Sub Kontrol_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Kontrol.Tick

        Gitti.Begin()

        Gitmis = True

    End Sub

End Class

[C#]

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace SilverlightApplication3

{

    public partial class Page : UserControl

    {

        System.Windows.Threading.DispatcherTimer Kontrol = new System.Windows.Threading.DispatcherTimer();

        bool Gitmis;

 

        public Page()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Page_Loaded);

            this.MouseMove += new MouseEventHandler(Page_MouseMove);

            this.Kontrol.Tick += new EventHandler(Kontrol_Tick);

        }

 

        void Kontrol_Tick(object sender, EventArgs e)

        {

            Gitti.Begin();

            Gitmis = true;

        }

 

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            Kontrol.Stop();

            Kontrol.Start();

            if (Gitmis)

            {

                Gitmis = false;

                Geldi.Begin();

            }

        }

 

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            Kontrol.Interval = new TimeSpan(0, 0, 5);

            Kontrol.Start();

        }

 

    }

}

Hepinize kolay gelsin.

Sunday, September 28, 2008 8:30:35 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, September 27, 2008

Silverlight 2.0 RC0 çıktıktan sonra DeepZoom Composer ile proje yaratmayı denediyseniz göreceksiniz ki DeepZoom Composer hala Beta 2 projeleri yaratıyor. Aslında arada çok büyük farklar olduğunu söyleyemem ama bu dönemde eğer DeepZoom Composer ile uygulama hazırlayabilmek istiyorsanız DeepZoom Composer'ın kullandığı proje şablonlarını yenilemeniz gerekiyor.

DeepZoom Composer Silverlight 2.0 RC0 Proje Şablonu - 27092008_1.zip (21,85 KB)

Yukarıdaki dosyayı bilgisayarınıza indirdikten sonra içindekileri doğrudan C:\Program Files\Deep Zoom Composer\ adresine kopyalayın. Eğer siz DeepZoom Composer'ı farklı bir konuma yüklediyseniz tabi ki sizin bilgisayarınızdaki yükleme yerine kopyalamanız gerekecek.

Hepinize kolay gelsin.

Saturday, September 27, 2008 5:58:01 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Friday, September 26, 2008

INETA Summer Hit üzerinden uzun bir zaman geçti gibi hissettiğimiz bu günlerde yeni bir aktivite serisi ile tekrar karşınızdayız. Bu sefer İstanbul değil Anadolu'nun merkezi, Başkentimiz Ankara'da olacağız.

INETA Capital Hit Afişi

Dikkat ederseniz İstanbul'daki Summer Hit sonrası içeriğimizi de epeyce değiştirdik. Tabi bunda sizlerin doldurmuş olduğu değerlendirme formlarının etkisi çok büyük. Bu sefer çok daha sıkışık ve yoğun bir tempomuz olacak. Hediyelerimiz daha fazla (hatta çok ilginç beklenmedik şeyler var :)) ve içecek sorununu da hallettik (:))

İlk gün sabah yine SL 2.0 ile başlayıp sonra benim çok önem verdiğim IIS 7'ye geçeceğiz. IIS 7.0 üzerinde ASP.NET ve PHP tarafında çok güzel yenilikler var. Sonrasında her zamanki gibi bir sohbet panelimiz olacak. Son olarak LINQ ile ilk günümüzü kapatacağız. İkinci gün WPF ile başlayarak ADO.NET Data Services konusunu inceleyeceğiz. Heyecanlandığınızın farkındayım :) Sonrasında IE 8.0 ile gelen yazılımcı ve tasarımcıları ilgilendiren yenilikler ve yeni uygulama platformlarını inceleyerek WCF dünyasına da atılarak iki günü sonlandıracağız.

Aktiviteye üniversite girişinde güvenlik sorunları yaşamamak adına kayıt olmanız şart.

Kayıt adresi: http://daron.yondem.com/kayit/

Emeklerinden dolayı buradan sevgili MSP, Çağrı Erdoğan'a çok teşekkür ediyorum.

Aktiviteyi duyururken geçen sefer güzel bir başarı elde etmiştik. Bu sefer de yine aşağıdaki bannerı kullanabilirsiniz. Banner'a tıklandığında link olarak da kayıt adresini verebilirsiniz.

INETA Capital Hit Banner

Hepinizi bekliyorum ;)

Friday, September 26, 2008 8:59:59 AM (GTB Standard Time, UTC+02:00)  #    Comments [23]   .NET Framework 3.5 | ASP.NET 3.5 | Expression Blend | IIS 7.0 | LINQ | Seminer | Silverlight 2.0 | Visual Basic 2008 | Visual Studio 2008 | WCF | WPF  | 
 Thursday, September 25, 2008

Silverlight'ın RTW (Release To Web) olmasına yani tam olarak son haline gelmesine çok az kaldı. Bugün RC0 (Release Candidate) sürümü sadece yazılım geliştiricilerin kullanımına sunuldu. Yani eğer yazılım geliştirme işlemi yapmıyorsunuz bu RC'yi bilgisayarınıza yüklemenize gerek yok. Aslına bakılırsa bu durum daha önceki Beta sürümleri için de kullanıcılar tarafında geçerli bir davranıştı :)

Nasıl başlarız?

İster sıfırdan Silverlight dünyasına giriyor olun ister uzun süredir Beta 1 ve Beta 2 ile uğraşıyor olun tabi ki artık yeni yüklemelere ihtiyacınız olacak. Eğer sanal makine kullanıyorduysanız sıfır bir makine işinizi görecektir, aksi halde tüm eski Beta 2 ve Beta 1 yüklemelerinin tamamen bilgisayarınızdan silmeniz gerekiyor.

Makinenizde ön şart olarak Visual Studio ve üzerine de .NET Framework 3.5 ve Visual Studio 2008 SP1 yüklü olması gerekiyor. Sonrasında ilk olarak Expression Blend tarafındaki sorunları çözmemiz gerek. Hatırlarsanız Silverlight 2.0 Beta 2 için Expression Blend 2.5 Preview sürümleri yayınlanmıştı. Microsoft bu yoldan vaz geçti ve Silverlight 2.0 development için Blend 2.5 değil 2.0 üzerinden devam edilmesini uygun gördü. Tabi Expression Blend 2.0 şu an satışta olan bir ürün olunca yeni eklenecek Silverlight 2.0 özelliklerini de bir Service Pack ile çözmeye karar verdiler. Sonuç olarak eğer Silverlight 2.0 RC0 ile uygulama hazırlayacaksanız bilgisayarınıza Expression Blend 2 yüklü olması ve üzerine de uygun Service Pack 1'i yüklemeniz gerekiyor.

Expression Blend 2 SP1 RC Preview (17.8MB)

Blend ile olan işimizi hallettikten sonra Visual Studio 2008 için de gereken eklentileri yüklememiz gerek. Silverlight Tool paketi yenilenmiş hali ile karşımızda.

Microsoft® Silverlight™ Tools for Visual Studio 2008 SP1 (RC0) (71,6MB)

Yeni neler var?

Yenilikler ve düzeltmeler gerçekten heyecan verici. Kişisel olarak da SL ekibine raporladığımız çoğu sorunun giderilmiş olması süper.

  • Sonunda Combobox kontrolümüz var!
  • PasswordBox geldi. Çakallıklar yapıp ayrı password fontları bağlamaya artık gerek kalmayacak :)
  • ProgressBar kontrolü karşınızda. Zor değildi aslında, hemen yapıyorduk elle ama olsun ;)
  • generic.xaml içerisinde tüm varsayılan stiller yenilendi.
  • MessageBox.Show geldi, oh be! JavaScript çağırmaktan bıkmıştık gerçekten.
  • HTML Object taglarındaki Type bilgisi son halini aldı ve x-silverlight-2-b2 'den x-silverlight-2'e değişti.
  • Embedded Font'lar artık Resource olarak Assembly içerisinde bulunmak zorunda. XAP içinde font saklama sistemi artık desteklenmiyor. Güvenlik...
  • System.Windows.Controls.Extended.dll değişti, artık System.Windows.Controls.dll var.

Bunlar dışında daha bir sürü değişiklik var :) Önemli olduğunu düşündüklerimi zaman içerisinde blogdan sizlerle detaylı olarak paylaşacağım. Şimdi taze Silverlight 2.0 RC0 kurduğum sanak makineme dönmem gerekiyor ;)

Hepinize kolay gelsin.

Thursday, September 25, 2008 5:27:07 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, September 23, 2008

Başlık olarak “Reflection” yazdıktan sonra ardına sayfalarca açıklama ve örnek konulabilir. Hatta bu konuda ayrı bir kitap bile yazılabilir. Reflection’ın çok farklı kullanımlar var. Özetleyerek hızlı bir şekilde tanımlamak istersek aslında Reflection bize hakkında bilgi sahibi olmadığınız programatik nesnelerle ilgili çalışma zamanında (run-time) bilgi alabilmemize olanak tanıyan bir metottur. Peki böyle bir şeye neden ihtiyacımız olsun? En basit örnek gerçek zamanlı olarak uygulamalara farklı DLL dosyalarının bağlandığı durumları gösterebiliriz. Böyle bir durumda kaynak konumdaki sınıflar veya metotlar ile ilgili herhangi bir bilgi bulunmaz. Söz konusu bu bilgilerin program çalışırken elde edilerek kullanılması gerekir. Gelin ilk olarak Reflection’ın yapısını ve sistemini tanımak adına tek bir uygulama içerisinde nasıl kullanılabileceğimize göz atalım. Örnek uygulamamızda aşağıdaki şekli ile tanımlanmış bir Urun sınıfı kullanacağız.

[VB]

Public Class Urun

 

    Private PAdi As String

    Public Property Adi() As String

        Get

            Return PAdi

        End Get

        Set(ByVal value As String)

            PAdi = value

        End Set

    End Property

 

    Sub New()

 

    End Sub

 

    Sub New(ByVal adi As String)

        Me.Adi = adi

    End Sub

 

    Function Uyari() As String

        Return "Ürünün adı: " & Me.Adi

    End Function

End Class

[C#]

public class Urun

{

 

    private string PAdi;

    public string Adi

    {

        get { return PAdi; }

        set { PAdi = value; }

    }

 

    public Urun()

    {

 

    }

 

    public Urun(string adi)

    {

        this.Adi = adi;

    }

 

    public string Uyari()

    {

        return "Ürünün adı: " + this.Adi;

    }

}

Uygulamamız içerisinde iki adet düğme yer alacak ve kullanacağımız Windows penceresinde global olarak tanımlanmış bir de Object tipinde değişkenimiz bulunacak.

[VB]

Dim BirUrun As Object   

[C#]

object BirUrun;

Uygulama içerisindeki düğmelerden birine basıldığında global BirUrun değişkenimiz yeni bir Urun değişkenine dönüştürülecek.

[VB]

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    BirUrun = New Urun

End Sub

[C#]

    private void button1_Click_1(object sender, EventArgs e)

    {

        BirUrun = new Urun();

    }

Programımız içerisinde diğer düğmeye basıldığında BirUrun adındaki değişkenimizin Adi özelliğini değiştirerek Uyari adındaki metodunu kullanmak istiyoruz. Fakat Visual Studio içerisinde maalesef ki BirUrun adındaki değişkenle beraber Urun tipine ait Intellisense desteği gelmeyecektir. Aslında bu durumun haklı bir nedeni var. İkinci düğmeye basıldığında BirUrun adındaki değişkenin tipininin Object mi yoksa Urun mü olacağı belli değil. İşte tam da istediğimiz ortamı yaratmış olduk. Kullanacağımız nesnenin tipi belirsiz ve biz ona ait bazı özellikleri kullanmak istiyoruz. Bu durumda ilk olarak ikinci düğmeye basıldığında gerçekten BirUrun değişkeninin tipi Urun mü yoksa değil mi sorusunu kontrol etmemiz lazım.

[VB]

       If TypeOf (BirUrun) Is Urun Then

 

        End If

[C#]

        if ((BirUrun) is Urun)

        {

 

        }

Buraya kadar her şey çok kolay. Bundan sonra eğer IF kontrollerimize olumlu sonuç dönüyorsa ilk olarak gidip nesnenin Adi özelliğini bulmamız ve ona bir değer aktarmamız gerekiyor.

[VB]

BirUrun.GetType.GetProperty("Adi").SetValue(BirUrun, "Daron", Nothing)

[C#]

BirUrun.GetType().GetProperty("Adi").SetValue(BirUrun, "Daron", null);   

Yukarıdaki kod ile elimizdeki nesnenin tipini bilmeden onun Adi adındaki özelliğini (property) yakalayarak değerini Daron olarak değiştiriyoruz. Kodumuzu detaylı olarak adım adım bakacak olursak ilk aşamada nesnenin tipini GetType ile alıyoruz. Sonrasında ise tipini yakaladığımız nesnenin GetProperty ile Adi adındaki özelliğini alarak SetValue ile söz konusu özelliğin değerini değiştiriyoruz. SetValue metodu toplam üç parametre alıyor; bunlardan ilki değer değişikliği yapılacak nesnenin kendisi, ikincisi yeni atanacak olan değer, üçüncüsü ise eğer değiştirilecek olan özellik (property) indeksli ise söz konusu indeks değeri. Bizim örneğimizde indeksli bir özellik olmadığı için bu parametreyi boş geçiyoruz.

Değer atamamızı tamamladığımıza göre bu sefer de sıra geldi BirUrun değişkenimize ait Uyari metodunu çalıştırmaya. Metodumuz bize bir String döndürecek biz de onu doğrudan bir mesaj kutusu ile kullanıcıya göstereceğiz.

[VB]

BirUrun.GetType.InvokeMember("Uyari", Reflection.BindingFlags.InvokeMethod, Nothing, BirUrun, Nothing)

[C#]

BirUrun.GetType().InvokeMember("Uyari", System.Reflection.BindingFlags.InvokeMethod, null, BirUrun, null).ToString();

Reflection kullanarak türü bilinmeyen bir nesnenin bir metodunu çalıştırmak için InvokeMember metodundan faydalanmamız gerekiyor. InvokeMember aslında çok geniş kullanımı olan bir metod, biz şimdilik sadece bir çeşit kullanımına değineceğiz. Örneğimizde InvokeMember bir metod çalıştıracağı için ilk parametresinde çalıştırılacak olan metodun adını ikincisinde BindingFlags.InvokeMethod ile bir Metod çalıştırılacağını belirtiyoruz. Üçüncü parametre bizim şimdilik kullanım alanımız dışında kalan Binding’lerle ilgili, aynı şekilde beşinci parametre de boş bırakılarak geçilecek. Dördüncü parametrede ise hedef nesnemiz olan BirUrun değişkenimizi atayacağız. Böylece metodumuzu da çalıştırmış olduk.

Dinamik DLL Kullanımı

Kabaca Reflection’ın nasıl kullanılabildiğine dair bir örnek yaptıktan sonra artık sıra geldi harici bir DLL dosyasının çalışma anında programımıza ekleyerek içerisindeki yapıları kullanmaya. Bu çeşit bir işlevselliği özellikle gerçek zamanlı DLL derlemesi ile birleştirdiğinizde çok farklı bir dünyaya kapı açmış olacaksınız. Hedef olarak kullanacağımız DLL dosyasını aşağıdaki kodlardan yaratacağız.

[VB]

Public Class Deneme

    Function Metin() As String

        Return "Çalışıyor"

    End Function

End Class

[C#]

    public class Deneme

    {

        string Metin()

        {

            return "Çalışıyor";

        }

Yarattığımız DLL dosyasını uygulamamız ile aynı konuma yerleştirdikten sonra aşağıdaki kod ile DLL’imizi kullanmaya başlayabiliyoruz.

[VB]

Dim BirAssembly As Reflection.Assembly = Reflection.Assembly.LoadFrom("ornek2.dll")

[C#]

System.Reflection.Assembly BirAssembly = System.Reflection.Assembly.LoadFrom("ornek2.dll");

Artık yukarıda tanımladığımız Assembly üzerinden Reflection kullanarak ilerleyebiliriz. İlk olarak Deneme adında sınıfımızdan bir instance almamız gerekecek. Bunun için Deneme tipini bulmamız lazım.

[VB / C#]

BirAssembly.GetModule("Ornek2.dll").GetType("Deneme")

Assembly üzerinden modülümüzü yakalıyor sonra da Deneme adındaki tipinizi buluyoruz. Tabi tipi bulmak yeterli değil, söz konusu tipte bir değişken yaratmamız gerekiyor. Activator sınıfını kullanarak bu tip üzerinden bir instance yaratarak Sinif adında bir değişkene aktaracağız.

[VB]

Dim Sinif = Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"))   

[C#]

object Sinif = Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"));

Yarattığımız sınıfın maalesef özellikleri otomatik olarak gelmeyecek. O nedenle Metin adındaki metodumuzu da elle bularak çalıştırmak zorundayız.

[VB]

BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, Nothing)

[C#]

BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, null)

Yine Assembly üzerinden yola çıkarak bu sefer daha da ileri gidiyoruz. Deneme sınıfımızı bulduktan sonra içerisinde Metin adındaki metodumuzu buluyor ve doğrudan Invoke ile söz konusu metodu çalıştırıyoruz. Invoke metodu bizden iki parametre istiyor; bunlardan ilki ana sınıfın kendisi. Bir önceki adımda yakaladığımız sınıfı buraya parametre olarak aktarıyoruz. Diğeri ise bizim kullanmayacağımız Binding parametresi.

Metin metodumuz çalıştırıldığında geriye bir String değişkeni döndürüyor. Bu değişkeni de bir mesaj kutusu ile kullanıcıya göstermek istersek uygulamamızın tam kodunun aşağıdaki şekilde sonlanması gerekiyor.

[VB]

Public Class Form2

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim BirAssembly As Reflection.Assembly = Reflection.Assembly.LoadFrom("ornek2.dll")

 

        Dim Sinif = Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"))

        MsgBox(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, Nothing))

    End Sub

End Class

[C#]

namespace CSReflection

{

    public partial class Form2 : Form

    {

        public Form2()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            System.Reflection.Assembly BirAssembly = System.Reflection.Assembly.LoadFrom("ornek2.dll");

 

            object Sinif = Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme"));

            MessageBox.Show(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invoke(Sinif, null).ToString());

        }

    }

}

Böylece harici bir DLL dosyasını yükleyerek istediğimiz metodu dinamik olarak kullanabildik. Farklı durumlarda isterseniz bir DLL içerisinde tüm metod, sınıf ve özelliklerin listelerini alabilir hatta bunları LINQ sorguları ile tarayabilirsiniz.

[VB]

Dim Metodlar = From Gelenler In BirAssembly.GetModule("Ornek2.dll").GetTypes Where Gelenler.GetMethod("Metin") IsNot Nothing

[C#]

var Metodlar = from Gelenler in BirAssembly.GetModule("Ornek2.dll").GetTypes() where Gelenler.GetMethod("Metin") != null select Gelenler;

Örneğin yukarıdaki LINQ sorgumuz ile harici DLL dosyası içerisinde Metin adında metodu olan tüm sınıfların bir listesini alıyoruz.

Hepinize kolay gelsin.

Tuesday, September 23, 2008 6:51:06 PM (GTB Standard Time, UTC+02:00)  #    Comments [8]   .NET Framework 3.0 | .NET Framework 3.5 | ASP.NET | ASP.NET 3.5 | LINQ | Silverlight 2.0 | Visual Basic 2005 | Visual Basic 2008 | Visual Studio 2005 | Visual Studio 2008 | WCF | WF | WPF  | 
 Sunday, September 21, 2008

Bir uygulama düşünün kendini programlayabilen. Konumuz “Star Trek” veya “Geleceğe Dönüş” değil. Emin olun gerçek dünyadan ve yapılabileceklerden bahsediyorum. Uygulamalarınızın dış sistemlerle ciddi bir bağlantı içerisinde olduğu durumlarda bazen kendi içlerinde dış sistemlere uygun kodlar üreterek kullanmaları gerekebilir. Bunu bazen uygulamaların kendi içlerindeki yapay zeka ile yapabilecekleri gibi bazen ise başka bir dış kaynaktan aldıkları yeni parametrelerden yola çıkarak kendi kodlarında değişiklik yapabilirler. Eğer bunların hiçbiri size gerçekçi gelmiyorsa başka bir seçenek olarak da harici uygulamaların kullanabileceği DLL dosyaları yaratacak bir uygulama yazmak istediğinizde yapmanız gerekenlerden bahsedebiliriz. Aslında her ikisi de aynı kapıya çıkıyor.

Bize dinamik olarak uygulamalar tarafından kullanılabilecek DLL dosyaları yaratacak bir kod lazım. Kullanacağımız nesnelerin çoğunun bulunduğu esas namespace System.CodeDom.Compiler olacak. Bunun haricinde C# veya VB için ayrı ayrı uygun namespace’leri kullanmamız gerek. Eğer VB kodu derleyecekseniz VB sınıflarını C# kodu derleyecekseniz tabi ki C# sınıflarını kullanmalısınız. Çapraz işlem yaparak C# kodunuz ile VB kodundan DLL üretme şansınız da var. Biz örneklerimizde C# ile C#’dan derleme, VB kodu ile de VB’den derleme yapacağız.

[VB]

Dim KodUretici As New Microsoft.VisualBasic.VBCodeProvider

Dim Derleyici As System.CodeDom.Compiler.CodeCompiler = KodUretici.CreateCompiler()

 

Dim Referanslarim As String() = {"System.dll"}

Dim AssemblyAdi As String = "Ornek.dll"

[C#]

Microsoft.CSharp.CSharpCodeProvider KodUretici = new Microsoft.CSharp.CSharpCodeProvider();

System.CodeDom.Compiler.ICodeCompiler Derleyici = KodUretici.CreateCompiler();

 

String[] Referanslarim =  {"System.dll"};

String AssemblyAdi= "Ornek.dll";

Kodumuzun başlangıcında ilk olarak birer CodeProvider nesnesi yaratıyoruz. Elimizdeki hazır kodu derleyecek olan nesneler olarak bu sınıflar VB ve C# için farklılaşıyor. CodeProvider’lar üzerinden birer de derleyici nesnesi aldıktan sonra sıra geliyor derleyeceğimiz kodun referanslarına karar vermeye. Referansları DLL isimleri ile bir String dizisine aktarmanız şart. Windows uygulamalarında en azından System.dll’in web uygulamalarında da System.Web.dll’in referans alınmış olması gerekiyor. Son olarak üreteceğimiz DLL dosyasının adını da başka bir değişkene aktararak yolumuza devam edelim.

[VB]

Dim DerlemeParametreleri As New System.CodeDom.Compiler.CompilerParameters(Referanslarim, AssemblyAdi)

DerlemeParametreleri.GenerateExecutable = True

DerlemeParametreleri.GenerateInMemory = False

[C#]

System.CodeDom.Compiler.CompilerParameters DerlemeParametreleri = new System.CodeDom.Compiler.CompilerParameters(Referanslarim, AssemblyAdi);

DerlemeParametreleri.GenerateExecutable = false;

 DerlemeParametreleri.GenerateInMemory = false;

Derleme işlemini yaparken yapmamız gereken ayarlar var. Bu ayarları derleyicimize bir CompilerParameters nesnesi olarak aktaracağız. DerlemeParametreleri değişkenimizi yaratırken referanslarımızı ve DLL adını aktardıktan sonra özel olarak GenerateExecutable özelliğini false olarak ayarlıyoruz. Böylece derleyicimiz bize tek başına çalışabilir bir dosya yaratmaktansa bir DLL dosyası yaratacak. Bir sonraki adımda da GenerateInMemory özelliğini false yaparak yaratılacak dosyanın uygulamamız ile aynı konuma, diske yazdırılmasını sağlıyoruz. Aksi halde yaratılan Assembly sadece hafızada tutulacak ve diske yazılmayacaktır. Sıra geldi dinamik olarak derlemeyeceğimiz kodu bir değişkene aktarmaya.

[VB]

Dim Kodum As String = <Kod>Public Class Deneme

    Function Metin() As String

        Return "Çalışıyor"

    End Function

End Class</Kod>.Value

[C#]

System.IO.StreamReader Okuyucu = new System.IO.StreamReader("Class1.cs");

string Kodum = Okuyucu.ReadToEnd();

Okuyucu.Close();

Bu noktada VB ile C# arasında farklı işlemler yaptım. VB’de doğrudan yaratacağım kodu uygulamanın içerisine gömerken C#’da derleyeceğim C# kodunu harici bir Class1.cs dosyasından çektim. Siz kendi uygulamalarınızda ister bu kodları farklı dosyalardan çekin ister metin işlemleri ile dinamik kod yaratın. İhtiyaçlarınıza göre uygun çözümü üretmek tamamen size kalmış. Önemli olan tek nokta aslında bu kodlarda hiçbir hatanın olmaması gerektiği, aksi halde derleme işlemi yapılamayacaktır.

[VB]

Dim Sonuc As System.CodeDom.Compiler.CompilerResults = KodUretici.CompileAssemblyFromSource(DerlemeParametreleri, Kodum)

[C#]

System.CodeDom.Compiler.CompilerResults Sonuc = KodUretici.CompileAssemblyFromSource(DerlemeParametreleri, Kodum);

Tüm ayarlarımız tamamlandığında göre doğrudan CodeProvider nesnemizin CompileAssemblyFromSource metodunu kullanarak derleme işlemini başlatabiliriz. Tabi bu esnada daha önce hazırlamış olduğumuz DerlemeParametrelerini de metoda parametre olarak aktarıyoruz. Derleme işlemimizi baştan sona tamamlayan kodumuzu bir bütün olarak inceleyelim.

[VB]

Dim KodUretici As New Microsoft.VisualBasic.VBCodeProvider

Dim Derleyici As System.CodeDom.Compiler.CodeCompiler = KodUretici.CreateCompiler()

 

Dim Referanslarim As String() = {"System.dll"}

Dim AssemblyAdi As String = "Ornek.dll"

 

Dim DerlemeParametreleri As New System.CodeDom.Compiler.CompilerParameters(Referanslarim, AssemblyAdi)

        DerlemeParametreleri.GenerateExecutable = True

        DerlemeParametreleri.GenerateInMemory = False

 

Dim Kodum As String = <Kod>Public Class Deneme

    Function Metin() As String

        Return "Çalışıyor"

    End Function

End Class</Kod>.Value

 

Dim Sonuc As System.CodeDom.Compiler.CompilerResults = KodUretici.CompileAssemblyFromSource(DerlemeParametreleri, Kodum)

[C#]

Microsoft.CSharp.CSharpCodeProvider KodUretici = new Microsoft.CSharp.CSharpCodeProvider();

System.CodeDom.Compiler.ICodeCompiler Derleyici = KodUretici.CreateCompiler();

 

String[] Referanslarim =  {"System.dll"};

String AssemblyAdi= "Ornek.dll";

 

System.CodeDom.Compiler.CompilerParameters DerlemeParametreleri = new System.CodeDom.Compiler.CompilerParameters(Referanslarim, AssemblyAdi);

DerlemeParametreleri.GenerateExecutable = false;

DerlemeParametreleri.GenerateInMemory = false;

 

System.IO.StreamReader Okuyucu = new System.IO.StreamReader("Class1.cs");

string Kodum = Okuyucu.ReadToEnd();

Okuyucu.Close();

 

System.CodeDom.Compiler.CompilerResults Sonuc = KodUretici.CompileAssemblyFromSource(DerlemeParametreleri, Kodum);

Dinamik olarak DLL dosyası derlemek işte bu kadar kolay. Dinamik kod yaratma araçları son dönemde çok popüler. Veritabanına bağlanarak veritabanındaki nesneleri algılayıp uygun “Veri Katmanı” kodunu dinamik olarak oluşturan hazır uygulamalar olduğu gibi bazı durumlarda özel kodlar yazmak da gerekebiliyor. Böyle bir durumda artık siz de uygulamalarınıza farklı kaynaklardaki şartlara uygun kodu dinamik olarak üretebilir ve bir DLL olarak farklı uygulamalara aktarabileceğiniz gibi kendi uygulamalarınızda da kullanabilirsiniz. Yarattığınız DLL dosyasını hemen uygulamanızda kullanmak isterseniz bu sefer dinamik olarak Assembly kullanımını ve Reflection konusuna eğilmenizde fayda var.

Hepinize kolay gelsin.

Sunday, September 21, 2008 7:04:21 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   .NET Framework 3.0 | .NET Framework 3.5 | ASP.NET | ASP.NET 3.5 | Silverlight 2.0 | Visual Basic 2005 | Visual Basic 2008 | Visual Studio 2005 | Visual Studio 2008 | WCF | WPF  | 
 Friday, September 19, 2008

İster VB olsun ister C#, ister web ister Windows uygulaması olsun yazdığımız tüm kodların derlenerek (Compile) bir EXE veya DLL haline dönüştürüldüğünü biliyoruz. Aslında .NET içerisinde yapılan işlem sizin yazdığınız herhangi bir .NET dilindeki kodun MSIL (Microsoft Intermediate Language)’a çevrilmesidir. İşte tam bu noktada akla gelen ilk soru; acaba bu çeviri işleminin tersini yapmak mümkün mü? Yani elimizdeki DLL veya EXE dosyasından yola çıkarak VB veya C# kodumuzu geri alabilir miyiz? Cevap: Evet.

Şu andan itibaren yapacaklarımız hedef olarak kullanacağınız uygulamanın lisans sözleşmesine göre yeri geldiğinde suç teşkil edebilir. O nedenle sizi özellikle uyarmak istiyorum. Çoğu zaman De-Compile işlemleri yaparkenki amacımız yazdığımız kodun nasıl derleyici tarafında MSIL’e çevrildiğini incelemek veya kaynak kodunu kaybettiğimiz ve bize ait olan bir uygulamanın kodlarına ulaşmak olacaktır. Diğer yandan lisans sözleşmesi ile aykırı düşmediği sürece farklı uygulamaları da De-Compile ederek arka planda farklı işlemlerin nasıl yapıldığını inceleme şansınız da olabilir.

.NET tarafına geçtiğimizde herhangi bir DLL veya EXE’nin aslında MSIL kodları içerdiğinden bahsetmiştik. Tabi ki bu MSIL kodları doğrudan bilgisayarlar tarafından çalıştırılabilir kodlar değiller. O nedenle içerisinde MSIL bulunan bir .NET yapısının çalışabilmesi için hedef makinede .NET Framework’ün yüklü olması gerekiyor. .NET Framework içerisindeki CLR (Common Language Runtime) bizim MSIL kodumuzu makine diline çevirerek çalışmasını sağlayacaktır. Kabaca baktığımızda De-Compile yolunda bizim ilk olarak elimizdeki DLL veya EXE içerisinden MSIL kodunu alarak çıkarmamız gerekecek. Bunun için doğrudan .NET Framework SDK paketi ile beraber gelen MSIL DisAssembler (ILDASM) uygulamasını kullanabiliriz.

IL DASM Kullanımı

Bilgisayarınıza .NET Framework SDK paketini kurduktan sonra doğrudan “Başlat” menüsünden ulaşabileceğiniz ILDASM programını Visual Studio yükleme konumu içerisinde SDK klasörü altında da bulabilirsiniz. Programı açtıktan sonra “File / Open” menüsünden istediğiniz bir .NET DLL veya EXE dosyasını açma şansınız olacaktır.Deneme amaçlı olarak gelin mini bir Windows uygulaması yazalım ve ILDASM ile açarak alacağımız sonucu görelim. Uygulamamız içerisinde birer TextBox, Button ve Label bulunacak. Basit bir şekilde düğmeye basıldığında TextBox içerisindeki değeri Label içerisine aktaracağız.

[VB]

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Label1.Text = TextBox1.Text

    End Sub

End Class

[C#]

namespace WindowsFormsApplication1

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            label1.Text = textBox1.Text;

        }

    }

}

Yukarıda yazdığımız kodlar ile oluşturduğumuz uygulamayı ILDASM ile açarak sonucu inceleyelim. Uygulamanın ilk açılan penceresinde bizim EXE’ye ait tüm sınıflar ve namespace’ler gözüküyor olacaktır. Eğer herhangi bir nesnenin tanımı veya metodu ile ilgili MSIL kodunu görmek isterseniz doğrudan çift tıklayarak yeni bir pencerede kodların açılmasını sağlayabilirsiniz.

ILDASM içerisinde EXE’mizin MSIL kodları açıkça gözüküyor
ILDASM içerisinde EXE’mizin MSIL kodları açıkça gözüküyor

Hazırladığımız örnek uygulamanın Button_Click durumundaki MSIL kodunu bulduğumuzda aşağıdaki sonuç ile karşılaşıyoruz.

[MSIL]

.method private instance void  Button1_Click(object sender,

                                            class [mscorlib]System.EventArgs e) cil managed

{

  // Code size       23 (0x17)

  .maxstack  8

  IL_0000:  ldarg.0

  IL_0001:  callvirt   instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication1.Form1::get_Label1()

  IL_0006:  ldarg.0

  IL_0007:  callvirt   instance class [System.Windows.Forms]System.Windows.Forms.TextBox WindowsApplication1.Form1::get_TextBox1()

  IL_000c:  callvirt   instance string [System.Windows.Forms]System.Windows.Forms.TextBox::get_Text()

  IL_0011:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)

  IL_0016:  ret

} // end of method Form1::Button1_Click

Yukarıdaki MSIL kodu normal şartlarda CLR tarafından makine koduna çevrilerek hedef ortamda çalıştırılıyor. Artık MSIL kodumuzu aldığımıza göre bu kodu VB veya C# koduna çevirmemiz lazım. Tabi bu iş o kadar kolay değil ve tek tek elle yapılabilecek bir iş de değil. O nedenle bu sefer de farklı bir araç kullanacağız.

Reflector iş başında

Lutz Roeder tarafından yazılmış bir program olarak Reflector’ı http://www.red-gate.com/products/reflector/ adresinden bilgisayarınıza indirebilirsiniz. Program aslında bir önceki adımda anlattığım MSIL çözme işlemini de kendi içinde yapabiliyor. Bununla kalmayıp çözdüğü MSIL kodunu istediğiniz .NET diline de çevirebiliyor.

Programı çalıştırdıktan sonra “File / Open” menüsünden istediğiniz bir EXE veya DLL dosyasını seçebilirsiniz. Uygulamanın ana penceresindeki sınıf listesine hemen seçtiğiniz program da gelecektir.

Reflector ile kaynak kodunu görebiliyoruz.
Reflector ile kaynak kodunu görebiliyoruz.

Ufak bir gezinti ile istediğiniz sınıfın veya metodun koduna doğrudan ulaşabilirsiniz. Reflector arayüzündeki “Programlama Dili” seçeneğinde VB, C#, Delphi ve IL seçenekleri bulunuyor. Bir önceki bölümde hazırladığımız uygulamamızı açarak Button.Click durumundaki kodu farklı dillerde Reflector ile alıp inceleyelim.

[VB]

Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)

    Me.Label1.Text = Me.TextBox1.Text

End Sub

[C#]

private void Button1_Click(object sender, EventArgs e)

{

    this.Label1.Text = this.TextBox1.Text;

}

Yazdığımız kodlar ile Reflector’ın bize verdiği kodlar tam olarak aynı değil. Bu durum zaten çok normal. Çünkü MSIL koduna çeviri esnasında aslında çoğu şey değişiyor. Örneğin tanımladığımız değişkenlerin bize özel olan isimlendirmeleri yok oluyor veya bizim kullandığımız bazı kısa metotlar uzun şekilleri ile yazılabiliyor. Hatta özellikle VB içerisindeki casting kolaylıkları Compile esnasında farklı değişikliklere neden olabiliyor. Bu durumda De-Compile ile aldığımız kod da yazdığımız koddan biraz farklı oluyor. Yine de elimizde çalışır durumda bir kod olduğuna kesin gözü ile bakabiliriz.

Nasıl engelleriz? Obfuscation!

Herhalde çoğunuz “tüm kodlarımız gözler önünde” endişesi içerisindesiniz. Aslında durum gerçekten de öyle. Tabi bu durumun birçok faydası var. Kişisel olarak itiraf etmek gerekirse farklı yazılımları De-Compile ederek çok şey öğrendiğimi söyleyebilirim. Bir defasında da kendi ürettiğimiz bir yazılımı De-Compile etmemiz gerekmişti, gerçekten hayat kurtarmıştı. Peki bunu nasıl engelleyebiliriz? İlk olarak şunu açıkça belirtiyim, herhangi bir .NET uygulamasından MSIL kodunun alınmasını engellemenin hiçbir yolu yok. Yapabileceğimiz tek şey MSIL kodunun okunabilirliliğini azaltmak için işlevsel olarak aynı işi gören fakat daha karışık bir MSIL kodu yaratmak. Bu işlem obfuscation olarak adlandırılıyor.

Obfuscation ile ilgili sektörde çok sayıda ücretli yazılım bulabilirsiniz. Biz bunlardan Xenocode'aait Postbuild 2008 adındaki ticari yazılımı kullanarak obfuscation ile neler yapabildiğimize bakacağız. XenoCode’u ilk açtığımızda karşımıza hemen bir uygulama listesi geliyor. Bu listeye bir önceki adımda kendi hazırladığımız EXE dosyasını ekleyerek uygulamanın üst menüsünden “Protect” tabına geçiyoruz. Burada sadece Windows’da çalışacak EXE dosyalarına uygulanabilecek özel bir koruma yöntemi olan “Surpress ILDASM” seçeneğinin işaretini kaldırmamız gerek. Bu seçenek DLL’lere zaten uygulanamayacaktır. Ekranın sağ tarafında korumak istediğimiz sınıfların ve metodların bir listesini işaretleyebiliyoruz. Tüm ayarları tamamladıktan sonra uygulamanın sağ altındaki “XenoCode Application” düğmesine basıyoruz.

Obfuscation işlemi için yollardayız
Obfuscation işlemi için yollardayız

Obfuscation işlemini tamamladıktan sonra sıra geldi testlerimizi yapmaya. İlk olarak uygulamamızı ILDASM ile açarak bakalım MSIL kodumuz ne hale gelmiş.

[MSIL]

.method private instance void  x44d0c0526a414989(object xe0292b9ed559da7d,

                                                class [mscorlib]System.EventArgs xfbf34718e704c6bc) cil managed

{

  // Code size       23 (0x17)

  .maxstack  8

  IL_0000:  ldarg.0

  IL_0001:  callvirt   instance class [System.Windows.Forms]System.Windows.Forms.Label WindowsApplication1.xaa4f033827d75b4d::get_x029e304eb4c44750()

  IL_0006:  ldarg.0

  IL_0007:  callvirt   instance class [System.Windows.Forms]System.Windows.Forms.TextBox WindowsApplication1.xaa4f033827d75b4d::get_x77691a2cfb8f8048()

  IL_000c:  callvirt   instance string [System.Windows.Forms]System.Windows.Forms.TextBox::get_Text()

  IL_0011:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Label::set_Text(string)

  IL_0016:  ret

} // end of method xaa4f033827d75b4d::x44d0c0526a414989

Gördüğünüz gibi aslında çok büyük bir değişiklik yok. Sadece sınıfların ve metodların isimleri değiştirilerek karışık isimler verilmiş. Aynı uygulamayı Reflector ile açtığımızda ise aşağıdaki kodları elde ediyoruz.

[VB]

Private Sub x44d0c0526a414989(ByVal xe0292b9ed559da7d As Object, ByVal xfbf34718e704c6bc As EventArgs)

    Me.x029e304eb4c44750.Text = Me.x77691a2cfb8f8048.Text

End Sub

[C#]

private void x44d0c0526a414989(object xe0292b9ed559da7d, EventArgs xfbf34718e704c6bc)

{

    this.x029e304eb4c44750.Text = this.x77691a2cfb8f8048.Text;

}

Kodlar epey okunurluluğunu kaybetmiş durumda. Bizim örneğimizde sadece tek bir satır kod bulunduğu için neyin ne olduğunu anlamak çok zor olmuyor. Fakat binlerde satırdan oluşan uygulamaların kodlarından anlaşılabilir bir sonuç çıkarmak neredeyse imkânsız olacaktır.

Hepinize kolay gelsin.

Friday, September 19, 2008 6:27:11 PM (GTB Standard Time, UTC+02:00)  #    Comments [11]   .NET Framework 3.0 | .NET Framework 3.5 | ASP.NET | ASP.NET 3.5 | Silverlight 2.0 | Visual Basic 2005 | Visual Basic 2008 | Visual Studio 2005 | Visual Studio 2008  | 
 Monday, September 08, 2008

Son zamanlarda özellikle yurt dışından yola çıkan ve Adobe'ci arkadaşlarımızın :) güzelce saptırdıkları bir haber geziyor etrafta. Buyurun örneğin aşağıdaki yazıyı bir okuyun;

http://www.mmistanbul.com/haber/title/nbc-online-futbol-yayini-icin-silverlight-yerine-adobe-flash-platformunu-secti

Şimdi yazıdaki hatalara gelelim :) NFL (National Football League) hiçbir zaman yayınlarını Silverlight ile yapacağını duyurmadı. Bahsi geçen duyuruyu yapan NBC (National Broadcasting Compan)'dir ve sözü geçen duyuru Olimpiyatların yayını ile ilgiliydi. 2008 Olimpiyatlarının USA içerisindeki yayın hakkına sahip olan NBC Silverlight 2.0 kullanmaya karar verdi ve tüm olimpiyatların yayınları Silverlight 2.0 ile yapıldı. Yani ortada bir üründen vazgeçme gibi bir durum yok :)

Gelelim haberde bahsi geçen Sunday Night Football yayınlarına; bu yayınlar NFL ve NBC Sports tarafından ortaklaşa olarak yapılıyor ve yayınların yapılması için kullanılacak teknolojinin seçiminde yetkili taraf ise NFL. NFL'in kararı ise Flash'tan yana olmuş.

Tüm bu detayları bilmeden, ilgilenmeden "Silverlight yerine Flash'a geçildi" gibi abuk bir sonuç çıkarmaya çalışmak çok yanlış. Olimpiyatların yayını ile Sunday Night Football'un yayınını aynı yayınmış gibi kabul edip :) (eh işlerine öyle geliyor) "İşte değiştirdiler, vazgeçtiler" nidaları gerçekten komik. İlgilenenler Adobe'nin basın açıklamasını okusun bakalım Olimpiyatlardan bahsedilen bir cümle var mı :)

Aslında Flash'ın veya Flash severler ve sosyal toplulukların böyle fake girişimlere ve spot haberlere ihtiyaçları olduğunu düşünmüyordum. Flash'ın güçlü olduğu yanlar var ve sektörde tabi ki yeri var. Ama herhalde Silverlight artık iyice korkutmaya başladı ki haberlerde saptırmalar ortaya çıkıyor.

Bu arada yeni bir haber daha veriyim :) Silverlight'ın sonraki sürümlerinde H.264 MPEG 4 ve AAC desteği geleceği yapılan duyurular arasında. Flash'a kıyasla bu kadar yeni bir teknoloji olarak SL'in aldığı yol özellikle yol/zaman :) adına gerçekten muhteşem, işte bu yüzden Microsoft'u seviyorum.

Sağlıcakla kalın ;)

Monday, September 08, 2008 8:32:53 AM (GTB Standard Time, UTC+02:00)  #    Comments [7]   Silverlight 2.0  | 
 Friday, September 05, 2008

PC Magazine LogoPC Magazine Eylül sayısından başlayarak artık PC Magazine'de Yazılım Editörlüğü görevini de yapıyor olacağım. Silverlight 2.0 yazılarım devam ediyor ve daha birçok projem var.

Eylül sayısında SL 2.0'ın TCP/IP soket programlama kısmına değindim. Ayrıca dergide ileride bloglardan duyuracağımız bir aktivitenin ipuçlarını da verdik :) Sürpriz! :)

Friday, September 05, 2008 1:22:15 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Tuesday, September 02, 2008

INETA Summer Hit'deki Silverlight 2.0 seminerime ait video kaydını aşağıdan izleyebilirsiniz. Daha önceki Silverlight 1.0 seminer kaydının epey izlendiğini bana gelen maillerden biliyorum. Seminer kayıtları ile ilgili sinsi projemin bitmesine az kaldı :)

Tuesday, September 02, 2008 3:38:19 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, August 28, 2008

Bugün Microsoft Türkiye organizasyonundaki Gelişim Atölyesi'nde WPF ve Silverlight anlattım. Toplam 5 adet 45 dakikalık oturum yetmedi de yetmedi :)

Gelişim Atölyesi'nden bir kare...
Gelişim Atölyesi'nden bir kare...
(Soldan sağa; MS S2B Program Yöneticisi Burak Sarıca, MS Technology Marketing Manager Nuri Çankaya, MSP Murat Duman ve ben :))

Oturum boyunca bilgisayarıma takılı bir mikrofondan sesimi de ekleyerek bilgisayarımdaki ekran görüntüsünü kaydettim. Böylece oturumda anlattığım her şeyi sizlerle de paylaşma şansım olacak. Maalesef oturumun Silverlight tarafında Virtual PC kullanınca ekran kaydetme esnasında bazı sorunlar oldu ve sadece WPF kısmını kaydedebildim. Çok yakında tüm video kayıtlarını sizlerle paylaşacağım :) 

Thursday, August 28, 2008 7:19:46 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0 | WPF  | 
 Wednesday, August 27, 2008

Silverlight 2.0'ın SharePoint ile kullanımı çok ilginç ve güzel sonuçlar doğurabiliyor. Bu çerçevede sizlerle daha önce Silverlight'ın SharePoint üzerinde kullanımı ile ilgili bir makalemi paylaşmıştım. Söz konusu makalede kullandığımız Silverlight BluePrint for SharePoint paketinin Silverlight 2.0 Beta 2 destekleyen sürümü yayınlandı.

http://www.codeplex.com/SL4SP

Yukarıdaki adresten yeni paketi bilgisayarınıza indirerek gerekli yüklemeleri yapabilirsiniz.

Hepinize kolay gelsin.

Wednesday, August 27, 2008 4:53:45 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   SharePoint | Silverlight 2.0  | 
 Monday, August 25, 2008

INETA Summer Hit etkinliği sonrası verdiğim bir söz vardı :) Tüm konuşmacıların sunumlarını benim blogdan sizlerle paylaşacağımı söylemiştim. O kadar geç kaldım ki sonunda artık "Nerede hocam?" gibi mailler almaya başladım :) Haklısınız. İşte hepsi aşağıda;

Silverlight Sunumu - 26082008_1.pptx (3,79 MB)
TFS Sunumu - 26082008_2.pptx (10,5 MB)
IE 8.0 Sunumu - 26082008_3.pptx (1,53 MB)
LINQ Sunumu - 26082008_4.pptx (660 KB)
Web 3.0 Sunumu - 26082008_5.xps (344 KB)

Monday, August 25, 2008 5:51:30 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   IE 8.0 | LINQ | Silverlight 2.0  | 
 Saturday, August 23, 2008

Silverlight 2.0 ile hazırlanmış ASP.NET sunucu kontrollerine adım adım yaklaştığımız bu günlerde "Charting" kontrolleri cephesinde Visifire adında bir paket ücretsiz olması ile beraber büyük olanaklar sağlıyor. Aşağıdaki adresi ziyaret ederek hemen kendi şablonlarınızı seçip verinizi de girerek size uygun Silverlight 2.0 Charting uygulamasının hazırlanmasını sağlayabilirsiniz.

http://www.visifire.com/silverlight_chart_designer.php

Uygulama hazırlandıktan sonra sitenin alt kısmında yer alan "View HTML" düğmesine basarak hazırladığınız grafiği stienize hangi kodlar ile yerleştirebileceğinizi görebilirsiniz. Eğer "Embed XML" işaretini kaldırırsanız uygulamanın harici bir XML dosyasından veri almasını da sağlayabilirsiniz. Normal şartlarda "Embed XML" işaretlenmediğinde site size aşağıdaki gibi bir JavaScript kodu verecektir.

    <script language="javascript" type="text/javascript">
        var vChart = new Visifire("Visifire.xap",500,300);
        vChart.setDataUri("Data.xml");
        vChart.render("VisifireChart");
    </script>

Bu kodun içerisinde "Data.XML" adresini rahatlıkla farklı bir Generic Handler'a bağlayarak dinamik veri bağlantısı yapabilirsiniz. Böylece site her açıldığında güncel XML ile Silverlight 2.0 grafiği ekrana gelecektir.

Visifire Chart'larının sitenizde çalışması için aşağıdaki adresten gerekli XAP dosyasını ve visifire.js adındaki harici JavaScript dosyasını indirerek sitenize kopyalamanız gerekiyor.

http://www.visifire.com/downloads/visifire_v1.1.1.zip

Aşağıdaki adresten oluşturabileceğiniz Chart çeşitlerinizi ve çalışan örneklerini de inceleyebilirsiniz.

http://www.visifire.com/silverlight_charts_gallery.php

Hepinize kolay gelsin.

Saturday, August 23, 2008 6:05:24 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Thursday, August 21, 2008

Bugün İzmir'de hosting sağlayıcılar ile bir bir eğitimimiz oldu. Benim için çok güzel bir fırsattı :) çünkü zaten hali hazırda Türkiye'deki hosting sağlayıcılar ile ilgili dertliyim. Şirket tarafında müşterilerimize sunduğumuz içerik yönetim sistemlerini müşterilerimiz hosting sağlayıcılardan aldıkları alanlara koyduklarına bir çok sorun ile karşılaşıyoruz. Bu sorunların detaylarına inerek eğitim boyunca ASP.NET hosting yaparken nelere dikkat edilmesi gerektiğine değindim.

Microsoft Hosting Çözümleri Eğitimi, İzmir
Microsoft Hosting Çözümleri Eğitimi, İzmir

Seminerlerde özellikle bana "ASP.NET 3.5 destekli hosting nasıl buluruz?" gibi sorular geliyor. Bu soruları ve arayışı doğrudan hosting firmalarındaki yetkililere iletme şansım oldu. İlginç bir şekilde sunucularında .NET Framework 3.5 kurulu olduğunu fakat sitelerinde hala 2.0 yazdığını söylediler :) Tabi en kısa zamanda bu hatayı düzeltecekler. Hatta birkaç gün içerisinde SP1 yüklü hostinglerimiz bile olacak Türkiye'de.

Bir diğer konu da tabi ki Silverlight'dı :) Silverlight'ın IIS tarafındaki Mime Type ayarlarından ve detaylarından bahsettik.

Eğitimde kullandığım sunumu aşağıdan indirebilirsiniz.

Hosting Çözümleri Eğitimi Sunumu - 21082008_1.pptx (206,66 KB)

Thursday, August 21, 2008 8:15:42 AM (GTB Standard Time, UTC+02:00)  #    Comments [12]   ASP.NET 3.5 | IIS 7.0 | Silverlight | Silverlight 2.0  | 
 Tuesday, August 19, 2008

Son iki gündür İzmir Microsoft Yaz Okulundaydım. Microsoft Yaz Okulu serisinin son durağı olan İzmir'de de Silverlight ve WPF konularına eğildik. İzmir ekibini :) İstanbul ve Ankara ile karşılaştırmak gerekirse sanırım İzmir'in havasından olsa gerek çok daha "fırlama" denilebilecek bir ekip vardı :) Beni bir çok kez dersi kaynatma konusunda kışkırtsalar da azimle iradeli bir şekilde görevimi sürdürdüm :)

İzmir Microsoft Yaz Okulu, Öğle Yemeği
İzmir Microsoft Yaz Okulu, Öğle Yemeği

Söz verdiğim gibi iki gün boyunca yaptığımız örnekleri kaynak kodları ile beraber sizlerle paylaşıyorum, aşağıdan tüm projeleri indirebilirsiniz.  

Örnek Uygulamalar - 19082008_1.rar (3,55 MB)

İstanbul, Ankara ve İzmir'den tüm yaz okulundaki öğrencilerime son olarak teşekkür etmek istiyorum. Hepsi de eminim ki önümüzdeki dönemde çok güzel projelere imza atacaklar.

Keep in touch ;)

Tuesday, August 19, 2008 11:03:19 AM (GTB Standard Time, UTC+02:00)  #    Comments [8]   Eğitimler | Silverlight 2.0 | WPF  | 
 Sunday, August 17, 2008

Bundan yaklaşık bir hafta kadar önce Adobe sponsorluğundaki RiaTalks etkinliğinde Silverlight anlatmıştım. Sizleri hem aktivite öncesi hem de sonrası blogdan bilgilendirmiştim. İşte o aktivitede yine ufak bir video çalışmamız oldu. Video konusundaki yardımlarından dolayı Murat Duman'a teşekkür ediyorum. İyi seyirler...

Sunday, August 17, 2008 11:14:48 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight | Silverlight 2.0  | 
 Friday, August 15, 2008

Silverlight'ın sunucu tarafındaki programlama dillerinden ve sunucu platformundan tamamen bağımsız olduğundan sürekli bahsediyoruz. Bu çerçevede daha önceki yazılarımdan birince PHP ile Silverlight 2.0 kullanımına değinmiştim. Bu yazımızda da Java ile Silverlight kullanımına değineceğiz.

Örneğimizde Java tarafından hazırladığımız bir web servisini Silverlight 2.0 tarafında Visual Studio içerisinden kullanacağız. Visual Studio ve .NET altyapısı ile rahatlıkla WSDL uyumlu web servislerini kullanabildiğimizi düşünürsek aynı standartlara uygun bir web servisinin Java ile hazırlanmış olması durumunda herhangi bir sorun yaşamayacağımıza kesin gözü ile bakabiliriz. İlk olarak Java tarafında aşağıdaki kodumuz ile basit bir web servisi hazırlayalım.

package com.daron.ws;

 

public class wsclass {

 

    public int topla(int x, int y)

    {

        return x+y;

    }

 

}

Yukarıdaki ufak kod ile aslında basit bir metod tanımlamış oluyoruz. Metodumuz aldığı iki integer parametreyi toplayıp geri döndürüyor. Bu parametreler ve metodun yapacağı işlemler sizin örneklerinizde çok daha farklı olabilir. Şu an için amacımız Silverlight tarafından Java'ya veri gönderip geriye sonuç alabiliyor olmak.

Eclipse üzerinden WSDL dosyasını da otomatik olarak yukarıdaki metod üzerinden yarattıktan sonra artık sıra geliyor bu servisi Silverlight tarafında kullanmaya. Silverlight 2.0 uygulamamızı yine Visual Studio içerisinde geliştireceğimiz için Java servisinin bulunduğu siteyi Visual Studio içerisinde de açmanız daha rahat bir çalışma ortamı yaratacaktır. Basit bir şekilde Visual Studio 2008 içerisinden "File / Open Web Site" diyerek Java ile hazırlanmış siteyi açabilirsiniz. Tabi Java dosyalarını sadece birer dosya olarak göreceksiniz, düzenleme şansınız olmayacak. Siteyi açtıktan sonra "File / Add / New Project" diyerek Silverlight projenizi sitenize ekleyebilirsiniz. Silverlight uygulamasını çalıştıracak olan örnek HTML dosyası otomatik olarak Java sitenize eklenecektir.

Web servisini referans alalım...

Web servisini referans olarak ekleyebilmeniz için tabi ki servisin çalışıyor olması gerek. Bunun için Eclipse üzerinden Tomcat'i kullanabilirsiniz. IIS yüklü bir makinede çalışıyorsanız 8080 gibi harici bir port vermeyi unutmayın. Web servisini tarayıcınızda çalıştırdıktan sonra adresini kopyalayarak Silverlight projenize sağ tıklayarak "Add Service Reference" diyerek referans ekleme işlemini tamamlayabilirsiniz.

Java web servisimizi referans olarak ekliyoruz.
Java web servisimizi referans olarak ekliyoruz.

Referans ekleme işlemi tamamlandığında artık Silverlight ile herhangi bir web servisini kullanır gibi Java web servisimizi de kullanabiliyoruz. Örneğimizi çalıştırabilmek için ilk olarak Silverlight ekranımıza iki metin kutusu ve bir de düğme yerleştirelim.

<UserControl x:Class="SilverlightApplication1.Page"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

      <TextBox Height="48.411" Margin="33.2830009460449,22.693000793457,115.582000732422,0" VerticalAlignment="Top" Text="TextBox" TextWrapping="Wrap" x:Name="Kutu1"/>

      <TextBox Height="48.95" Margin="33.2830009460449,75.1039962768555,115.582000732422,0" VerticalAlignment="Top" Text="TextBox" TextWrapping="Wrap" x:Name="Kutu2"/>

      <Button Height="52.95" HorizontalAlignment="Stretch" Margin="92.2839965820313,0,165.50700378418,88.1999969482422" VerticalAlignment="Bottom" Content="Button" x:Name="Dugme"/>

    </Grid>

</UserControl>

Her şey hazır olduğuna göre artık web servislerimizi kodumuz ile tanımlayıp kullanabiliriz.

[VB]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Dim Servisim As New ServiceReference1.wsclassClient

        AddHandler Servisim.toplaCompleted, AddressOf Servisim_toplaCompleted

        Servisim.toplaAsync(Kutu1.Text, Kutu2.Text)

    End Sub

 

    Private Sub Servisim_toplaCompleted(ByVal sender As Object, ByVal e As ServiceReference1.toplaCompletedEventArgs)

        Dugme.Content = e.Result

    End Sub

End Class

[C#]

namespace SilverlightApplication2

{

    public partial class Page : UserControl

    {

        ServiceReference1.wsclassClient Servisim = new SilverlightApplication2.ServiceReference1.wsclassClient();

 

        public Page()

        {

            InitializeComponent();

            this.Dugme.Click += new RoutedEventHandler(Dugme_Click);

            Servisim.toplaCompleted += new EventHandler<SilverlightApplication2.ServiceReference1.toplaCompletedEventArgs>(Servisim_toplaCompleted);

        }

 

        void Dugme_Click(object sender, RoutedEventArgs e)

        {

            Servisim.toplaAsync(int.Parse(Kutu1.Text), int.Parse(Kutu2.Text));

        }

 

        void Servisim_toplaCompleted(object sender, SilverlightApplication2.ServiceReference1.toplaCompletedEventArgs e)

        {

            Dugme.Content = e.Result.ToString();

        }

    }

}

Konumuz Silverlight ile web servisleri kullanımı olmadığı için yukarıdaki kodun detaylarına girmeyeceğim. Bu konuda detaylı bir yazıyı aşağıdaki adresten inceleyebilirsiniz.

http://daron.yondem.com/tr/PermaLink.aspx?guid=19fe09b2-2987-4369-a5d5-58e0641c8d6b

Kodları incelediğimizde yaptığımız şeyin aslında ASP.NET ile hazırlanmış bir web servisi kullanmaktan farklı olmadığını görüyoruz. Java ile yazılmış olan web servisimiz yine Silverlight tarafından asenkron olarak kullanılabiliyor.

Projenizi Visual Studio içerisinde Build ederek Silverlight XAP dosyasını oluşturduktan sonra siteyi Tomcat üzerinden çalıştırmak zorunda olduğunuzu unutmayın. Aksi halde web servisi çalışmayacağı için Silverlight hata verecektir.

Sonuç

Silverlight'ın güzelliklerinden faydalanmak için ASP.NET tarafında olmanız şart değil. İster Java ister PHP ister herhangi bir sunucu taraflı programlama dili kullanın Silverlight ile kullanıcı arayüzünüzü hazırlayabilirsiniz.

Java ile WSDL uyumlu web servisi hazırlayıp çalıştırabilme :) konusundaki yardımlarından dolayı sevgili Bilge Başaltun'a buradan çok teşekkür ediyorum.

Hepinize kolay gelsin.

Friday, August 15, 2008 1:12:04 PM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight 2.0  | 
 Wednesday, August 13, 2008

Son iki gündür Ankara'da Microsoft Yaz Okulu'nda Silverlight ve WPF konularını anlattım. Ankara, İstanbul ve İzmir'de yapılan yaz okullarındaki öğrencilerin arasındaki sinsi çekişme ortamı hoşuma gitmedi diyemem :) Örneğin Ankara'daki arkadaşlar İstanbul'daki arkadaşlarla ilgili "Haremlik ve Selamlık şeklinde oturuyorlarmış sanırım hocam" şeklinde yorumlarda bile bulundular :) Tabi şaka bir yana yaz okullarındaki bu gençlerin önümüzdeki yılda çok güzel işler yapacağından eminim. Hatta büyük ihtimal ile bazılarının adlarını sürekli duyuyor olacaksınız, şimdiden BlogEngineTR ekibine katılanlar bile var. Azimlerini takdir ediyorum.

Microsoft Yaz Okulu, Ankara
Microsoft Yaz Okulu, Ankara

Tüm eğitim ve seminerlerimde olduğu gibi yaz okulunda da tamamen spontane örneklerle ilerledim. Yaptığımız uygulamalarının toparlayabildiğim kadarının kaynak kodlarını aşağıdaki adresten indirebilirsiniz.

Örneklere ait kaynak kodları - 13082008_2.rar (5,77 MB)

Son olarak, "Hocam bu üniversiteye gelir misiniz?" "Şuraya gider misiniz?" gibi sorularla sıkça karşılaştığım için buradan cevap vermek istiyorum. "Şu ana kadar davet edilip de gitmediğim bir yer olmadı" :)

Hepinize kolay gelsin...

Wednesday, August 13, 2008 12:45:38 PM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight 2.0 | WPF  | 
 Tuesday, August 12, 2008

Visual Studio 2008 SP1 yüklemesi sonrası Silverlight 2 Beta 2 ile çalışanlar artık çalışamadıklarını görecekler :) Bu nedenle yeni bir yükleme paketi Microsoft tarafından hazırlandı. İlk olarak bilgisayarınızdan Silverlight 2 ile ilgili her şeyi silin ve sonrasında aşağıdaki adresten gerekli yüklemeyi bilgisayarınıza indirerek çalıştırın.

http://www.microsoft.com/downloads/details.aspx?FamilyId=50A9EC01-267B-4521-B7D7-C0DBA8866434&displaylang=en

Kolay gelsin ;)

Tuesday, August 12, 2008 7:57:57 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, August 09, 2008

Cuma ve cumartesi günlerimi riatalks.com aktivitesinde geçirdim. Benim de cuma akşam üstü bir Silverlight sunumum vardı. Her konuşmacıya 45 dakika ayrıldığı için benim açımdan epey sıkıntılı bir manzara oluştu. Hakkında hiç bir bilgi sahibi olunmayan bir teknoloji olarak Silverlight ile ilgili doğru manzarayı yaratacak bilgileri 45 dakikada aktarmak gerçekten çok zor. Yine de elimden geleni yaparak "Hiç yoktan iyidir" söylemleri ile sunumumu bitirdim.

riatalks.com'da Silverlight oturumu.
riatalks.com'da Silverlight oturumu.

INETA Summer Hit'den hatırlayacağınız birkaç konuşmacımız da riatalks'da söz alma şansına sahip oldu. Alışmışken riatalks için de bir video çekimi yaptık, özellikle Ali Rıza'ya performansından dolayı teşekkür etmem gerek. Video son haline geldiğinde sizinle paylaşacağım.

Saturday, August 09, 2008 9:45:34 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Tuesday, August 05, 2008

Son iki gündür Microsoft İstanbul ofislerinde Microsoft'un Yaz Okulu'nda Silverlight ve WPF anlattım. Yaz okulundaki gençler gerçekten muhteşem seçilmiş. Her biri birer cevher niteliğindeydi. Silverlight 2.0 Beta 2 ile çalıştığımız için tabi ki teknik açıdan epey sıkıntılı dakikalar da yaşadık üzerine benim sesimin kısıklığı da eklenince ideal bir ortam oluştuğunu söyleyemem fakat her iki dünyaya da güzel bir giriş yaptığımızı düşünüyorum.

Microsoft Yaz Okulu, İstanbul
Microsoft Yaz Okulu, İstanbul

Herkese tavsiye ettiğim üzere yaz okulundaki kardeşlerime de tavsiyem benim blogdaki "Kütüphane" bölümünden Silverlight ve WPF makaleleri incelemeleri.

Hepinize kolay gelsin, başarılar....

Tuesday, August 05, 2008 11:37:41 AM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0 | WPF  | 
 Monday, August 04, 2008

Bugün INETA Summer Hit 2008'in ikinci gününü de mutlu bir şekilde sonlandırdık. Yaz aylarında bir hafta sonu etkinliğinde 350 üstü katılımcıya sahip olmak benim için çok heyecan vericiydi. "Acaba gerçekten gerek var mı? Yoksa ben mi gaza geliyorum?" sorusunu artık kendi kendime sormama gerek kalmayacak sanırım. Tüm konuşmacılarımız adına bizi yalnız bırakmadığınız ve bilgi paylaşımından doğan sevinci yaşamamıza olanak tanıdığınız için çok teşekkür ediyorum.

INETA Summer Hit 2008
INETA Summer Hit 2008

Gelen maillerden cevaplarını beklediğiniz bazı sorular olduğunu bildiğim için birkaç noktaya değinmek istiyorum. Aktivitenin video kayıtlarını, tüm çekilen fotoğrafların tam çözünürlüklü halini, sunumları sizlerle paylaşacağız. Bu gibi içerikler için benim blogu takip etmenizi tavsiye edebilirim. Bahsettiğim içerikleri şu an hazırlıyoruz.

Aktiviteyle ilgili teşekkür etmem gereken bir ordu var; sevgili konuşmacılarımız Ali Rıza Babaoğlan, Ali Servet Eyüpoğlu, Eralp Erat, Kadir Çamoğlu ve Uğur Umutluoğlu'na buradan çok teşekkürler. Organizasyonda benim yardımıma koşan kardeşlerim Murat Duman, Yiğit Kıran, Görkem Güngör ve YTÜ Bilişim Kulübü'nden Oğuz Yılmaz, M. Zeki Ersen'e de ayrı ayrı teşekkürler.

Sunday, August 03, 2008 11:34:18 PM (GTB Standard Time, UTC+02:00)  #    Comments [8]   IE 8.0 | LINQ | Seminer | Silverlight 2.0  | 
 Friday, August 01, 2008

Silverlight 2.0 içerisinde MultiScaleImage ve DeepZoom konusunda daha önce detaylı bir makaleyi sizlerle paylaşmıştım. Makalede kullandığımız Deep Zoom Composer aracının yeni bir sürümü yayınlandı. Deep Zoom Composer'ın yeni sürümünü aşağıdaki adresten indirebilirsiniz.

http://www.microsoft.com/downloads/details.aspx?FamilyID=457b17b7-52bf-4bda-87a3-fa8a4673f8bf&DisplayLang=en

Live Labs Photo Zoom

Yeni sürümle beraber artık Deep Zoom Composer ile hazırladığınız uygulamaları MS Live Labs PhotoZoom çerçevesinde ücretsiz olarak internette yayınlayabiliyoruz. Her zamanki gibi yeni bir DeepZoom projesi yaratarak ilerledikten sonra son "Export" adımında "PhotoZoom Export" seçeneğini seçerseniz sizden LiveID bilgileriniz istenecektir. Eğer LiveID'niz ile PhotoZoom sistemine kayıt olmadıysanız hemen programın içerisindeki linkten siteye bağlanarak kayıt olabilirsiniz.

PhotoZoom Servisi ve Deep Zoom Composer
PhotoZoom Servisi ve Deep Zoom Composer

Kayıt işlemini tamamladıktan sonra doğrudan Deep Zoom Composer içerisinde LiveID'niz ile giriş yaparak çalışmanızı webe yükleyebilirsiniz. Yükleme esnasında sizden üzerinde çalıştığınız proje için bir albüm ismi ve kapak görseli seçmeniz istenecektir.

PhotoZoom yüklemesi...
PhotoZoom yüklemesi...

Tüm ayarları tamamladıktan sonra "Upload" düğmesine bastığınızda önce proje çıktısı yaratılacak sonra da PhotoZoom hesabınızda gerekli albüm yaratılarak içerisine Silverlight uygulaması yüklenecektir. Sonucu aşağıdaki adreste inceleyebilirsiniz.

http://photozoom.mslivelabs.com/album.aspx?alias=darony&album=1

Hepinize kolay gelsin.

Friday, August 01, 2008 9:12:05 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, July 31, 2008

PC Magazine LogoPC Magazine Ağustos sayısından başlayarak Silverlight 2.0 yazılarımla karşınızda olacağım. Haziran ayına kadar PC.NET tarafındaki teknik yazılarımla  beni takip edenler artık PC Magazine tarafından devam edebilirler :) Bu ay SL 2.0 dünyasına giriş yazısı ile başladık önümüzdeki aylarda detaylarla devam edeceğiz.

Bu arada PC Magazine'in twitter hesabından dergiyle ilgili gelişmeleri de takip edebilirsiniz, kurumsal anlamda twitter kullanımı için güzel bir örnek teşkil ediyor.

Thursday, July 31, 2008 1:01:58 AM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Wednesday, July 23, 2008

Silverlight 2.0 ile beraber gelen kontrollerden biri de MultiScaleImage kontrolü. Bu kontrolün yapabildikleri arasında gerçekten çok ilginç uygulamalar var. Genel itibari ile çok büyük boyutta resimlerin istemci tarafında bant genişliğinin en uygun performans ile kullılarak gösterilmesini sağladığını söyleyebiliriz. Örneğin elinizde çok yüksek çözünürlükte 2GB'lık bir fotoğraf var ve bu fotoğrafı istemci tarafında göstermek istiyorsunuz veya elinizde toplam 3GB'lık bir fotoğraf arşivi var ve bunu güzel bir Silverlight galerisi şeklinde kullanıcılarla paylaşmak istiyorsunuz. Fakat uygulamanın çalışırken doğal olarak tüm resimleri yüklememesi hatta sadece o an ekranda gözüken kısımları yüklemesi gerekiyor. Tüm bunları elle tek tek kodlayarak yapabiliriz fakat MultiScaleImage varken aslında herşey çok daha kolay ilerliyor.

Deep Zoom Composer

MultiScaleImage kontrolü içerisinde gösterilecek resimlerin farklı detaylarda gösterilebilmesi ve kullanıcı resme zoom yaptıkça yeni detayların yüklenerek ekranda gösterilebilmesi için arkaplanda resimlerin biraz detaylı bir yapıda hazırlanmış olması gerekiyor. Bu işlemleri otomatik olarak yapabilecek bir uygulama olan Deep Zoom Composer'ı aşağıdaki adresten bilgisayarınıza indirip kurabilirsiniz.

http://www.microsoft.com/downloads/details.aspx?FamilyID=457b17b7-52bf-4bda-87a3-fa8a4673f8bf&DisplayLang=en

Yüklemeyi yapıp yeni bir DeepZoom projesi yarattığınızda programın arayüzündeki "Add Image" düğmesi ile projeye istediğiniz kadar resim ekleyebilirsiniz. Eklediğiniz bu resimleri "Compose" sekmesinde sahneye sürükleyerek istediğiniz şekilde resimleri iç içe veya üst üste koyabilirsiniz. Resimleri ufaltabilir veya büyütebilirsiniz. Unutmayın ki burada bir resmi diğerine göre çok ufak yerleştirseniz de kullanıcı birazdan hazırlayacağımız uygulamada zoom yaparak tüm detayları görebilecek. Yani bir insan resmi koyup gözünün içine de ufacık görünecek şekilde aslında 5MB'lık kocaman bir fotoğraf yerleştirebilirsiniz. Kullanıcı resmi ilk açtığında bu fotoğraf insanın gözünün içinde ufacık olduğu için tamamen yüklenmeyecek ve sadece gözüktüğü kadarı istemciye gönderilecektir. Oysa kullanıcı zoom yaparak gözün içine girip büyük fotoğrafı görmeye başladığında ise detaylar yüklenerek fotoğrafınız tüm çözünürlüğü ile net bir şekilde gözükecektir. DeepZoom Composer'ın kullanımı ile ilgili detaylı bilgiyi sevgili Turhal Temizer'in yazısından edinebilirsiniz.

DeepZoom Composer içerisinde fotoğraflarımız.
DeepZoom Composer içerisinde fotoğraflarımız.

Biz uygulamamızda yukarıdaki gibi fotoğrafları sahneye ekleyip sağ tuş ile gelen menüden de tüm fotoğrafları "Arrange to Grid" diyerek bir tablo içerisindeymiş gibi hizalatalım. Böylece tüm fotoğraflar yan yana ve alt alta sıralanacaktır. Daha önce de bahsettiğim gibi isterseniz fotoğrafları üst üste yerleştirme ve farklı tasarımlar yapma şansınız da var. Örneğin bir mekanın duvarındaki reklamı ayrı bir detaylı fotoğraf olarak koyabilirsiniz. Böylece kullanıcı mekan fotoğrafındaki duvarda yer alan reklama zoom yaptığında aslında daha detaylı farklı bir görsel yüklenmeye başlayacak ve normalde elde edilemeyen bir detay gösterimi yapılabilecektir.

Son olarak DeepZoom Composer içerisinde "Export" bölümüne geçerek artık fotoğraflarımızın gerekli çıktılarını almak istiyoruz. Export esnasında özellikle "Output Type" olarak "Export Images" seçeneğini işaretlemeyi unutmayın. Normalde DeepZoomComposer isterseniz size hazır bir Silverlight projesi de yaratabiliyor fakat bu yazımızda biz kendi uygulamamızı hazırlayacağımız için sadece fotoğrafların düzenlenerek gerekli arşivin oluşturulmasını istiyoruz.

DeepZoom Composer arşivimiz.
DeepZoom Composer arşivimiz.

Yukarıda da gördüğünüz üzere gerekli dosyalar bizim için hazırlanmış. Buradaki XML dosyalarını tek tek inceleyebilirsiniz. Aslında her bir dosya ayrı birer XML dosyasına yönlendiriyor bizi. Arşive eklediğimiz her resim için ayrıca birer XML dosyası yaratılıyor ve bu dosyalar içerisinde resimlerle ilgili konum bilgisi gibi detaylar yer alıyor. Ayrıca her resmimizin farklı boyutlarda kopyaları da klasörler içerisine kopyalanmış durumda. Hatta çok büyük resimler parçalara bölünerek ayrı ayrı dosyalar olarak da kaydedilmiş. MultiScaleImage kontrolünün de gücü zaten buradan geliyor. Kaynaktaki farklı boyuttaki ve parçalardaki fotoğrafları gerçek zamanlı olarak birleştirebiliyor ve otomatik olarak ekranda gözüken detaya uygun hedef dosyaları istemciye yüklüyor. Tüm geçiş efektlerini de tabi ki otomatik olarak yapıyor. Peki artık kaynak dosyalarımız hazır olduğuna göre uygulamamızı da hazırlamaya başlayalım.

Silverlight projemizi yaratalım...

Yeni bir Silverlight projesi yaratarak hemen içerisine bir MultiScaleImage kontrolü yerleştiriyoruz. Şimdilik tasarım anlamında farklı birşey yapmayacağız. Uygulamamızın XAML kodu aşağıdaki gibi basit bir şekilde sonlanıyor.

<UserControl x:Class="SilverlightApplication6.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="1024" Height="768">

    <Grid x:Name="LayoutRoot" Background="White">

        <MultiScaleImage x:Name="DeepZoom"/>

    </Grid>

</UserControl>

DeepZoom adını verdiğim MultiScaleImage kontrolümüzü programlamaya başlayacağız. İlk olarak yapmak istediğimiz işlemleri bir sıralayalım;

  • Fotoğraf arşivimizi kontrole yükleyeceğiz.
  • Fare ile fotoğraf arşivi içerisinde gezilebilmesini sağlayacağız
  • Farenin roller'ı ile zoom ve zoom out yapılabilmesini sağlayacağız
  • Artistik hareketler yapacağız

Listemizdeki tek tek yaparak ilerleyelim. İlk olarak fotoğraf arşivimizi doğrudan kontrolümüze bağlayalım.

[VB]

        DeepZoom.Source = New DeepZoomImageTileSource(New Uri("GeneratedImages/dzc_output.xml", UriKind.Relative))

[C#]

            DeepZoom.Source = new DeepZoomImageTileSource(new Uri("GeneratedImages/dzc_output.xml", UriKind.Relative));

Gördüğünüz üzere doğrudan DeepZoom kontrolümün Source özelliğini değiştiriyorum ve yarattığımız yeni bir DeepZoomImageTileSource nesnesini kendisine atıyoruz. Bu esnada bir önceki adımda DeepZoom Composer'ın bizim için yarattığı arşivden dzc_output.xml dosyasını kaynak olarak gösteriyoruz. DeepZoom Composer'ın yarattığı GeneratedImages klasörünü doğru olarak çalışabilmesi için XAP dosyanız ile aynı konuma kopyalamanız gerekecektir.

Fotoğraf arşivini gezelim.

Sıra geldi fare ile fotoğrafların arasındaki gezintimize başlamaya. Aslında yapacağımız işlem klasik bir Sürükle&Bırak işleminden farklı değil. Fakat bu sefer sürükleyip bıraktıracağımız şey aslında MultiScaleImage kontrolünün ViewPortOrigin'i. Yani bizim bu arşive MultiScaleImage aracılığı ile bakış noktamızı değiştreceğiz.

[VB]

    Dim Tasiniyor = False

    Dim FareKonum As Point

    Dim DeepZoomOrigin As Point

[C#]

        bool Tasiniyor = false;

        Point FareKonum;

        Point DeepZoomOrigin;

Sürükle ve bırak işlemi öncesinde ihtiyacımız olacak global değişkenlerimizi yukarıdaki gibi yaratalım. Sonrasında toplam üç farklı event için kod yazmamız gerekiyor. MouseLeftButtonDown, MouseMove ve MouseLeftButtonUp durumlarında sürükleme işlemini başlatıp durdurmaya karar vereceğiz.

[VB]

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        Tasiniyor = True

        FareKonum = e.GetPosition(Me)

        DeepZoomOrigin = DeepZoom.ViewportOrigin

    End Sub

[C#]

        void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = true;

            FareKonum = e.GetPosition(this);

            DeepZoomOrigin = DeepZoom.ViewportOrigin;

        }

Kullanıcı fare ile sahneye tıkladığında hemen taşınma işlemini başlattığımız için global Tasiniyor değişkenini True yapıyoruz. Böylece ileride yazacağımız MouseMove kodu durumdan haberdar olabilecek. Bir sonraki adımda farenin pozisyonunu ve sonrasında da DeepZoom kontrolünün o anki orijin noktasını kenara not alıyoruz. Bu bilgileri ileriki hesaplamalarımızda kullanacağız.

[VB]

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        If Tasiniyor Then

            Dim YeniDeepZoomOrigin As New Point

            YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth)

            YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth)

            DeepZoom.ViewportOrigin = YeniDeepZoomOrigin

        Else

            FareKonum = e.GetPosition(Me)

        End If

    End Sub

[C#]

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            if (Tasiniyor)

            {

                Point YeniDeepZoomOrigin = new Point();

                YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth);

                YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth);

                DeepZoom.ViewportOrigin = YeniDeepZoomOrigin;

            }

            else

            {

                FareKonum = e.GetPosition(this);

            }

        }

Sahnenin MouseMove durumunda ilk olarak bir taşıma işlemi olup olmadığını kontrol ediyoruz. Eğer taşıma işlemi yoksa FareKonum adındaki ve farenin mevcut konumunu saklayan değişkeni yeniliyoruz. Bunu yapmamızın nedeni ileride yazacağımız zoom işlemleri. Zoom işlemini yaparken farenin konumuna hep ihtiyacımız olacak. Burada sürekli güncel konumu FareKonum'a aktarmak gerekiyor. Eğer taşıma işlemi yapılıyorsa bu sefer de DeepZoom kontrolümüzün ViewPortOrigin'ini uygun şekilde ayarlamamız gerek. Bu amaçla kodumuzda yeni bir Point değişkeni tanımlayarak farenin mevcut konumu, eski konumu ve eski orijin noktası arasında koordinat hesaplamaları yaparak ilerliyoruz.

[VB]

    Private Sub Page_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonUp

        Tasiniyor = False

    End Sub

[C#]

        void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = false;

        }

Son olarak farenin sol tuşu bırakıldığında da taşıma işlemini sonlandırıyoruz. Böylece artık fotoğraf arşivi içerisinde kullanıcılar rahatlıkla gezebilecektir. Sıra geldi zoom meselesine.

Fare ile Zoom-In ve Zoom-Out

Fare ile zoom işlemleri için farenin roller'ını kullanacağız. Detaylar için Silverlight 2.0 içerisinde fare roller'ı kullanmayla ilgili buradaki makleyi inceleyebilirsiniz. İlk olarak DOM üzerinden gerekli eventları Silverlight ile yakalamamız gerekiyor.

[VB]

        System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

[C#]

            System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", FareTekerlekDondu);

FareTekerlekDondu eventı içerisinde aşağıda kodları yazmamız gerekiyor. Bu kodların çok detayına inmeyeceğiz çünkü bir önceki paragrafta bahsettiğim makalede zaten bu konu detayları ile inceleniyor. Bizim için bu kodda önemli olan kısım Zoom işleminin yapıldığı satırlar.

[VB]

    Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs)

        Dim DonMiktar As Integer = 0

        Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject

        'IE ve OPERA

        If Not Gelen.GetProperty("wheelDelta") Is Nothing Then

            'OPERA'da ters!

            If Not Gelen.GetProperty("opera") Is Nothing Then

                DonMiktar = -DonMiktar

            End If

            DonMiktar = Gelen.GetProperty("wheelDelta")

            'Mozilla ve Safari

        ElseIf Not Gelen.GetProperty("detail") Is Nothing Then

            DonMiktar = -Gelen.GetProperty("detail")

        End If

        If DonMiktar > 0 Then

            'Zoom yap

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y)

        Else

            'Uzaklaş

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y)

        End If

 

        If DonMiktar <> 0 Then

            e.PreventDefault()

            Gelen.SetProperty("returnValue", False)

        End If

    End Sub

[C#]

        private void FareTekerlekDondu(object sender, System.Windows.Browser.HtmlEventArgs e)

        {

            int DonMiktar = 0;

            System.Windows.Browser.ScriptObject Gelen = e.EventObject;

            //IE ve OPERA

            if ((Gelen.GetProperty("wheelDelta") != null)) {

                //OPERA'da ters!

                if ((Gelen.GetProperty("opera") != null)) {

                    DonMiktar = -DonMiktar;

                }

                DonMiktar = (int)Gelen.GetProperty("wheelDelta");

            }

            //Mozilla ve Safari

            else if ((Gelen.GetProperty("detail") != null)) {

                DonMiktar = -1 * (int)Gelen.GetProperty("detail");

            }

            if (DonMiktar > 0) {

                //Zoom yap

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

            else {

                //Uzaklaş

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

 

            if (DonMiktar != 0) {

                e.PreventDefault();

                Gelen.SetProperty("returnValue", false);

            }

        }

İlk olarak ElementToLogicalPoint metodu ile elimizdeki fare konumunun DeepZoom içerisinde tam olarak hangi koordinatlara geldiğini buluyoruz. Sonrasında da ZoomAboutLogicalPoint metodu ile zoom işlemini yapıyoruz. Zoom işlemi esnasında bizden üç parametre isteniyor, zoom miktarı, zoomlanacak noktanın X ve Y koordinatları. Böylece basit bir şekilde zoom işlemini de çözmüş olduk.

Atraksyon zamanı!

Yapılacaklar listemizde son bir öğe kaldı :) "Atraksyon". Şimdi biraz hareketli birşeyler yapalım. Eğer uygulamanın başından beridir benimle aynı adımları takip ediyorsunuz şu an DeepZoom kontrolü içerisinde yan yana ve alt alta sıralı onlarca fotoğrafınız var demektir. Peki bu fotoğrafları rastgele karıştıran bir düğme eklesek? Animasyonlarla fotoğraf düğmeye her basıldığında rastgele olarak yerlerini değiştirseler hoş olmaz mıydı? Belki de sizin istediğiniz farklı sıralara bile gelebilirler. Hemen kolları sıvayalım ve XAML'ımıza basit bir düğme ekleyelim.

<UserControl x:Class="SilverlightApplication6.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="1024" Height="768">

    <Grid x:Name="LayoutRoot" Background="White">

        <MultiScaleImage x:Name="DeepZoom"/>

        <Button Height="65" HorizontalAlignment="Right" Margin="0,0,30,19" VerticalAlignment="Bottom" Width="174" Content="Karistis" x:Name="Karistir"/>

    </Grid>

</UserControl>

Artık uygulamamızın XAML kodu yukarıdaki şekilde olacak. Düğmeye tıklandığında DeepZoom kontrolü içerisindeki tüm resimleri alarak sırasını karıştırmamız sonra da animasyonlarla yeni konumlara yerleştirmemiz gerek. İlk olarak resimleri karıştıracak olan kodu yazalım.

[VB]

        Dim FotoList As New List(Of MultiScaleSubImage)

        FotoList = DeepZoom.SubImages.ToList()

 

        For x As Integer = 0 To FotoList.Count - 1

            Dim Simdiki As MultiScaleSubImage = FotoList(x)

            FotoList.RemoveAt(x)

            FotoList.Insert(Rnd() * FotoList.Count, Simdiki)

        Next

[C#]

            List<MultiScaleSubImage> FotoList = new List<MultiScaleSubImage>();

            FotoList = DeepZoom.SubImages.ToList();

            Random Rastgele = new Random();

 

            for (int x = 0; x <= FotoList.Count - 1; x++)

            {

                MultiScaleSubImage Simdiki = FotoList[x];

                FotoList.RemoveAt(x);

                FotoList.Insert(Rastgele.Next(FotoList.Count), Simdiki);

            }

Bir DeepZoom içerisinde tüm resimler birer MultiScaleSubImage olarak bulunuyor. DeepZoom içerisinden tüm listeyi alıp içerisindeki her resmi listeden çıkartıp yeni bir rastgele indeks ile ekliyoruz. Böylece her seferinde sıralamayı rastgele değiştirmiş olduk. Sıra geldi bu sıralama ile resimleri sahnedeki yeni konumlarına birer animasyon ile göndermeye.

[VB]

        Dim KolonSayisi As Integer = 5

        Dim SatirSayisi As Integer = 5

        Dim ToplamEklenen As Integer = 0

 

        For Satir As Integer = 0 To SatirSayisi

            For Kolon As Integer = 0 To KolonSayisi

                If ToplamEklenen <> FotoList.Count Then

 

....................                

 

        ToplamEklenen += 1

                Else

        Exit Sub

                End If

            Next

        Next

[C#]

            int KolonSayisi = 5;

            int SatirSayisi = 5;

            int ToplamEklenen = 0;

 

            for (int Satir = 0; Satir <= SatirSayisi; Satir++)

            {

                for (int Kolon = 0; Kolon <= KolonSayisi; Kolon++)

                {

                    if (ToplamEklenen != FotoList.Count)

                    {

                       

..............................

 

                        ToplamEklenen += 1;

                    }

                    else

                    {

                        break;

                    }

                }

            }

Yukarıdaki kodumuzun orta kısmında birazdan her resmi farklı bir konuma animasyon ile gönderen kodu yazacağız. Fakat onun öncesinde kodun ana yapısını bir inceleyelim. Resimler yan yana ve alt alta sıralayacağımız için aslında bir Grid yapısında görsellik yaratmış olacağız. Kodumuzda KolonSayisi ve SatirSayisi değişkenleri kaç kolon ve satırlık bir sıralama yapılacağını belirliyor. ToplamEklenen değişkeni ise o ana kadar kaç fotoğraf eklediğimizi hafızada tutacak, böylece döngü içerisinde eklenen toplam fotoğraf sayısı elimizdeki fotoğraf sayısına ulaşırsa döngüden çıkacağız. Şimdi gelelim fotoğrafları yeni konumlarına gönderecek animasyonları yaratacak kodumuza.

[VB]

        Dim Foto As MultiScaleSubImage = FotoList(ToplamEklenen)

        Dim MevcutKonum As Point = Foto.ViewportOrigin

        Dim HedefKonum As Point = New Point(-1.14 * Kolon, -0.8 * Satir)

 

        'Animasyonu yaratalım

        Dim Anim As New Storyboard

        Dim NoktaAnim As New PointAnimationUsingKeyFrames

        Dim KeyFrame As New SplinePointKeyFrame

        KeyFrame.Value = HedefKonum

        KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1))

 

        Dim Ivme As New KeySpline

        Ivme.ControlPoint1 = New Point(0, 1)

        Ivme.ControlPoint2 = New Point(1, 1)

        KeyFrame.KeySpline = Ivme

        NoktaAnim.KeyFrames.Add(KeyFrame)

 

        Storyboard.SetTarget(NoktaAnim, Foto)

        Storyboard.SetTargetProperty(NoktaAnim, New PropertyPath("ViewportOrigin"))

 

        Anim.Children.Add(NoktaAnim)

 

        Anim.Begin()

[C#]

        MultiScaleSubImage Foto = FotoList[ToplamEklenen];

        Point MevcutKonum = Foto.ViewportOrigin;

        Point HedefKonum = new Point(-1.14 * Kolon, -0.8 * Satir);

 

        //Animasyonu yaratalım

        Storyboard Anim = new Storyboard();

        PointAnimationUsingKeyFrames NoktaAnim = new PointAnimationUsingKeyFrames();

        SplinePointKeyFrame KeyFrame = new SplinePointKeyFrame();

        KeyFrame.Value = HedefKonum;

        KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1));

 

        KeySpline Ivme = new KeySpline();

        Ivme.ControlPoint1 = new Point(0, 1);

        Ivme.ControlPoint2 = new Point(1, 1);

        KeyFrame.KeySpline = Ivme;

        NoktaAnim.KeyFrames.Add(KeyFrame);

 

        Storyboard.SetTarget(NoktaAnim, Foto);

        Storyboard.SetTargetProperty(NoktaAnim, new PropertyPath("ViewportOrigin"));

 

        Anim.Children.Add(NoktaAnim);

 

        Anim.Begin();

Kodumuz biraz uzun gibi gözükse de aslında özünde yaptığımız şey çok basit. İlk olarak döngümüzle oluşturduğumuz ToplamEklenen sayısı üzerinden o anki resmi FotoList içerisinden bir değişkene alıyoruz. MevcutKonum ve HedefKonum değişkenlerimiz ise fotoğrafın şu anki ve animasyonun sonundaki konumlarını saklıyor. Yeni konum hesaplarken kolon ve satır arası mesafelerle sayıları çarparak yeni konumu rahatlıkla hesaplayabiliyoruz. Artık hedeflediğimiz konum da belli olduğuna göre geriye kaldı eldeki fotoğrafı hedef konuma taşıyacak animasyonu yaratmak. Animasyon yapacağımız şey fotoğrafın ViewportOrigin özelliği ve bu özelliği Point tipinde. Bu nedenle PointAnimationUsingKeyFrame kullanarak hedef KeyFrame'i yaratacağız. Kodumuzda baktığımızda KeyFrame adındaki değişkenimiz 1 saniye sonra ViewPortOrigin değerini değiştiriyor. Ayrıca animasyonu ivme vermek için bir de KeySpline kullanıyoruz. Tüm bu nesnelerin birbirlerine eklenme şekilleri XAML'da bir StoryBoard yaratmaktan farklı değil. Kodumuzun en sonunda artık animasyonumuzu çalıştırmak için Begin metodunu çağırabiliriz.

Herşey bitti

Uygulamamız bitti. Artık istediğimiz kadar fotoğraflarımız arasında geçebilir, zoom yapabilir hatta resimleri bir düğme ile animasyonlu bir şekilde karıştırabiliriz. Uygulamanın tam kodunu aşağıda inceleyebilirsiniz.

[VB]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim Tasiniyor = False

    Dim FareKonum As Point

    Dim DeepZoomOrigin As Point

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        'Kaynağımızı bağlayalım

        DeepZoom.Source = New DeepZoomImageTileSource(New Uri("NewFolder1/dzc_output.xml", UriKind.Relative))

 

        'MouseWheel bağlantısı yapalım

        System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

        System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

    End Sub

 

    Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs)

        Dim DonMiktar As Integer = 0

        Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject

        'IE ve OPERA

        If Not Gelen.GetProperty("wheelDelta") Is Nothing Then

            'OPERA'da ters!

            If Not Gelen.GetProperty("opera") Is Nothing Then

                DonMiktar = -DonMiktar

            End If

            DonMiktar = Gelen.GetProperty("wheelDelta")

            'Mozilla ve Safari

        ElseIf Not Gelen.GetProperty("detail") Is Nothing Then

            DonMiktar = -Gelen.GetProperty("detail")

        End If

        If DonMiktar > 0 Then

            'Zoom yap

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y)

        Else

            'Uzaklaş

            Dim ZoomlananNokta As Point = DeepZoom.ElementToLogicalPoint(FareKonum)

            DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y)

        End If

 

        If DonMiktar <> 0 Then

            e.PreventDefault()

            Gelen.SetProperty("returnValue", False)

        End If

    End Sub

 

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        Tasiniyor = True

        FareKonum = e.GetPosition(Me)

        DeepZoomOrigin = DeepZoom.ViewportOrigin

    End Sub

 

    Private Sub Page_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonUp

        Tasiniyor = False

    End Sub

 

    Private Sub Page_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseMove

        If Tasiniyor Then

            Dim YeniDeepZoomOrigin As New Point

            YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth)

            YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth)

            DeepZoom.ViewportOrigin = YeniDeepZoomOrigin

        Else

            FareKonum = e.GetPosition(Me)

        End If

    End Sub

 

    Private Sub Karistir_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Karistir.Click

        Dim FotoList As New List(Of MultiScaleSubImage)

        FotoList = DeepZoom.SubImages.ToList()

 

        For x As Integer = 0 To FotoList.Count - 1

            Dim Simdiki As MultiScaleSubImage = FotoList(x)

            FotoList.RemoveAt(x)

            FotoList.Insert(Rnd() * FotoList.Count, Simdiki)

        Next

 

        Dim KolonSayisi As Integer = 5

        Dim SatirSayisi As Integer = 5

        Dim ToplamEklenen As Integer = 0

 

        For Satir As Integer = 0 To SatirSayisi

            For Kolon As Integer = 0 To KolonSayisi

                If ToplamEklenen <> FotoList.Count Then

                    Dim Foto As MultiScaleSubImage = FotoList(ToplamEklenen)

                    Dim MevcutKonum As Point = Foto.ViewportOrigin

                    Dim HedefKonum As Point = New Point(-1.14 * Kolon, -0.8 * Satir)

 

                    'Animasyonu yaratalım

                    Dim Anim As New Storyboard

                    Dim NoktaAnim As New PointAnimationUsingKeyFrames

                    Dim KeyFrame As New SplinePointKeyFrame

                    KeyFrame.Value = HedefKonum

                    KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1))

 

                    Dim Ivme As New KeySpline

                    Ivme.ControlPoint1 = New Point(0, 1)

                    Ivme.ControlPoint2 = New Point(1, 1)

                    KeyFrame.KeySpline = Ivme

                    NoktaAnim.KeyFrames.Add(KeyFrame)

 

                    Storyboard.SetTarget(NoktaAnim, Foto)

                    Storyboard.SetTargetProperty(NoktaAnim, New PropertyPath("ViewportOrigin"))

 

                    Anim.Children.Add(NoktaAnim)

 

                    Anim.Begin()

 

                    ToplamEklenen += 1

                Else

                    Exit Sub

                End If

            Next

        Next

    End Sub

End Class

[C#]

namespace SilverlightApplication1

{

    public partial class Page : UserControl

    {

        bool Tasiniyor = false;

        Point FareKonum;

        Point DeepZoomOrigin;

 

        public Page()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Page_Loaded);

            this.MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown);

            this.MouseLeftButtonUp += new MouseButtonEventHandler(Page_MouseLeftButtonUp);

            this.MouseMove += new MouseEventHandler(Page_MouseMove);

            this.Karistir.Click += new RoutedEventHandler(Karistir_Click);

        }

 

        void Karistir_Click(object sender, RoutedEventArgs e)

        {

            List<MultiScaleSubImage> FotoList = new List<MultiScaleSubImage>();

            FotoList = DeepZoom.SubImages.ToList();

            Random Rastgele = new Random();

 

            for (int x = 0; x <= FotoList.Count - 1; x++)

            {

                MultiScaleSubImage Simdiki = FotoList[x];

                FotoList.RemoveAt(x);

                FotoList.Insert(Rastgele.Next(FotoList.Count), Simdiki);

            }

 

            int KolonSayisi = 5;

            int SatirSayisi = 5;

            int ToplamEklenen = 0;

 

            for (int Satir = 0; Satir <= SatirSayisi; Satir++)

            {

                for (int Kolon = 0; Kolon <= KolonSayisi; Kolon++)

                {

                    if (ToplamEklenen != FotoList.Count)

                    {

                        MultiScaleSubImage Foto = FotoList[ToplamEklenen];

                        Point MevcutKonum = Foto.ViewportOrigin;

                        Point HedefKonum = new Point(-1.14 * Kolon, -0.8 * Satir);

 

                        //Animasyonu yaratalım

                        Storyboard Anim = new Storyboard();

                        PointAnimationUsingKeyFrames NoktaAnim = new PointAnimationUsingKeyFrames();

                        SplinePointKeyFrame KeyFrame = new SplinePointKeyFrame();

                        KeyFrame.Value = HedefKonum;

                        KeyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1));

 

                        KeySpline Ivme = new KeySpline();

                        Ivme.ControlPoint1 = new Point(0, 1);

                        Ivme.ControlPoint2 = new Point(1, 1);

                        KeyFrame.KeySpline = Ivme;

                        NoktaAnim.KeyFrames.Add(KeyFrame);

 

                        Storyboard.SetTarget(NoktaAnim, Foto);

                        Storyboard.SetTargetProperty(NoktaAnim, new PropertyPath("ViewportOrigin"));

 

                        Anim.Children.Add(NoktaAnim);

 

                        Anim.Begin();

 

                        ToplamEklenen += 1;

                    }

                    else

                    {

                        break;

                    }

                }

            }

 

        }

 

        void Page_MouseMove(object sender, MouseEventArgs e)

        {

            if (Tasiniyor)

            {

                Point YeniDeepZoomOrigin = new Point();

                YeniDeepZoomOrigin.X = DeepZoomOrigin.X - (((e.GetPosition(DeepZoom).X - FareKonum.X) / DeepZoom.ActualWidth) * DeepZoom.ViewportWidth);

                YeniDeepZoomOrigin.Y = DeepZoomOrigin.Y - (((e.GetPosition(DeepZoom).Y - FareKonum.Y) / DeepZoom.ActualHeight) * DeepZoom.ViewportWidth);

                DeepZoom.ViewportOrigin = YeniDeepZoomOrigin;

            }

            else

            {

                FareKonum = e.GetPosition(this);

            }

        }

 

        void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = false;

        }

 

        void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            Tasiniyor = true;

            FareKonum = e.GetPosition(this);

            DeepZoomOrigin = DeepZoom.ViewportOrigin;

        }

 

        void Page_Loaded(object sender, RoutedEventArgs e)

        {

            //Kaynağımızı bağlayalım

            DeepZoom.Source = new DeepZoomImageTileSource(new Uri("NewFolder1/dzc_output.xml", UriKind.Relative));

 

            //MouseWheel bağlantısı yapalım

            System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", FareTekerlekDondu);

            System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", FareTekerlekDondu);

        }

 

        private void FareTekerlekDondu(object sender, System.Windows.Browser.HtmlEventArgs e)

        {

            int DonMiktar = 0;

            System.Windows.Browser.ScriptObject Gelen = e.EventObject;

            //IE ve OPERA

            if ((Gelen.GetProperty("wheelDelta") != null)) {

                //OPERA'da ters!

                if ((Gelen.GetProperty("opera") != null)) {

                    DonMiktar = -DonMiktar;

                }

                DonMiktar = (int)Gelen.GetProperty("wheelDelta");

            }

            //Mozilla ve Safari

            else if ((Gelen.GetProperty("detail") != null)) {

                DonMiktar = -1 * (int)Gelen.GetProperty("detail");

            }

            if (DonMiktar > 0) {

                //Zoom yap

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(2, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

            else {

                //Uzaklaş

                Point ZoomlananNokta = DeepZoom.ElementToLogicalPoint(FareKonum);

                DeepZoom.ZoomAboutLogicalPoint(0.5, ZoomlananNokta.X, ZoomlananNokta.Y);

            }

 

            if (DonMiktar != 0) {

                e.PreventDefault();

                Gelen.SetProperty("returnValue", false);

            }

        }

    }

}

Hepinize kolay gelsin.

Wednesday, July 23, 2008 3:52:03 PM (GTB Standard Time, UTC+02:00)  #    Comments [6]   Silverlight 2.0  | 
 Saturday, July 19, 2008

Silverlight 2.0 Beta 2 içerisinde istemci makinedeki herhangi bir dosyaya ulaşmakla ilgili örneklerimizde Open File Dialog nesnesini detayları ile incelemiştik. Tam zıttı bir senaryoda da kullanıcıya sistemine kaydedebileceği bir dosya vermek isteyebiliriz. Bu gibi bir çözüm için maalesef Save File Dialog gibi bir kontrole sahip değiliz. O nedenle biraz farklı bir taktik uygulayarak kullanıcıya vermek istediğimiz dosyayı ilk olarak sunucuya göndererek kaydedeceğiz sonrasında da sunucudan dosyayı tekrar istemcinin alarak kaydedebilmesini sağlayacağız. Bu senaryo ilk bakışta çok saçma gibi gözükse de aslında dosya yaratma işlemini sunucu tarafında yaparsanız herhangi bir performans sorunu olmayacaktır. Gönül isterdi ki dosyayı tamamen istemcide Silverlight ile yaratarak kullanıcıya verebilelim. Fakat maalesef şimdilik en azından Beta 2 içerisinde böyle bir şansımız yok.

Peki herşeyi yaptık, dosyamızı Silverlight 2.0 Beta 2 ile yarattık, sunucuya bir web servisi aracılığı ile gönderdik ve kaydettik. Bundan sonrasında bu dosyayı Silverlight içerisinden istemcideki kullanıcıya nasıl vereceğiz. Kullanacağımız taktik aslında epeyce basit. Tüm tarayıcılarda kullanıcıyı dosya downloadu için dosyanın bulunduğu adrese yönlendirirseniz hemen "Download" penceresi açılacaktır. Kullanıcının içerisinde bulunduğu web sayfası hala görüntülenmeye devam edecektir. Yani aslında siz kullanıcıyı başka bir adrese yönlendiriyor olsanız da söz konusu adreste bir sayfa olmadığı için görüntüde bir değişiklik olmayacak ve hedef adresteki dosyanın download işlemi başlayacaktır. Biz de Silverlight tarafından bu taktikten faydalanacağız ve sayfanın adresini kullanıcının indirmesini istediği adres ile değiştirerek tarayıcının "Save File Dialog" açmasını sağlayacağız.

[VB]

        Dim Adres As Uri

        Uri.TryCreate(System.Windows.Browser.HtmlPage.Document.DocumentUri, New Uri("indir.zip", UriKind.Relative), Adres)

[C#]

            Uri Adres;

            Uri.TryCreate(System.Windows.Browser.HtmlPage.Document.DocumentUri, new Uri("teklialtyazi.zip", UriKind.Relative), out Adres);

İlk olarak kullanıcıyı yönlendirmek istediğimiz adresi oluşturmamız gerek. Bunun için Uri sınıfındaki TryCreate metodunu kullanacağız. Bu metod bizden bir base Uri ve Relative Uri alarak ikisini birleştirebiliyor. Base Url için içerisinde bulunduğumuz sayfanın adresini System.Windows.Browser.HtmlPage.Document.DocumentUri ile veriyoruz, relative Uri için yeni bir Uri değişkeni yaratıp download edilecek olan dosyanın adını veriyoruz. Son olarak da almak sonucun aktarılacağı yeni Uri değişkenimizi referans olarak aktarıyoruz.

[VB]

        CType(System.Windows.Browser.HtmlPage.Document.GetProperty("location"), System.Windows.Browser.ScriptObject).SetProperty("href", Adres.ToString)

[C#]

            ((System.Windows.Browser.ScriptObject)System.Windows.Browser.HtmlPage.Document.GetProperty("location")).SetProperty("href", Adres.ToString());

Simdi yapmamız gereken ise sayfanın adresini bir önceki adımda elde ettiğimiz adres ile değiştirmek. İlk olarak System.Windows.Browser.HtmlPage.Document.GetProperty ile sayfadaki dokümanın location özelliğini alıyoruz. Sonrasında da dokümanı bir ScriptObject'e cast ederek SetProperty ile href özelliğini değiştiriyoruz. Aslında bunu biraz JavaScript'teki document.location.href özelliğine benzetebilirsiniz. Artık kodumuzu çalıştırdığımızda Silverlight içerisinde herhangi bir düğmeye basıldığında otomatik olarak tarayıcının "Save File Dialog" penceresi açılacak ve kullanıcı istediği dosyayı Silverlight tarafından indirebilecek.

Hepinize kolay gelsin.

Saturday, July 19, 2008 1:58:35 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, July 17, 2008

İster PHP olsun ister farklı sunucu taraflı programlama dilleri olsun hepsi de "adı üzerinde" sunucu tarafında çalışıyorlar. Biz ise Silverlight tarafında tamamen istemcide çalışıyor. Bu çerçevede Silverlight'ın tamamen sunucudan bağımsız olduğunu düşünürsek aslında sunucu ile belirli standartları yakaladığımız sürece istediğimiz sunucu taraflı programlama altyapısı ile entegrasyon sağlayabiliriz. Bu standartlar WSDL kuralları çerçevesinde hazırlanmış bir web servisi olabileceği gibi bazen çok basit bir POST işlemi bile olabilir. Bu yazımda Silverlight 2.0 Beta 2 ile beraber sunucu tarafında bir PHP kodu kullanarak mail gönderim işlemi yapacağız. Hazırladığımız Silverlight 2.0 uygulamasının XAP dosyasını sunucuya atmamız uygulamamızın çalışması için yeterli olacaktır.

Önce PHP tarafını çözelim!

PHP tarafında çok detaya girmeyeceğiz. Yapacağımız şey basit bir şekilde sayfaya POST ile gönderilen değişkenleri alıp uygun bir mail mesaj stringi haline çevirdikten sonra mail olarak istediğimiz kullanıcıya göndermek olacak.

<?php

$senderName = $_POST['Gonderen'];

$senderEmail = $_POST['Email'];

$emailMessage = $_POST['Mesaj'];

$recipient = "alici@domain.com";

$subject = "Mesaj Konusu";

$headers = "From: $Email";

$message = "Kimden: $Gonderen\nEposta Adresi: $Email\n\n Mesaj: $Mesaj";

$message = stripslashes($message);

mail($recipient, $subject, $message, $headers)

?>

Örneğimize devam ederken ufak bir uyarıda bulunmam gerek. Kesinlikle yukarıdaki gibi bir PHP dosyasını sitenize bu haliyle bırakmayın. Şu an yukarıdaki dosyada ne post eden arkadaşın kimliği, ne sender'ın agent tipi hiçbir şey kontrol edilmiyor. Güvenlik açısından kesinlikle bu kodun geliştirilmesi gerek aksi halde önüne gelen buraya bilgileri POST ederek size milyonlarca mail yollayabilir.

Uygulamamızın tasarımını yapalım

Yine çok basit bir mailform hazırlayacağız. Blend 2.5 içerisinden Silverlight sayfamıza toplam üç adet TextBox ve bir de Button koyuyoruz. Site ziyaretçileri isimlerini, maillerini ve mesajlarını yazarak düğmeye basıp gize gönderebilecekler. Oluşturduğumuz uygulamanın XAML kodunu aşağıda inceleyebilirsiniz.

<UserControl x:Class="SilverlightApplication2.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBox Height="32" Margin="96,42,74,0" VerticalAlignment="Top" Text="Adınız" TextWrapping="Wrap" x:Name="txtAdi"/>

        <TextBox Height="29" Margin="96,88,74,0" VerticalAlignment="Top" Text="Mailiniz" TextWrapping="Wrap" x:Name="txtMaili"/>

        <TextBox Margin="96,132,74,81" Text="Mesajınız" TextWrapping="Wrap" x:Name="txtMesaji"/>

        <Button Height="32" HorizontalAlignment="Stretch" Margin="180,0,146,31" VerticalAlignment="Bottom" Content="Gönder" x:Name="btnGonder"/>

    </Grid>

</UserControl>

Kodlamaya geçelim

Uygulamamızın kod kısmında bir WebClient nesnesi kullanacağız. WebClient nesnemize sahnedeki tüm bilgileri bir String olarak vererek POST metodu ile bilgileri kendisine parametre olarak vereceğimiz bir adrese göndermesini isteyeceğiz.

[VB]

        Dim VeriGonder As New System.Net.WebClient

        VeriGonder.Headers(HttpRequestHeader.ContentType) = "application/x-www-form-urlencoded"

[C#]

            System.Net.WebClient VeriGonder = new System.Net.WebClient();

            VeriGonder.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";

VeriGonder adını verdiğimiz WebClient nesnemin hemen ContentType bilgisini ayarlamam gerekiyor. Bunun için WebClient'ın Headers dizisinden ContentType'ı bularak form-urlencoded olarak değiştiriyorum. Böylece birazdan URLEncode tekniği ile hazırladığımız verileri bu WebClient ile rahatlıkla sunucuya gönderebileceğiz.

[VB]

        Dim GonderilecekData As String = "Gonderen=" & Browser.HttpUtility.UrlEncode(txtAdi.Text) & "&"

        GonderilecekData &= "Email=" & Browser.HttpUtility.UrlEncode(txtMaili.Text) & "&"

        GonderilecekData &= "Mesaj=" & Browser.HttpUtility.UrlEncode(txtMesaji.Text)

[C#]

            string GonderilecekData = "Gonderen=" + System.Windows.Browser.HttpUtility.UrlEncode(txtAdi.Text) + "&";

            GonderilecekData += "Email=" + System.Windows.Browser.HttpUtility.UrlEncode(txtMaili.Text) + "&";

            GonderilecekData += "Mesaj=" + System.Windows.Browser.HttpUtility.UrlEncode(txtMesaji.Text);

Kodumuz içerisinde hemen göndereceğimiz verileri Key/Value çiftleri şeklinde birleştiriyoruz. Göndereceğimiz her verinin bir ismi ve tabi ki değeri olması gerekiyor. Aslında yaptığımız şey normalde URL üzerinden göndereceğimiz veriyi URLEncode ile aynı şekilde oluşturmak. Eğer göndereceğiniz verilerin sayısı çok ise performans açısından standart String işlemleri yerine bir StringBuilder kullanmanızı tavsiye ederim.

[VB]

        AddHandler VeriGonder.UploadStringCompleted, AddressOf VeriGonder_UploadStringCompleted

        VeriGonder.UploadStringAsync(New Uri("http://localhost:49424/SilverlightApplication2Web/mailgonder.php", UriKind.Absolute), "POST", GonderilecekData)

[C#]

            VeriGonder.UploadStringCompleted += VeriGonder_UploadStringCompleted;

            VeriGonder.UploadStringAsync(new Uri("http://localhost:49424/SilverlightApplication2Web/mailgonder.php", UriKind.Absolute), "POST", GonderilecekData);

Son olarak verimizi sunucuya göndermeden önce gönderme işlemi tamamlandığında çalıştırılmak üzere VeriGonder nesnemizin UploadStrintCompleted event'ına da bir event-handler bağlıyoruz. Artık verimizi sunucuya göndermeye hazır olduğumuza göre hemen adresini vererek POST metodu ile veriyi yolculayabiliriz.

[VB]

    Private Sub VeriGonder_UploadStringCompleted(ByVal sender As Object, ByVal e As System.Net.UploadStringCompletedEventArgs)

        btnGonder.Content = "Tamam"

    End Sub

[C#]

        private void VeriGonder_UploadStringCompleted(object sender, System.Net.UploadStringCompletedEventArgs e)

        {

            btnGonder.Content = "Tamam";

        }

Veri gönderme işlemi tamamlandığında ekrandaki kontrolleri kaldırıp bir teşekkür mesajı göstermek güzel olabilirdi. İşin o kısmını ben size bırakmış oliyim. Şimdilik UploadStringCompleted event'ında düğmeye "Tamam" yazdırarak örneğimizi çalıştırabiliriz.

@ İşaret Sorunu!

Ufak bir sorunumuz var. Silverlight 2.0 Beta 2 ile beraber gelen bu sorun ufak gibi gözükse de aslında epey önemli :) Yukarıdaki örneği çalıştırdığınızda göreceksiniz ki herhangi bir TextBox içerisinde @ işareti koyamıyorsunuz. Bunun basit bir nedeni var, aslında AltGr tuşu ile oluşturduğunuz hiçbir karakteri TextBox'lara yerleştiremeyeceksiniz. Neden mi? Bilmiyorum, bu bir bug. Silverlight 2.0'ın Beta 2 sonrasında sürümlerinde bu hata giderilecek. Şimdilik aşağıdaki gibi bir çözüm uygulayabiliriz.

[VB]

    Dim Oncekiler(1) As Integer

 

    Private Sub txtMaili_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Input.KeyEventArgs) Handles txtMaili.KeyDown

        If e.PlatformKeyCode = 81 Then

            If Oncekiler(0) = 17 And Oncekiler(1) = 18 Then

                txtMaili.Text &= "@"

                txtMaili.SelectionStart = txtMaili.Text.Length

            End If

        End If

        Oncekiler(0) = Oncekiler(1)

        Oncekiler(1) = e.PlatformKeyCode

    End Sub

[C#]

        int[] Oncekiler = new int[2];

 

        private void txtMaili_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)

        {

            if (e.PlatformKeyCode == 81)

            {

                if (Oncekiler[0] == 17 & Oncekiler[1] == 18)

                {

                    txtMaili.Text += "@";

                    txtMaili.SelectionStart = txtMaili.Text.Length;

                }

            }

            Oncekiler[0] = Oncekiler[1];

            Oncekiler[1] = e.PlatformKeyCode;

        }

İlk önce uygulamaya çalıştığımız mantığı kavrayalım. txtMail adındaki textBox içerisinde herhangi bir tuşa basıldığında yukarıdaki gibi KeyDown event'ı çalışacaktır. Bu event'a baktığımızda klavyede AltGr tuşuna basıldığında sırası ile iki tuşa basılmış gibi sistemin 17 ve sonrasonda da 18 numaralı PlatformAnahtarları'nı döndürdüğünü görebiliriz. Bu tuşların Macintosh dahil tüm sistemlerdeki PlatformKeyCode adında anahtarları vardır ve bu değerler sürekli aynıdır. Normalde biz @ işaretini koyabilmek için AltGr'ye bastıkdan sonra bir de Q harfine basarız. O zaman kontrol etmemiz gereken durum şu; Q harfine basıldıysa acaba bir önceki basılan tuş AltGr miydi? Eğer öğleyse bana bir @ işareti lazım. İşte kodumuz da bu kontrolü yapıyor. Sürekli olarak basılan son iki tuşu Oncekiler adındaki dizimizde saklıyor ve her tuşa basıldığında KeyDown içerisinde eğer Q harfine basılmış ise son basılan iki tuşun KeyCode'larının da 17 ve 18 olup olmadığını kontrol ediyoruz. Eğer durum buysa txtMaili TextBox'ı içerisine bir @ işareti ekleyip imleci metnin en sonuna gönderiyoruz.

Sonuç

Makalemizde kullandığımız teknik aslında web programcılığının en ilkel zamanlarından bu güne kadar gelen ve yapı taşı diyebileceğimiz POST metodunun ta kendisi. Bu çerçevede sunucu taraflı programlama sistemlerinin hepsi bu şekilde veri trafiğine açık olduğu için aynı teknikler ile Silverlight'ı sunucu tarafı ile rahatlıkla konuşturabilir ve ister sunucunun işletim sistemi olsun, ister kullanılan teknoloji olsun her konuda tam bağımsızlığın tadını çıkartabilirsiniz.

Hepinize kolay gelsin.

Thursday, July 17, 2008 1:43:17 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Saturday, July 12, 2008

Her programcının hayatında en az birkaç defe Office dosya formatları ile ilgilendiği projeler olmuştur. Bu durum ister yeni bir Word dosyası yaratmak olsun, ister bir Excel dosyasından veri çekmek olsun OpenXML öncesinde ciddi sıkıntılar çektiğimiz bir gerçek. En basit bir sebep olarak binary formatlı dokümanlar ile uğraşmak zorunda kaldığımızı söyleyebiliriz. Office 2007 ile beraber tanıştığımız ve sonlarına X harfleri eklenen dosya uzantıları aslında OpenXML'in geldiğinin bir işaretiydi. İyi ki geldin diyerek yavaş yavaş konumuza geçiş yapalım.

Daha önceki yazılarımda Silverlight 2.0 ile istemci tarafındaki dosyalara OpenFileDialog ile ulaşabildiğimizi görmüştük. Yine aynı sistemi kullanarak bu sefer amacımız bir Powerpoint dosyasını açarak söz konusu dosyanın Thumbnail görüntüsünü Silverlight içerisinde göstermek. Aslında çok şanslıyız, neden mi? Çünkü OpenXML var.

OpenXML'in bize faydası ne?

OpenXML formatındaki her dosya aslında bir ZIP dosyasıdır. Eğer dosyanın uzantısını ZIP olarak değiştirirseniz aslında içerisine girerek tüm detayları görebilirsiniz.

OpenXML dosyalarının içinde herşey XML formatında, açık seçik karşımızda.
OpenXML dosyalarının içinde herşey XML formatında, açık seçik karşımızda.

Yukarıdaki basit bir Powerpoint dosyasının içeriği görebilirsiniz. Gördüğünüz üzere aslında her şey ayrı ayrı XML dosyaları şeklinde kaydedilmiş. Yani bir Office 2007 dosyası yaratmak özünde XML'ler yaratarak ZIP'lemekten farklı değil. Hele bir de bu dosyaları açarak programlarınızda göstermek istiyorsanız LINQ2XML'in gücünden de faydalanarak çok hızlı çözümler geliştirmeniz mümkün.

Konumuza dönersek; bize Powerpoint dosyasının Thumbnail'i lazımdı. Bunun için XML'ler içerisinde ilk slayt ile ilgili bilgileri alarak gerekli çizimleri hazırlayabiliriz fakat buna gerek yok. Çünkü her PowerPoint dosyası zaten işletim sisteminde gösterilecek olan Thumbnail'i kendi içinde barındırır. OpenXML formatı sağ olsun, dosyamızın içini biraz karıştırdığımızda görüyoruz ki ZIP dosyası içerisinde docProps adındaki bir klasörün içinde thumbnail.jpeg adında bir JPG dosyası bulunuyor. İşte bu dosya bizim Silverlight tarafında göstereceğimiz thumbnail görselini içeriyor.

ZIP'ten resmi nasıl alacağız?

Yine daha önceki bir yazımda bir ZIP dosyalarını Silverlight tarafında açabilmenin yollarına değinmiştik. Hatta daha da ileri giderek Silverlight 2.0 XAP dosyaları da birer ZIP dosyası olduğu için onları açmıştık. Şimdi ise sıra başka bir ZIP dosyası açmaya geldi, Powerpoint dosyaları.

İlk olarak Powerpoint dosyasını açarak Thumbnail'i gösterecek olan uygulamamızın tasarımını basit bir şekilde yapalım. Sahnede bir düğme ve bir de Image nesnesi olsun. Düğmeye basında kullanıcıdan bilgisayarından bir Powerpoint dosyası seçmesini isteyelim ve sonrasında da seçili dosyanın Thumbnail'ini Image nesnesi içerisinde gösterelim.

<UserControl x:Class="SilverlightApplication58.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <Button Height="32" HorizontalAlignment="Left" Margin="24,32,0,0" VerticalAlignment="Top" Width="104" Content="Button" x:Name="btnDosyaAc"/>

        <Image Margin="160,32,80,140" x:Name="imgOnIzleme"/>

    </Grid>

</UserControl>

Sıra geldi gerekli işlemleri sırası ile yapacak olan kodumuzu yazmaya.

[VB]

        Dim DosyaAc As New OpenFileDialog

        DosyaAc.Filter = "PowerPoint 2008 Dosyaları (*.pptx)|*.pptx"

        DosyaAc.Multiselect = False

        DosyaAc.ShowDialog()

[C#]

            OpenFileDialog DosyaAc = new OpenFileDialog();

            DosyaAc.Filter = "PowerPoint 2008 Dosyaları (*.pptx)|*.pptx";

            DosyaAc.Multiselect = false;

            DosyaAc.ShowDialog();

İlk olarak yukarıdaki şekilde Silverlight tarafında kullanıcıdan bilgisayarından bir Powerpoint dosyası seçmesini isteyelim. Sonrasında bize dosyanın Stream'i gelecek ve biz de içerisinden istediğimiz JPEG dosyasını almaya çalışacağız. Kodumuz içerisinde istemcideki dosyalara ulaşmak için bir OpenFileDialog kullanıyor, filtresini de sadece PPTX'leri gösterecek şekilde ayarlıyoruz.

[VB]

        If DosyaAc.SelectedFile IsNot Nothing Then

            Dim Foto As New Imaging.BitmapImage()

            Dim Gelen = Application.GetResourceStream(New Windows.Resources.StreamResourceInfo(DosyaAc.SelectedFile.OpenRead(), Nothing), New Uri("docProps/thumbnail.jpeg", UriKind.Relative)).Stream

            Foto.SetSource(Gelen)

            imgOnIzleme.Source = Foto

        End If

[C#]

            if (DosyaAc.SelectedFile != null) {

                System.Windows.Media.Imaging.BitmapImage Foto = new System.Windows.Media.Imaging.BitmapImage();

                System.IO.Stream Gelen = Application.GetResourceStream(new System.Windows.Resources.StreamResourceInfo(DosyaAc.SelectedFile.OpenRead(), null), new Uri("docProps/thumbnail.jpeg", UriKind.Relative)).Stream;

                Foto.SetSource(Gelen);

                imgOnIzleme.Source = Foto;

            }

Bu noktada Silverlight ile beraber gelen Resource yapısını kullanacağız ve sanki harici bir kaynak açarmış gibi ZIP dosyasını açtıracağız. Sonuçta hedefin bir Powerpoint dosyası olup olmadığı önemli değil. Bizim istediğimiz ZIP dosyasındaki docProps klasöründe bir dosyayı almak. Kullandığımız taktik daha önceleri Silverlight 2.0 XAP dosyalarından dosya almak için kullandığımız taktik ile birebir aynı. StreamResource olarak OpenFileDialog'dan gelen dosyanın içerisinde JPEG dosyasını alıyor ve GetResourceStream ile de dosyayı çekiyoruz. Çektiğimiz dosyayı daha önce Foto adında tanımladığımız BitmapImage değişkenine SetSource ile atayarak sonunda da delimizdeki resmi sahnedeki Image nesnesine aktarıyoruz.

Böylece Powerpoint dosyasında Thumbnail'i bularak Silverlight 2.0 içerisinde çok kolay bir şekilde gösterebildik. Bu aynı taktiği ASP.NET ile de kullanarak gerektiğinde sunucu taraflı olarak Powerpoint dosyalarında Thumbnail'ler yaratmak OpenXML sayesinde çocuk oyuncağına dönüşmüş durumda.

Hepinize kolay gelsin.

Saturday, July 12, 2008 5:05:12 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, July 10, 2008

Silverlight 2.0 Beta 2 ile beraber 1.0 sürümüne göre uygulamaların dağıtım sistemi değişti ve karşımıza XAP dosyaları çıktı. Bu dosyaları standart HTML veya herhangi bir sunucu taraflı programlama altyapısında kullanmanın yolu da aslında eskiden Flash tarafında alışık olduğumuz Object taglarına dönüştü. Bu durumun tabi ki güzel yanları var, Silverlight 1.0'da olduğu gibi harici JavaScript dosyalarına (Silverlight.js) ve DIV elementlerine vs ihtiyacımız olmuyor. Şimdi gelin beraber Silverlight 2.0 uygulamalarını sayfalarımıza yerleştirirken kullanacağımzı OBJECT tagları ile gelen yenilikleri inceleyelim.

Yeni bir Silverlight 2.0 projesi

Visual Studio 2008 içerisinde yeni bir Silverlight 2.0 projesi yarattığımızda bizim için test amaçlı olarak örnek bir de HTML dosyası hazırlanıyor. Bu dosya içerisinde bir Silverlight uygulamasının gösterimi için konulmuş kodları yavaş yavaş inceleyelim.

    <div id="silverlightControlHost">

        <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">

            <param name="source" value="ClientBin/SilverlightApplication56.xap"/>

            <param name="onerror" value="onSilverlightError" />

            <param name="background" value="white" />

 

            <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

            </a>

        </object>

        <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

    </div>

En dışta silverlightControlHost adında bir DIV elementi bulunuyor. Aslında böyle elementin bulunmasına hiç gerek yok, sadece CSS ile Silverlight uygulamasının boyutu ayarlanabilsin diye yerleştirilmiş bu DIV elementinin başka herhangi bir işlevselliği olmadığı için rahatlıkla koddan kaldırılabilir.

Esas OBJECT tagımıza geçtiğimizde karşımıza dört farklı özellik çıkıyor. Bunlardan Data özelliği OBJECT taglarının farklı tarayıcılarda farklı işlevselliklerle karşılaşmasından dolayı yerleştirilmiş. Data özelliği olmayan OBJECT tagları bazı tarayıcılarda sorun çıkartabiliyor. TYPE özelliği tarayıcıya Silverlight Plug-In'in bu OBJECT tagından sorumlu olduğu bilgisini verirken width ve height ise uygulamanın sayfadaki boyutunu belirtiyor.

            <param name="source" value="ClientBin/SilverlightApplication56.xap"/>

            <param name="onerror" value="onSilverlightError" />

            <param name="background" value="white" />

OBJECT tagları arasında bazı parametreler var. Bu parametreler uygulamanın özelliklerine göre değişecektir, hatta burada tanımlanmamış olan bazı farklı parametreler de kullanmak mümkün. Mevcut parametreler arasında Source parametresi istemciye yüklenecek olan XAP dosyasının adresini taşırken onerror parametresi ise hata durumunda istemci tarafında çalıştırılacak olan JavaScript metodunun adını saklıyor.

            <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

            </a>

Buradaki kod ise aslında istemcide Silverlight Runtime yüklü olmadığında gösterilecek olan içeriği tanımlıyor. Gördüğünüz gibi basit bir şekilde "Get Microsoft Silverlight" logosu gösterilerek microsoft.com'da bir web sayfasına yönlendirilmiş. Artık SL 1.0'da olduğu gibi Silverlight Plug-In'in hangi sürümünün veya hangi platforma özel yüklemesinin yapılacağına JavaScript ile istemci tarafında karar vermiyoruz. Herhangi bir şekilde yükleme gerektiğinde doğrudan Microsoft sitesine yönlendirme yaparak tüm işi Microsoft'a bırakıyoruz. Bu biz yazılım geliştiriciler için çok daha rahat bir sistem.

Eğer isterseniz yukarıdaki HTML kodunu değiştirerek Silverlight RunTime yüklü olmadığında ekranda gösterilecek içeriği farklı bir şekilde tanımlayabilirsiniz. Önemli olan tek nokta herhangi bir şekilde bir link ile kullanıcıları doğru adrese yönlendirerek Microsoft sitesinden RunTime paketini indirmelerine olanak tanımak.

    <div id="silverlightControlHost">

        <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">

            <param name="source" value="ClientBin/SilverlightApplication56.xap"/>

            <param name="onerror" value="onSilverlightError" />

            <param name="background" value="white" />

 

            <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">

                <img src="silverlightyok.jpg" alt="Microsoft Silverlight Yükle" style="border-style: none"/>

            </a>

        </object>

        <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

    </div>

Örneğin yukarıdaki kod içerisindeki HTML sayesinde eğer istemci tarafında Silverlight Runtime yüklü değil ise silverlightyok.jpg adında bir resim gösteriliyor ve tıklandığında RunTime yüklenmek üzere Microsoft web sitesine yönlendiriliyor.

        <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>

Bu da nesi? Bu tamamen Safari tarafında bir önbellekleme sorununu gidermek için yerleştirilmiş normalde kullanılmayan bir IFRAME. Safari tarayıcısında bir sayfada eğer bir IFRAME varsa sayfa hiçbir şekilde önbelleğe alınmıyor.

Bunların haricinde Visual Studio'da yaratılan sayfa içinde hata yakalama için onSilverlightError adında bir JavaScript fonksiyonu ve errorLocation adında bir DIV elementi bulunuyor. Bahsi geçen bu JavaScript fonksiyonu herhangi bir hata durumunda hata mesajını alarak errorLocation içerisine yazdırmakla sorumlu.

Hepinize kolay gelsin.

Thursday, July 10, 2008 2:20:04 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Wednesday, July 09, 2008

Silverlight 2.0 Beta 2 içerisinden normal şartlarda uygulamanın çalıştığı bilgisayardaki dosyalara ulaşma şansınız olmaz. Bu durum aslında çok normal bir durum çünkü Silverlight tamamen internet tarayıcısı içerisinde çalışıyor ve dışarıya çıkarak sisteme ulaşması büyük bir güvenlik açığı olurdu. Oysa bizim bazı durumlarda Silverlight tarafına sistemimizdeki bir dosyayı aktarmak isteyebiliriz. Örneğin sistemdeki bir video dosyasını kullanıcının web sitesindeki Silverlight ile açarak oynatmasını isteyebiliriz. Özellikle bu Silverlight uygulamasının Macintosh tarafında da çalışacağını düşünürsek aslında Mac için basit bir WMV Player bile yapmış oluyoruz. Peki sistemdeki dosyalara nasıl ulaşacağız? Tabi ki "Open File Dialog" aracılığı ile.

Uygulamamızı tasarlayalım.

İlk olarak istemci tarafındaki video dosyalarını oynatacak olan uygulamamızın ana ekran tasarımını yapalım. Sahnede adı Video olan bir MediaElement ve bir de Button bulunacak. Düğmeye basıldığında Open File Dialog aracılığı ile istemcide video dosyalarından birini alacağız.

<UserControl x:Class="SilverlightApplication55.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <MediaElement Margin="24,8,128,84" x:Name="Video"/>

        <Button Height="24" HorizontalAlignment="Stretch" Margin="192,0,128,44" VerticalAlignment="Bottom" Content="Dosya Aç" x:Name="btnAc" Click="btnAc_Click"/>

    </Grid>

</UserControl>

Kodlama zamanı

Düğmemize basıldığında ilk olarak yeni bir Open File Dialog yaratacağız sonrasında da nesnemizin özelliklerini tanımlayacağız.

[VB]

Dim DosyaAc As New OpenFileDialog

DosyaAc.Filter = "WMV Dosyaları (*.wmv)|*.wmv"

DosyaAc.Multiselect = False

DosyaAc.ShowDialog()

[C#]

OpenFileDialog DosyaAc = new OpenFileDialog();

DosyaAc.Filter = "WMV Dosyaları (*.wmv)|*.wmv";   

DosyaAc.Multiselect = false;   

DosyaAc.ShowDialog();

Kod içerisinde Open File Dialog'un ilk olarak Filter özelliğini tanımlıyoruz. Aslında buradaki kullanım Windows Forms'daki kullanım ile neredeyse aynı. Bizim örneğimizdeki filtrede kullanıcıya sadece WMV dosyalarını seçtiriyoruz. Bir sonraki adımda Open File Dialog nesnemizin Multiselect özelliğinide False yaparak bir defada sadece bir dosya seçilebilmesini de sağladıktan sonra artık Dialog'u ekranda göstermek için ShowDialog metodunu çağırabiliriz.

[VB]

If DosyaAc.SelectedFile IsNot Nothing Then

Video.AutoPlay = True

Video.SetSource(DosyaAc.SelectedFile.OpenRead)

End If

[C#]

if (DosyaAc.SelectedFile != null) {

    Video.AutoPlay = true;

    Video.SetSource(DosyaAc.SelectedFile.OpenRead);

}

Kullanıcı Open File Dialog'u kapattıktan sonra herhangi bir dosyanın seçilip seçilmediğini SelectedFile özelliği üzerinden kontrol ederek eğer dosya seçilmiş ise OpenRead metodu ile dosyayı okuyabiliyoruz. Biz okuduğumuz dosyayı MediaElement'in Source'una aktaracağımız için ilk olarak aktarma sonrası hemen video oynatılsın diye MediaElement'in AutoPlay özelliğini True yapıyoruz. Son olarak da SetSource metoduna elimizdeki dosyayı aktarıyoruz. Böylece artık video dosyası MediaElement içerisinde oynatılıyor olacak. Unutmayın videoyu sunucuya almadık, hala tamamen istemci tarafında çalışıyoruz.

Birden çok dosya okuyalım

Open File Dialog'un MultiSelect özelliği True olduğunda birden çok dosya seçilerek işlem yapılabiliyor. Bu konudaki örneğimizde sahnede bir TextBox ve bir düğme bulunacak. Düğmeye tıklandığında sistemden kullanıcıların istedikleri kadar fazla sayıda TXT dosyası seçebilecekler. Bu dosyaların hepsinin içeriğini arka arkaya TextBox içerisine yerleştireceğiz.

[VB]

        Dim DosyaAc As New OpenFileDialog

        DosyaAc.Filter = "TXT Dosyaları (*.txt)|*.txt"

        DosyaAc.Multiselect = True

        DosyaAc.ShowDialog()

        If DosyaAc.SelectedFiles IsNot Nothing Then

            For Each Dosya In DosyaAc.SelectedFiles

                txtMetin.Text += Dosya.OpenText.ReadToEnd

            Next

        End If

[C#]

OpenFileDialog DosyaAc = new OpenFileDialog();

DosyaAc.Filter = "TXT Dosyaları (*.txt)|*.txt";

DosyaAc.Multiselect = true;

DosyaAc.ShowDialog();

if (DosyaAc.SelectedFiles != null) {

    foreach ( Dosya in DosyaAc.SelectedFiles) {

        txtMetin.Text += Dosya.OpenText.ReadToEnd;

    }

}

Yukarıdaki kod içerisinde her zamanki gibi Open File Dialog nesnemizi oluşturarak uygun filtreyi tanımlıyoruz. Dikkat etmemiz gereken nokta Multiselect özelliğinin True olarak ayarlanmış olması. Dosyalar seçildikten sonra SelectedFiles listesinden her bir dosyayı tek tek alarak OpenText metoduyla dosya içerisindeki yazıyı okuyarak txtMetin adındaki TextBox nesnemize aktarıyoruz.

Hepinize kolay gelsin.

Wednesday, July 09, 2008 1:01:10 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, July 07, 2008

ASP.NET Authentication mekanizmaları neredeyse tüm ASP.NET projelerinde kullandığımız pratik çözümlerden. Özellikle Forms Authentication belki de özellikle internet projelerinde en sık karşılaştığımız sistem. Peki nasıl yaparız da Silverlight 2.0 Beta 2 uygulamalarımızda ASP.NET Forms Authentication yapısını kullanabiliriz?

WCF üzerinden Authentication servisine ulaşalım.

Silverlight tarafında sunucuyla veri alışverişi için en uygun seçim WCF servisleri. Bu nedenle bize bir şekilde Authentication servisine ulaşabileceğimiz bir servis gerekiyor. Yeni bir Silverlight projesi yaratarak yanında gelen ASP.NET sitesiyle işlemlerimizi yapmaya başlayalım.

ASP.NET'in kendi WCF Authentication servis altyapısını kullanacağız. Tek ihtiyacımız olan bir Wrapper. Bunun için hemen ASP.NET sitesine sağ tuş ile tıklayarak gelen menüden "Add New Item" diyip normal bir Text File ekleyelim. Bu yeni dosyanın adını Auth.svc şeklinde düzenledikten sonra içini açarak aşağıdaki kodu yapıştıralım.

<%@ ServiceHost Language="VB" Service="System.Web.ApplicationServices.AuthenticationService" %>

Böylece servisimizi tamamladık. Sıra geldi bu servisin çalışması için Web.Config içerisinde yapmamız gereken ayarlara. İlk olarak Forms Authentication yapımızı ayarlayalım.

      <authentication mode="Forms">

        <forms loginUrl="default.aspx" protection="All" timeout="30" path="/">

          <credentials passwordFormat="Clear">

            <user name="daron" password="123" />

          </credentials>

        </forms>

      </authentication>

      <authorization>

        <deny users="?" />

      </authorization>

Yukarıdaki kodumuz ile default.aspx haricindeki sitedeki her şeyi dışarıya kapadık. Çok uğraşmamak için hemen Web.Config içerisinde de bir kullanıcı tanımladım. Normalde bu tarz bir yapıyı kimseye tavsiye etmiyorum. Tabi tüm dosyaları dışarıya kapadığımız için Silverlight uygulaması da Auth.svc servisine de ulaşamayacak. O nedenle servisimizi Authentication dışında tutup herkese açmamız lazım.

  <location path="Auth.svc">

    <system.web>

      <authorization>

        <allow users="*"/>

      </authorization>

    </system.web>

  </location>

Forms Authentication ayarlarımızı tamamladığımıza göre artık WCF servisimizle ilgili ayarları da yapabiliriz.

  <system.serviceModel>

    <services>

      <service name="System.Web.ApplicationServices.AuthenticationService"

              behaviorConfiguration="AuthenticationServiceTypeBehaviors">

        <endpoint contract="System.Web.ApplicationServices.AuthenticationService"

                  binding="basicHttpBinding" bindingConfiguration="userHttp"

                  bindingNamespace="http://asp.net/ApplicationServices/v200"/>

      </service>

    </services>

    <bindings>

      <basicHttpBinding>

        <binding name="userHttp">

          <security mode="None"/>

        </binding>

      </basicHttpBinding>

    </bindings>

    <behaviors>

      <serviceBehaviors>

        <behavior name="AuthenticationServiceTypeBehaviors">

          <serviceMetadata httpGetEnabled="true"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <!-- HTTP üzerinden servise ulaşımı sağlar. -->

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

  </system.serviceModel>

  <!--Authentication servisini dışarıya açar-->

  <system.web.extensions>

    <scripting>

      <webServices>

        <authenticationService enabled="true" requireSSL="false"/>

      </webServices>

    </scripting>

  </system.web.extensions>

Her şey hazır. Internet tarayıcınızda Auth.svc adresini açtığınızda servisin çalışır halde olduğunu görebilirsiniz. Sıra geldi Silverlight ile bu servisi kullanmaya.

WCF Authentication Servisimiz Silverlight ile dilleniyor.

Herhangi bir WCF servisini Silverlight uygulamamıza linklermiş gibi yine projeye sağ tıklayarak "Add Service Reference" diyerek referansımızı yaratıyoruz. Sonrasında artık kod içerisinde tüm Authentication mekanizmalarını kullanabiliriz.

[VB]

    WithEvents Servisim As New ServiceReference1.AuthenticationServiceClient

 

    Private Sub Giris_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Giris.Click

        Servisim.LoginAsync(Kullanici.Text, Sifre.Text, "", True)

    End Sub

 

    Private Sub Servisim_LoginCompleted(ByVal sender As Object, ByVal e As ServiceReference1.LoginCompletedEventArgs) Handles Servisim.LoginCompleted

        Giris.Content = e.Result

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

            Giris.Click += new RoutedEventHandler(Giris_Click);

        }

 

        void Giris_Click(object sender, RoutedEventArgs e)

        {

            ServiceReference1.AuthenticationServiceClient Servisim = new SilverlightApplication2.ServiceReference1.AuthenticationServiceClient();

            Servisim.LoginCompleted += new EventHandler<SilverlightApplication2.ServiceReference1.LoginCompletedEventArgs>(Servisim_LoginCompleted);

            Servisim.LoginAsync(Kullanici.Text, Sifre.Text, "", true);

        }

 

        void Servisim_LoginCompleted(object sender, SilverlightApplication2.ServiceReference1.LoginCompletedEventArgs e)

        {

            Giris.Content = e.Result.ToString();

        }

Yukarıdaki örnek kodlar içerisinde WCF servisimizin LoginAsync metodunu kullanarak bir Login işlemi yapmaya çalışıyoruz. Yine servis ile beraber gelen event'lardan biri olan LoginCompleted durumunda ise Login işleminin başarılı olup olmadığını ekrana yazdırıyoruz. Bu şekilde servis içerisinde kullanabileceğiniz Logout, IsLoggedIn gibi metodlar da bulunuyor.

Hepinize kolay gelsin.

Monday, July 07, 2008 4:39:11 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, July 06, 2008

Silverlight 2 Beta 2 uygulamalarınızı test ederken bazen hangi nesnenin nerede olduğunu standart web tarayıcılarındaki DOM Explorer eklentileri gibi görebilmek isteyebilirsiniz. Her nesnenin gerçek zamanlı olarak nasıl bir XAML oluşturduğunu görmenin yanı sıra herhangi bir web sitesinde çalışan Silverlight 2 uygulamasının tüm kaynak XAML'ını gösteren SilverlightSpy karşınızda!

SilverlightSpy arayüzü...
SilverlightSpy arayüzü...

Aşağıdaki adresten uygulamanın yükleme sayfasına ulaşarak ClickOnce üzerinden yüklemeyi gerçekleştirebilirsiniz. Yükleme öncesi aynı sayfada "install the prerequisites" linkine tıklayarak gerekli ön yüklemeleri tamamlamayı unutmayın.

http://firstfloorsoftware.com/silverlightspy/download-silverlight-spy/

Uygulama tamamen tarayıcıdan bağımsız çalışıyor. Kendi içerisine gömülü Internet Explorer yapısını kullanarak ziyaret ettiğiniz sitelerin içerisindeki Silverlight uygulamalarını incelemenizi sağlıyor.

Hepinize kolay gelsin.

Sunday, July 06, 2008 12:19:47 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Saturday, July 05, 2008

Silverlight 2.0 içerisinde kullandığımız standart kontrollerin yanı sıra istersek kendi kontrollerimizi de hazırlama şansımız var. Daha önceleri ister ASP.NET ister Windows uygulamalarından alışık olduğumuz bu uygulama ile hazırladığınız size özel kontrolleri farklı projelerde rahatlıkla kullanma şansına sahip olabilirsiniz. Bu yazımızda deneme amaçlı olarak Silverlight 2.0 ile beraber gelen Button kontrolünü baz alıp geliştirerek yeni bir kontrol oluşturacağız. Yaratacağımız yeni TimeOutButton kontrolü kullanıcından bir TimeOut değeri alacak. Milisaniye cinsinden verilen bu süre sonunda Button kullanılamaz hale gelecek. Bu esnada Button'un üzerinde sürekli kaç saniye kaldığı da yazılacak. Kullanıcıların belirli bir sürede bir işlemi tamamlamasını istiyorsanız bu gibi bir Button işinizi görebilir. Gelin hemen işe koyulalım.

Çalışma ortamımızı hazırlayalım.

Kontrolümüzü geliştirirken sürekli test etmek isteyeceğiz. O nedenle ilk olarak sağlıklı bir çalışma ortamı hazırlamamız lazım. Yeni bir Silverlight projesi yarattığınızda Visual Studio içerisinde Solution içinde bir ASP.NET ve bir de Silverlight projeniz bulunur. Solution dosyasına bir proje daha ekleyeceğiz. Solution Explorer içerisinde solution dosyasına sağ tuş ile tıkladıktan sonra "Add / New Project" diyerek "Silverlight Class Library" seçeneğini işaretlemeniz yeterli olacaktır. Böylece yeni kontrolümüzü oluşturmak için kodlarımızı yazacağımız ortamı geliştirdik.

Solution'ı Compile ettiğimizde Silverlight projemize otomatik olarak bu kontrol projemizin de eklenmesi gerekiyor. O nedenle hemen Silverlight projesine sağ tuş ile tıklayarak gelen menüden "Add Reference" komutunu verin ve karşınıza gelen pencereden de "Projects" tabına geçerek Class Library projenizi seçin. Böylece artık F5'e bastığınızda her şey otomatik olarak yapılacaktır ve kontrolünüzü kullanılır şekilde inceleyebileceksiniz. Tabi testlere geçmeden önce biraz kod yazmamız gerekiyor ;)

Kontrolümüzü hazırlayalım.

Class Library içerisinde kod dosyamızda düğmemizin adını taşıyan bir Class bulunuyor. Bu Class'ı biz örneğimizde standart Silverlight Button kontrolünden inherit edeceğiz. Böylece yeni ve gelişmiş bir Button yaratırken her şeye sıfırdan başlamayacağız, Silverlight içerisinde hazır Button kontrolünü alarak üzerine yeni işlevsellikler ekleyeceğiz.

[VB]

Public Class TimeOutButton

    Inherits Button

 

End Class

[C#]

namespace TimeOutBtn

{

    public class TimeOutButton : Button

    {

       

    }

}

Bir sonraki adımda hemen kontrolümüze yeni bir Property tanımlayalım. Property'miz sayesinde kullanıcıların düğmenin ne kadar süre aktif kalacağını tanımlayabilecekler.

[VB]

    Private PTimeOut As Integer

    Public Property TimeOut() As Integer

        Get

            Return PTimeOut

        End Get

        Set(ByVal value As Integer)

            PTimeOut = value

        End Set

    End Property

[C#]

        public int TimeOut { get; set; }

Düğmemiz ilk olarak sayfada gözüktüğünde hemen işlemlere başlamamız gerekiyor. İlk olarak düğmenin için sayaç bilgisi yazacak yeni bir kontrol eklememiz şart. Düğmenin Content özelliği duruma göre doğrudan bir String olabilir veya Content içerisinde farklı Silverlight nesneleri bulunabilir. Tüm bunları göz önünde bulundurmak zorundayız.

[VB]

        Dim Container As New StackPanel

        Container.Orientation = Orientation.Vertical

        Container.HorizontalAlignment = Windows.HorizontalAlignment.Center

        Container.VerticalAlignment = Windows.VerticalAlignment.Center

 

        If Me.Content.GetType() Is System.Type.GetType("System.String") Then

            Dim TextBl As New TextBlock

            TextBl.Text = Me.Content

            Container.Children.Add(TextBl)

        Else

            Container.Children.Add(Me.Content)

        End If

        Container.Children.Add(MyBox)

        Me.Content = Container

[C#]

            StackPanel Container = new StackPanel();

            Container.Orientation = Orientation.Vertical;

            Container.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;

            Container.VerticalAlignment = System.Windows.VerticalAlignment.Center;

 

            if (object.ReferenceEquals(this.Content.GetType(), System.Type.GetType("System.String"))) {

                TextBlock TextBl = new TextBlock();

                TextBl.Text = this.Content.ToString();

                Container.Children.Add(TextBl);

            }

            else {

                Container.Children.Add(this.Content as UIElement);

            }

            Container.Children.Add(MyBox);

            this.Content = Container;

Kodumuz içerisinde ilk olarak bir StackPanel yaratıyoruz. StackPanel'in özelliklerini ayarladıktan sonra hemen düğmemize atanmış Content'i kontrol ediyoruz. Amacımız Content içerisinde her ne varsa hepsini StackPanel içine eklemek. Sonrasında bizim kalan saniye miktarını göstereceğimiz TextBlock'u da yine StackPanel içerisine ekleyerek StackPanel'i de düğmenin Content'i yapacağız. Böylece bu TimeOutButton kontrolünü kullananlar düğmenin Content'ine ne koyarlarsa koysunlar kalan saniye miktarı sürekli bu Content'in içerisinde gösterilecek.

Eğer düğmeye atanmış Content String tipindeyse bu String'i alıp yeni bir TextBlock yaratarak içerisine yerleştiriyoruz. TextBlock'umuzu da StackPanel içine koyuyoruz. Eğer Content String değilse demek ki kullanıcı düğmenin Content'ine bir Silverlight nesnesi koymuş. Bu durumda söz konusu nesneyi alıp doğrudan StackPanel içine koyabiliriz. Son olarak kodumuzda gözükmeyen fakat uygulamamızda global bir değişken olarak yarattığımız MyBox adındaki TextBlock'u da StackPanel'e ekliyoruz ve StackPanel'i de düğmenin Content'i yapıyoruz. MyBox kontrolünü global yaratmamızın nedeni ileriki adımlarda MyBox'ın içeriğine sürekli kalan saniye miktarını yazdıracak olmamız.

[VB]

    Dim MyBox As New TextBlock

    WithEvents Timer As New System.Windows.Threading.DispatcherTimer

[C#]

        TextBlock MyBox = new TextBlock();

        System.Windows.Threading.DispatcherTimer Timer = new System.Windows.Threading.DispatcherTimer();

Global değişkenimiz arasında bir de DispatcherTimer bulunuyor. Bu Timer ile kalan saniye miktarını sürekli hesaplayıp kontrol ederek düğmenin içine yazdıracağız.

[VB]

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer.Tick

        If PTimeOut <= 0 Then

            Timer.Stop()

            MyBox.Visibility = Windows.Visibility.Collapsed

            Me.IsEnabled = False

        Else

            PTimeOut -= 1000

            MyBox.Text = (PTimeOut / 1000).ToString  + " saniye kaldı."

        End If

    End Sub

[C#]

        private void Timer_Tick(object sender, System.EventArgs e)

        {

            if (TimeOut <= 0)

            {

                Timer.Stop();

                MyBox.Visibility = System.Windows.Visibility.Collapsed;

                this.IsEnabled = false;

            }

            else {

                TimeOut -= 1000;

                MyBox.Text = (TimeOut / 1000).ToString() + " saniye kaldı.";

            }

        }

Kodumuzda kalan süreyi PTimeOut adındaki private değişkenimizde saklayacağız. Eğer kalan süre sıfırın altında ise hemen Timer'ımızı durduruyor ve kalan süreyi gösteren TextBlock'umuz olan MyBox'ı sahneden kaldırıp düğmeyi de pasif hale getiriyoruz. Kalan süre sıfırdan büyük olduğu sürece MyBox TextBlock içerisine gerekli uyarıyı yazdırıp kalan süreyi Timer'ın Intervali kadar azaltıyoruz.

Expression Blend içerisinde hazırladığımız yeni kontrol.
Expression Blend içerisinde hazırladığımız yeni kontrol

Artık kontrolümüz hazır. Projemizi Blend ile açtığımızda Asset Library içerisinde Custom Controls tabında kontrolümüzü görebiliyoruz. Sahneye bir TimeOutButton ekleyip TimeOut özelliğini de ayarladıktan sonra kontrolümüzü kullanabiliriz.

<UserControl x:Class="SilverlightApplication47.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300" xmlns:TimeOutBtn="clr-namespace:TimeOutBtn;assembly=TimeOutBtn">

    <Grid x:Name="LayoutRoot" Background="White">

          <TimeOutBtn:TimeOutButton TimeOut="5000" Height="72" HorizontalAlignment="Left" Margin="56,48,0,0" VerticalAlignment="Top" Width="128" Content="TimeOutButton"/>

    </Grid>

</UserControl>

Hepinize kolay gelsin. Uygulamanın tam kodunu aşağıda inceleyebilirsiniz.

[VB]

Public Class TimeOutButton

    Inherits Button

 

    Private PTimeOut As Integer

    Public Property TimeOut() As Integer

        Get

            Return PTimeOut

        End Get

        Set(ByVal value As Integer)

            PTimeOut = value

        End Set

    End Property

 

    Dim MyBox As New TextBlock

    WithEvents Timer As New System.Windows.Threading.DispatcherTimer

 

    Private Sub TimeOutButton_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Container As New StackPanel

        Container.Orientation = Orientation.Vertical

        Container.HorizontalAlignment = Windows.HorizontalAlignment.Center

        Container.VerticalAlignment = Windows.VerticalAlignment.Center

 

        If Me.Content.GetType() Is System.Type.GetType("System.String") Then

            Dim TextBl As New TextBlock

            TextBl.Text = Me.Content

            Container.Children.Add(TextBl)

        Else

            Container.Children.Add(Me.Content)

        End If

        Container.Children.Add(MyBox)

        Me.Content = Container

        Timer.Interval = New TimeSpan(0, 0, 1)

        Timer.Start()

    End Sub

 

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer.Tick

        If PTimeOut <= 0 Then

            Timer.Stop()

            MyBox.Visibility = Windows.Visibility.Collapsed

            Me.IsEnabled = False

        Else

            PTimeOut -= 1000

            MyBox.Text = (PTimeOut / 1000).ToString  + " saniye kaldı."

        End If

    End Sub

End Class

[C#]

using System;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Ink;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace TimeOutBtn

{

    public class TimeOutButton : Button

    {

        public int TimeOut { get; set; }

 

        TextBlock MyBox = new TextBlock();

        System.Windows.Threading.DispatcherTimer Timer = new System.Windows.Threading.DispatcherTimer();

 

        public TimeOutButton()

        {

            this.Loaded += new RoutedEventHandler(TimeOutButton_Loaded);

            Timer.Tick += new EventHandler(Timer_Tick);

        }

 

        private void TimeOutButton_Loaded(object sender, System.Windows.RoutedEventArgs e)

        {

            StackPanel Container = new StackPanel();

            Container.Orientation = Orientation.Vertical;

            Container.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;

            Container.VerticalAlignment = System.Windows.VerticalAlignment.Center;

 

            if (object.ReferenceEquals(this.Content.GetType(), System.Type.GetType("System.String"))) {

                TextBlock TextBl = new TextBlock();

                TextBl.Text = this.Content.ToString();

                Container.Children.Add(TextBl);

            }

            else {

                Container.Children.Add(this.Content as UIElement);

            }

            Container.Children.Add(MyBox);

            this.Content = Container;

            Timer.Interval = new TimeSpan(0, 0, 1);

            Timer.Start();

        }

        private void Timer_Tick(object sender, System.EventArgs e)

        {

            if (TimeOut <= 0)

            {

                Timer.Stop();

                MyBox.Visibility = System.Windows.Visibility.Collapsed;

                this.IsEnabled = false;

            }

            else {

                TimeOut -= 1000;

                MyBox.Text = (TimeOut / 1000).ToString() + " saniye kaldı.";

            }

        }

    }

}

Saturday, July 05, 2008 1:34:50 PM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Friday, July 04, 2008

Silverlight uygulamalarında sağ tuş uygulamaya tıkladığımızda karşımıza Silverlight'a ait özel "Silverlight Configuration" menüsü gelir. Bu menüden kullanıcıların Silverlight uygulaması ile ilgili ayarları yapabilecekleri bir arayüze ulaşılır. Fakat bazı durumlarda farenin sağ tuşunu biz de kullanmak isteyebiliriz. Bu ister global anlamda tüm sayfayı kapsayacak şekilde olsun ister belirli Silverlight kontrolleri için olsun istersek sağ tuş ile gelen menüyü değiştirme şansımız var.

Menümüzü ve animasyonları hazırlayalım.

Silverlight uygulamamızda sağ tuş ile tıklandığında gösterilmek üzere hızlıca bir menü hazırlayalım. Menümüzde birden çok düğme bulunacak. Düğmeleri dikey olarak sahnede sıralamak için Menu'ye ait kök element olarak bir StackPanel kullanacağız.

        <StackPanel Height="248" Width="160" Background="#FFFF0000" x:Name="Menu1" Canvas.Top="24" Canvas.Left="48" Opacity="0">

            <Button Content="Button"/>

            <Button Content="Button"/>

            <Button Content="Button"/>

            <Button Content="Button"/>

            <Button Content="Button"/>

        </StackPanel>

Yukarıdaki XAML kodu içerisinde Menu1 adında bir StackPanel bulunuyor. StackPanel içerisinde tüm düğmeler dikey olarak hizalanacak. Bu StackPanel'i duruma göre sahnede gösterecek veya saklayacak olan animasyonlarımızı da hazırlayalım. Animasyonlar basit bir şekilde StackPanel'in Opacity özelliğini değiştirecekler.

        <Storyboard x:Name="MenuGel">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Menu1" Storyboard.TargetProperty="(UIElement.Opacity)">

                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="1"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="MenuGit">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Menu1" Storyboard.TargetProperty="(UIElement.Opacity)">

                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

Sıra kodlamada...

Uygulayacağımız taktik aslında çok basit; Silverlight uygulamasının içerisinde bulunduğu sayfanın oncontextmenu event'ını yakalayarak normal çalışma şeklini iptal edip menü gösterme işlemini biz üstleneceğiz. İlk olarak söz konusu event'ı uygulama açılışında yakalayalım.

[VB]

    Public Sub New()

        InitializeComponent()

        System.Windows.Browser.HtmlPage.Document.AttachEvent("oncontextmenu", AddressOf SagTus)

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

            System.Windows.Browser.HtmlPage.Document.AttachEvent("oncontextmenu", SagTus);

            this.MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown);

        }

Kodumuz içerisindeki SagTus adındaki event-handlerımızı da hemen yazalım.

[VB]

    Private Sub SagTus(ByVal sender As Object, ByVal args As Browser.HtmlEventArgs)

        Menu1.SetValue(Canvas.LeftProperty, CDbl(args.OffsetX))

        Menu1.SetValue(Canvas.TopProperty, CDbl(args.OffsetY))

        MenuGel.Begin()

        args.PreventDefault()

    End Sub

[C#]

        void SagTus(object sender, System.Windows.Browser.HtmlEventArgs args)

        {

            Menu1.SetValue(Canvas.LeftProperty, (double)args.OffsetX);

            Menu1.SetValue(Canvas.TopProperty, (double)args.OffsetY);

            MenuGel.Begin();

            args.PreventDefault();

        }

Kodumuzda ilk olarak args üzerinden farenin konumuzu alıyoruz ve söz konusu konuma Menu1 adındaki StackPanel'imizi taşıyoruz. Bizim örneğimizdeki Silverlight uygulamasının kök elementi bir Canvas olduğu için taşıma işlemini StackPanel'in Canvas.Left ve Canvas.Top özelliklerini değiştirerek halledebiliriz. Bir sonraki adımda menüyü görünür hale getirecek olan MenuGel animasyonunu çalıştırıp, args üzerinden PreventDefault metodunu çalıştırarak söz konusu event-handler'ın tarayıcı tarafından değerlendirilmesini engelliyoruz. Böylece tarayıcı bu event çalıştığında herhangi bir menü göstermeyecek.

[VB]

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        MenuGit.Begin()

    End Sub

[C#]

        void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            MenuGit.Begin();

        }

Son olarak uygulamanın herhangi bir yerine tıklandığında menüyü saklayacak olan MenuGit animasyonunu çalıştırıyoruz. Böylece istediğimiz gibi sağ tuş ile gelecek olan menüyü ayarlayabilir, tasarımını değiştirebiliriz.

Hepinize kolay gelsin.

Friday, July 04, 2008 7:29:45 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, July 02, 2008

Dinamik olarak Silverlight 2.0 uygulamalarında farklı XAP dosyalarını istemci tarafına yükleyerek ana XAP içerisinde gösterebiliyor olmak kullanıcı deneyimi açısından büyük önem taşıyor. İçerisinde yoğun animasyonların ve belki de harici kontrollerin bulunduğu bir arayüzü Silverlight uygulaması istemciye ilk gönderildiğinde topluca göndermek doğru olmayabilir. Bu durum hem ana Silverlight uygulamasının istemcide açılma süresini uzatacak hem de belki kullanıcının hiç kullanmayacağı uygulama bölümlerinin gereksiz yere kullanıcıya gönderilmesine neden olacaktır. Tüm bu nedenlerle dinamik olarak harici XAP dosyalarını, yani Silverlight uygulamalarını başka bir Silverlight uygulaması içerisine yükleyerek çalıştırabilmek büyük önem taşıyor. Sonraki örneğimizde dinamik XAP yükleme işlemini nasıl yapabileceğimizi inceleyeceğiz.

Projemizi hazırlayalım...

İlk olarak Visual Studio içerisinde yeni bir Silverlight projesi yaratarak beraberinde bir de ASP.NET uygulaması yaratılması için ilk açılışta gelen uyarı kutusunda gerekli işaretlemeyi yapalım. Bu standart prosesi atlattıktan sonra artık Visual Studio içerisindeki Solution'ımıza yeni bir Silverlight projesi daha eklememiz gerekiyor. Toplam olarak Solution içerisinde bir ASP.NET ve iki Silverlight projesi bulunacak.

Solution'a Solution Explorer içerisinde sağ tuş ile tıklayarak gelen menüden "Add / New Project" yeni bir Silverlight projesi seçerek ekleyebilirsiniz. Ekleme işlemini yaparken size aşağıdaki şekilde bir pencere ile eklenen Silverlight uygulamasının Solution içerisinde bir ASP.NET sitesi ile ilişkilendirip ilişkilendirilmeyeceği sorulacaktır. Bu noktada var olan uygulama ile yeni Silverlight'ımızı ilişkilendirmemiz gerekiyor, böylece Visual Studio içerisinde F5'e bastığımızda bu Silverlight uygulaması da compile edilerek ASP.NET sitesi içerisine kopyalanacaktır.

İkinci Silverlight uygulamamızı Solution içerisine eklerken...
İkinci Silverlight uygulamamızı Solution içerisine eklerken...

Sonradan yüklenecek Silverlight uygulamamızı hazırlayalım...

İlk olarak uzaktaki (remote) Silverlight uygulamamızı hazırlayalım. Örnek olması ve konudan çok uzaklaşmamak adına uygulamamız çok basit olacak fakat unutmayın ki uzaktaki Silverlight uygulaması video gösteren veya belki de harici kontroller (DataGrid) kullanan bir uygulama da olabilirdi. Böyle bir durumda karşıdan yüklenecek uygulamamız çok daha büyük bir boyuta sahip olurdu.

Biz şimdilik uygulama içerisinde toplama işlemi yapan iki TextBox ve bir de Button bulunsun. Böylece ana uygulamada toplama işlemi yapılacağı zaman bu harici uygulamayı yükleyerek kullanıcının istediğini yapmasını sağlayalım.

[XAML]

<UserControl x:Class="SilverlightRemote.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBox Height="40" HorizontalAlignment="Left" Margin="40,40,0,0" VerticalAlignment="Top" Width="120" Text="TextBox" TextWrapping="Wrap" x:Name="Kutu1"/>

        <TextBox Height="40" HorizontalAlignment="Right" Margin="0,40,40,0" VerticalAlignment="Top" Width="120" Text="TextBox" TextWrapping="Wrap" x:Name="Kutu2"/>

        <Button HorizontalAlignment="Stretch" Margin="160,120,160,140" VerticalAlignment="Stretch" Content="Button" x:Name="Dugme"/>

    </Grid>

</UserControl>

Uygulamamızın XAML kodu yukarıdaki şekilde sonlanıyor. Şimdi geçelim arkaplanda çalışan ve basit bir şekilde toplama işlemi yaparak sonucu düğmenin üzerine yazdıran koda.

[VB]

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Dugme.Content = CInt(Kutu1.Text) + Kutu2.Text

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

            Dugme.Click += new RoutedEventHandler(Dugme_Click);

        }

 

        void Dugme_Click(object sender, RoutedEventArgs e)

        {

            Dugme.Content = int.Parse(Kutu1.Text) + int.Parse(Kutu2.Text);

        }

Ana Silverlight uygulamamızı hazırlayalım...

Sıra geldi gerektiğinde uzaktaki Silverlight uygulamamızı yükleyerek kullanıcının kullanmasını sağlayacak olan ana uygulamamızı geliştirmeye. Bunun için yine basit bir örnek olarak uygulamamız içerisine bir StackPanel yerleştirelim. Söz konusu StackPanel içerisinde şimdilik uzaktaki uygulamamızın yüklenmesini sağlayacak olan bir düğme yer alacak.

[XAML]

<UserControl x:Class="SilverlightApplication36.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <StackPanel x:Name="LayoutRoot" Background="White">

        <Button Content="TOPLAMA işlemi için tıkla" x:Name="Dugme"/>

    </StackPanel>

</UserControl>

Uygulamamızın tasarımı da hazır olduğuna göre artık düğmeye basıldığında çalışacak kod kısmına geçebiliriz. Düğmemize tıklandığında bir WebClient kullanarak sunucudan diğer uygulamanın XAP dosyasını istemci tarafına yüklememiz gerekiyor.

[VB]

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Dim Yukleme As New WebClient

        AddHandler Yukleme.OpenReadCompleted, AddressOf Yukleme_OpenReadCompleted

 

        Yukleme.OpenReadAsync(New Uri("SilverlightRemote.xap", UriKind.Relative))

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

            Dugme.Click += new RoutedEventHandler(Dugme_Click);

        }

 

        void Dugme_Click(object sender, RoutedEventArgs e)

        {

            WebClient Yukleme = new WebClient();

            Yukleme.OpenReadCompleted += new OpenReadCompletedEventHandler(Yukleme_OpenReadCompleted);

            Yukleme.OpenReadAsync(new Uri("SilverlightRemote.xap", UriKind.Relative));

        }

Kodumuzun ilk satırında bir WebClient yarattıktan sonra WebClient'ın OpenReadCompleted event'ını da bir event-handler'a bağlıyoruz. Sonrasında da OpenReadAsync metodu ile uzaktaki XAP dosyasını istemciye indirmeye başlıyoruz. İndirme işlemi tamamlandığında event-handler kodumuz çalışacak. Şimdi esas işlemleri yapacağımız, XAP dosyası istemciye indiğinde çalışacak olan event-handler kodumuza geçelim.

[VB]

Dim UygulamaManifesti As String = New IO.StreamReader(Application.GetResourceStream(New Windows.Resources.StreamResourceInfo(e.Result, Nothing), New Uri("AppManifest.xaml", UriKind.Relative)).Stream).ReadToEnd()

[C#]

string UygulamaManifesti = new System.IO.StreamReader(Application.GetResourceStream(new System.Windows.Resources.StreamResourceInfo(e.Result, null), new Uri("AppManifest.xaml", UriKind.Relative)).Stream).ReadToEnd();

Buradaki kod ilk bakışta biraz karışık gelebilir fakat aslında çok basit. Her Silverlight uygulaması içerisinde (XAP dosyası içerisinde) bir AppManifest.xaml bulunur. Bu dosya içerisinde tek tek söz konusu uygulamada kullanılan Assembly'lerin adları ve ilişkili DLL dosyalarının adları bulunur. Bizim de hedefimiz uzaktaki uygulamada kullanılmış tüm Assembly'leri bularak istemci tarafında belleğe yüklemek. Aslında bizim örneğimizde tek bir Assembly olduğunu biliyoruz fakat eğer örnek farklı olsaydı ve harici kontroller kullanılmış olsaydı doğal olarak birden çok Assembly olacaktı. O nedenle biz daha genel geçer bir taktik kullanarak esnek olalım.

Yukarıdaki kod içerisinde bir StreamResourceInfo nesnesine e.Result ile indirdiğimiz XAP dosyasını aktarıyoruz. Bu StreamResource içerisinden de Application.GetResourceStream ile AppManifest.xaml dosyasını istiyoruz. Dosyayı aldığımızda Stream'ini de bir StreamReader ile sonuna kadar ReadToEnd ile okuyoruz. Böylece artık elimizde AppManifest.xaml var.

[VB]

Dim Dagitim As Deployment = CType(Markup.XamlReader.Load(UygulamaManifesti), Deployment)

[C#]

Deployment Dagitim = System.Windows.Markup.XamlReader.Load(UygulamaManifesti) as Deployment;

Bir sonraki adımda AppManifest.xaml içerisinde tanımlı olan Deployment şeklini bir Deployment nesnesine eşitlememiz gerekiyor. Bunu aslında elimizde String olarak var olan bir XAML'ı .NET nesnesine çevirme olarak değerlendirebilirsiniz. Markup.XamlReader.Load metodu ile elimizdeki dosyayı okutarak gelen nesneyi de Deployment'a Cast ediyoruz. Zaten uzaktaki (remote) uygulamamızı Compile ettiğimizde oluşan XAP dosyasının içerisine girerek AppManifest.xaml'ına baktığımızda da aşağıdaki XAML ile karşılaşıyoruz.

[XAML] AppManifest.xaml

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="SilverlightRemote" EntryPointType="SilverlightRemote.App" RuntimeVersion="2.0.30523.6">

  <Deployment.Parts>

    <AssemblyPart x:Name="SilverlightRemote" Source="SilverlightRemote.dll" />

  </Deployment.Parts>

</Deployment>

Sıra geldi artık Deployment içerisindeki tüm Assembly'leri gezerek hepsini istemci tarafında hafızaya yüklemeye. Tüm bu yüklemeleri yaparken aralarından SilverlightRemote.dll adında olanı bir kenara çekerek referansını ayrı bir değişkende tutacağız. Bunun yapmamızın nedeni ise bu DLL içerisindeki Page sınıfından bir adet türeterek sahneye almak zorunda olmamız. Assembly'leri hafızaya yüklesek de işin görsel kısmını sahneye almamız lazım. Bunun detaylarına birazdan değineceğiz, önce bir Assembly'leri tek tek yükleyelim.

[VB]

        Dim GorselAssembly As System.Reflection.Assembly = Nothing

 

        For Each BirAssembly As AssemblyPart In Dagitim.Parts

            Dim AssemblyDLLAdi As String = BirAssembly.Source

            Dim StreamBilgi As Windows.Resources.StreamResourceInfo = Application.GetResourceStream(New Windows.Resources.StreamResourceInfo(e.Result, "application/binary"), New Uri(AssemblyDLLAdi, UriKind.Relative))

 

            If AssemblyDLLAdi = "SilverlightRemote.dll" Then

                GorselAssembly = BirAssembly.Load(StreamBilgi.Stream)

            Else

                BirAssembly.Load(StreamBilgi.Stream)

            End If

        Next

[C#]

            System.Reflection.Assembly GorselAssembly = null;

 

            foreach (AssemblyPart BirAssembly in Dagitim.Parts)

            {

                string AssemblyDLLAdi = BirAssembly.Source;

                System.Windows.Resources.StreamResourceInfo StreamBilgi = Application.GetResourceStream(new System.Windows.Resources.StreamResourceInfo(e.Result, "application/binary"), new Uri(AssemblyDLLAdi, UriKind.Relative));

 

                if (AssemblyDLLAdi == "SilverlightRemote.dll")

                {

                    GorselAssembly = BirAssembly.Load(StreamBilgi.Stream);

                }

                else

                {

                    BirAssembly.Load(StreamBilgi.Stream);

                }

            }

Satır satır yukarıdaki kodumuzu inceleyelim. İlk satırda Assembly tipinde bir değişken yaratıyoruz. Bu değişken gerektiğinde bizim uzaktaki uygulama içerisinde görsel arayüzü tanımlayan Page sınıfının bulunduğu DLL'in referansını taşıyacak. Sonrasında hemen Deployment nesnemiz olan Dagitim'ın Parts dizisinde bir ForEach döngüsü başlatarak tüm Assembly'leri gezmeye başlıyoruz. Her Assembly'nin Source'unu yani tam DLL dosyasının adını alarak bu dosyaları tek tek StreamBilgi adındaki değişkenimize yüklüyoruz. XAP dosyası içerisinden DLL'leri alırken aynı AppManifest.Xaml'ı alırkenki tekniği kullanıyoruz. Son olarak hemen o an için üzerinde çalıştığımız Assembly'nin görsel arayüzümüzün bulunduğu Assembly olup olmadığını kontrole diyoruz. Bunun için doğrudan Assembly'e ait DLL adını karşılaştırıyoruz.

Burada hemen bir dipnot geçelim. Bir Silverlight uygulaması içerisinde harici kontrolleri içeren veya farklı sınıfları ve kodları barındıran DLL'ler bulunabilir. Bunların haricinde bir de her XAML (görsel) dosya arkasındaki UserControl tipindeki sınıflar vardır. Biz yukarıdaki kodumuzda içerisinde UserControl bulunan DLL'i ayırarak bir kenara referansını kaydediyoruz çünkü bu UserControl'ları sahneye almamız gerekiyor. Oysa diğer Assembly'leri kullanabilmek için sadece belleğe yüklememiz yeterli.

IF koşulumuz içerisinde gerekli kontrolleri de yaptıktan sonra normal Assembly'leri Load metodu ile Stream'ini vererek belleğe yüklerken içerisinde UserControl'lerimizin bulunduğu Assembly'i yüklerken GorselAsssembly değişkenine de bir referansını alıyoruz.

[VB]

        Dim Arayuz As UIElement = CType(GorselAssembly.CreateInstance("SilverlightRemote.Page"), UIElement)

        LayoutRoot.Children.Add(Arayuz)

[C#]

            UIElement Arayuz = GorselAssembly.CreateInstance("SilverlightRemote.Page") as UIElement;

            this.LayoutRoot.Children.Add(Arayuz);

Sıra geldi GorselAssembly içerisindeki ana UserControl'ümüz olan Page sınıfından bir instance olarak sahneye yerleştirmeye. Bunun için Assembly'nin CreateInstance metoduna sınıfımızın tam yolunu vererek bir kopyasını alıyor ve UIElement tipine cast ediyoruz. Sonrasında da elimizdeki nesneyi uygulamamızdaki StackPanel içerisine ekliyoruz.

Artık uygulamamızı çalıştırabiliriz. İlk Silverlight uygulaması istemciye yüklendikten sonra düğmeye bastığınızda ikinci uygulama sunucudan alınarak içerisinde UserControl sahneye yerleştirilecektir. Böylece rahatlıkla bir Silverlight projesini parçalar şeklinde geliştirebilir ve uygulamanın bölümlerini gerektikçe istemci tarafına aktarabilirsiniz.

Hepinize kolay gelsin.

Wednesday, July 02, 2008 10:14:01 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Tuesday, July 01, 2008

Bugün Microsoft İstanbul ofisinde Turkcell, Tekfen, Finansbank gibi kurumlardan katılımcıların bulunduğu Silverlight 2.0 ve WPF eğitimindeydim. Artık yavaş yavaş eğitimleri doğrudan Silverlight 2.0 tarafına doğru kaydırmaya başladık. Önümüzde ortalama iki ay gibi bir süre olsa da Silverlight 1.0'ın ömrü pek uzun gözükmüyor.

Microsoft Türkiye İş Ortakları Eğitimi
Microsoft Türkiye İş Ortakları Eğitimi

Eğitimde "Bir Türkiye Klasiği" diyebileceğim şekilde :) herkes C#'cıydı. Örneklerimizi C# üzerinden yaptık fakat en sonda kendimi tutamayıp yine VB ile inline XML ve XLINQ örneğimi de gösterdim. "C#'da yok mu bu?" sorusunu da "HAYIR ve hiçbir zaman da olmayacak nihahahaha!" şeklinde bir cevap vermekten de görüldüğü üzere büyük zevk aldım :) Şaka bir yana etki - tepki meselesi sonucunda sanırım VB fanatikliği yolunda ilerliyorum ki hiç hoş değil :)

Tuesday, July 01, 2008 1:36:46 PM (GTB Standard Time, UTC+02:00)  #    Comments [7]   Eğitimler | Silverlight 2.0 | WPF  | 
 Monday, June 30, 2008

Silverlight 1.0 ile beraber istemci tarafında herhangi bir font yüklemesi olmadan istediğimiz fontları TextBlock ve TextBox gibi kontrollerde kullanabilir hale gelmiştik. Silverlight 2.0 tarafında gelen yeniliklerle beraber artık her şeyi VB veya C# kodumuz ile halletmemiz gerekiyor. Bu yazımızda Silverlight 2.0 ile beraber özel font kullanımını inceleyeceğiz.

Sunucudan asenkron font indirerek kullanmak

Sunucudaki istediğimiz bir fontu asenkron olarak istemci tarafına indirip istediğimiz kontrollere bağlayabiliriz. Böylece gerekli fontları sadece gerekli olduğunda istemci tarafına taşımış oluruz. Bunun için Silverlight 2.0 tarafında bir WebClient nesnesi kullanarak ilk olarak font dosyasını istemci tarafına indirmemiz gerekiyor.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Yukleme As New WebClient

        AddHandler Yukleme.OpenReadCompleted, AddressOf Yukleme_OpenReadCompleted

        Yukleme.OpenReadAsync(New Uri("/SilverlightApplication33Web/deveload.ttf", UriKind.Relative))

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

 

            WebClient Yukleme = new WebClient();

            Yukleme.OpenReadCompleted += new OpenReadCompletedEventHandler(Yukleme_OpenReadCompleted);

            Yukleme.OpenReadAsync(new Uri("/SilverlightApplication34Web/deveload.ttf", UriKind.Relative));

        }

Kodumuzda Silverlight uygulaması yüklendiği gibi hemen bir WebClient nesnesi yaratarak ardından OpenReadCompleted event'ı için dinamik bir event handler bağlıyoruz. Söz konusu event handler WebClient nesnesinin sunucudan aldığı dosyanın download işlemi bittiğinde çalıştırılacak ve böylece biz de veri geldiğinde istediğimiz kontrole bağlayabileceğiz. Event-handler bağlantısını da tamamladıktan sonra OpenReadAsync ile sunucudan verimizi almaya başlıyoruz.

[VB]

    Private Sub Yukleme_OpenReadCompleted(ByVal sender As Object, ByVal e As System.Net.OpenReadCompletedEventArgs)

        Label1.FontSource = New FontSource(e.Result)

        Label1.FontFamily = New FontFamily("DEVELOAD")

    End Sub

[C#]

        void Yukleme_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)

        {

            Label1.FontSource = new FontSource(e.Result);

            Label1.FontFamily = new FontFamily("DEVELOAD");

        }

Veri sunucudan geldiğinde, download işlemi bittiğinde çalışan event-handler içerisinde hemen elimizdeki TextBlock olan Label1 adındaki kontrolün FontSource özelliğini değiştiriyoruz. Tanımladığımız yeni FontSource veri kaynağını e.Result ile alıyor, yani WebClient'ın indirdiği Stream'i doğrudan FontSource'a çevirerek TextBlock'a aktarıyoruz. Son olarak tabi ki TextBlock'un FontFamily özelliğini de uygun şekilde değiştirmemiz gerek.

İsterseniz WebClient nesnesinin DownloadProgressChanged durumuna da bir event-handlar bağlayarak Fontların yüklenmesi esnasında yüklemenin ne kadarının tamamlandığını da takip edebilirsiniz.

Hepinize kolay gelsin.

Monday, June 30, 2008 1:14:10 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, June 29, 2008

Birden çok dil kullanılan projelerde .NET ile beraber gelen dahili Localization özellikleri hızlı çözümler yaratmak adına ciddi birer kurtarıcı olarak değerlendirilebilir. Kişisel olarak her zaman daha özelleştirilebilir altyapılara sahip olmak adına el yapımı altyapıları tercih etsem de her zaman bunun için zaman bulunamayabiliyor. Silverlight 2.0 ile beraber de artık .NET dillerini ve altyapısını kullanabildiğimize göre bize yardımcı olacak bir Localization sistemi olsa gerek diyerek beraberce yola çıkalım. Ürün Beta 2 aşamasında olduğu için bazı sorunları radikal çözümlerle atlatacağız fakat sonunda tabi ki çalışır bir örneğimiz olacak.

Yeni bir Silverlight 2.0 Beta 2 projesi yarattıktan sonra hemen Visual Studio içerisindeki Solution Explorer penceresinde Silverlight projemize sağ tuş tıklayarak "Add / New Folder" diyelim ve Resources adında bir klasör ekleyelim. Uygulamamızda olmasını istediğimiz dillere ait bilgileri bu klasör içerisine yerleştireceğiz. Resources klasörüne sağ tuş ile tıklayarak gelen menünden "Add / New Item" komutunu vererek yazilar.resx adında bir "Resources File" ekleyelim. Karşınıza çıkan ekranda Resource dosyası içerisine istediğiniz "Name / Value" çiftini girebilirsiniz. Şimdilik örnek olması amacıyla aşağıdaki şekilde düzenlememizi yapalım.

Localization Resource dosyamız.
İngilizce Localization Resource dosyamız.

Unutmamanız gereken detaylardan biri dosya ile ilgili Access Modifiers ayarsını Public olarak değiştirmek. Bu ayarı yaptığımızda aslında arka planda otomatik olarak değişmesi gereken bir kod daha var. Söz konusu kod Resource dosyamızla beraber otomatik olarak yaratılan Designer.vb veya Designer.cs dosyası içerisinde yer alıyor.

Arkaplandaki sinsi kod dosyası!
Arkaplandaki sinsi kod dosyası!

Yukarıdaki ekran görüntüsünde de görebileceğiniz üzere Visual Studio içerisinde Solution Explorer'da "Show All Files" düğmesine tıkladığınızda karşınıza ek dosyalar çıkacaktır. Bu dosyalardan Resource dosyamızın arkasında durdan VB/CS dosyasını açarak aşağıdaki kodları değiştirmemiz gerekiyor.

EskisiYenisi

[VB]

        Friend Sub New()

            MyBase.New()

        End Sub

[VB]

        Public Sub New()

            MyBase.New()

        End Sub

[C#]

        internal yazilar() {

        }

[C#]

        public Resource1() {

        }

Artık sıra geldi bu Resource dosyası içerisindeki verileri Silverlight XAML sayfalarımızda kullanmaya. Bunun için Page.XAML dosyamızı açarak hemen Root XML elementimize yeni bir XML NameSpace eklememiz şart.

<UserControl x:Class="SilverlightApplication31.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:yerel="clr-namespace:SilverlightApplication31.My.Resources"

   Width="400" Height="300">

Yukarıdaki şekli ile eklediğimiz NameSpace aslında Intellisense desteği sayesinde otomatik olarak karşınıza çıkacaktır. Eğer herhangi bir hata alırsanız projenizi bir kereliğine Build ederek sonra tekrar deneyin. NameSpace'in ismini tanımlamak tamamen size kalmış ben örnekte "yerel" anahtar kelimesini kullanmayı tercih ettim. Son olarak aşağıdaki kod ile Assembly içerisinden kullanacağımız kaynağımızı da sayfanın Resource'ları içerisine ekleyelim.

    <UserControl.Resources>

        <yerel:yazilar x:Name="LocStrings" />

    </UserControl.Resources>

Dillere göre metinleri görebilmek için uygulamamızın arayüzüne iki adet TextBlock koymakta fayda var. TextBlock'ları da koyduğumuzda uygulamanın XAML kodu aşağıdaki şekilde sonuçlanıyor.

<UserControl x:Class="SilverlightApplication31.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:yerel="clr-namespace:SilverlightApplication31.My.Resources"

   Width="400" Height="300">

    <UserControl.Resources>

        <yerel:yazilar x:Name="Kaynak" />

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBlock Height="40" HorizontalAlignment="Left" Margin="40,40,0,0" VerticalAlignment="Top" Width="160" Text="TextBlock" TextWrapping="Wrap" x:Name="Label1"/>

        <TextBlock HorizontalAlignment="Left" Margin="40,120,0,140" Width="160" Text="TextBlock" TextWrapping="Wrap" x:Name="Label2"/>

    </Grid>

</UserControl>

Resource'lar içerisindeki bilgileri bu TextBlock'lara bağlamamız gerek. Bunun için klasik bir Binding kullanırken veri kaynağı olarak da sayfanın Resource'larına eklediğimiz Kaynak adındaki veri kaynağımızı kullanacağız.

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBlock Height="40" HorizontalAlignment="Left" Margin="40,40,0,0" VerticalAlignment="Top" Width="160" Text="{Binding Baslik, Source={StaticResource Kaynak}}" TextWrapping="Wrap" x:Name="Label1"/>

        <TextBlock HorizontalAlignment="Left" Margin="40,120,0,140" Width="160" Text="{Binding Metin, Source={StaticResource Kaynak}}" TextWrapping="Wrap" x:Name="Label2"/>

    </Grid>

Bağlama işlemini de tamamladığımıza göre geri kaldı ikinci bir dil için Resource dosyası oluşturmaya. Elde olan yazilar.resx dosyasından bir kopya alarak yaziler.tr.resx adında bir dosya yaratabilirsiniz. Bu dosya içerisinde de yine Baslik ve Metin kaynaklarının Türkçe karşılıklarını yazmamız gerekecek.

Localization Resource dosyamız.
Türkçe Localization Resource dosyamız.

Artık neredeyse her şey hazır. Fakat ufak bir sorunumuz daha var. Visual Studio bizim için Silverlight projemizin Bin/Debug klasöründe gerekli dillere özel klasörleri yaratarak DLL'leri yaratsa da maalesef bunları Silverlight'ın XAP dosyasına kopyalamıyor. Bu ufak hata Silverlight'ın Beta 2 sonrası sürümlerinde düzeltilene kadar bizim Silverlight projemizin .proj uzantılı dosyasını NotePad ile açarak elle düzenlememiz gerekiyor.

    <SupportedCultures>tr</SupportedCultures>

Yukarıda gördüğünüz şekilde PROJ dosyası içerisinde normalde içi boş olan bu tagların arasında kullanacağımız dillerin dil kodlarını sıralamamız şart. Tüm işlemlerimizi tamamladık, artık Silverlight uygulamasını sayfaya yerleştirirken hangi dil ayarını parametre olarak aktarırsanız o dile uygun kaynaklar yüklenecektir.

        <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">

            <param name="source" value="ClientBin/SilverlightApplication31.xap"/>

            <param name="background" value="white" />

            <param name="culture" value="tr" />

            <param name="uiculture" value="tr" />

        </object>

Yukarıdaki kod içerisinde uygulamanın Türkçe ayarlar ile açılmasını sağlıyoruz.

Hepinize kolay gelsin.

Sunday, June 29, 2008 10:04:45 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Silverlight 2.0  | 
 Saturday, June 28, 2008

Bugün riatalks.com aktivitesindeydim. RIA (Rich Internet Application) konusu çerçevesinde gerçekleştirilen aktivite serisinde benim de ufak bir Silverlight konuşmam oldu. Çok fazla teknik içeriği olmayan zevkli bir aktiviteydi. Hatta yarın da aktivite devam ediyor olacak.

RIATALKS aktivitesinden bir kare...
RIATALKS aktivitesinden bir kare...

Özellikle RIA konusunda bir vizyon edinmek isteyenler Bahçeşehir Üniversitesi'nde düzenlenen aktiviteye katılmalarını tavsiye ederim.

Saturday, June 28, 2008 10:30:40 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Seminer | Silverlight | Silverlight 2.0  | 
 Friday, June 27, 2008

Son iki gündür Dubai'deydim. Microsoft Dubai tarafından iş ortakları için düzenlenen Silverlight 2.0 eğitimini sundum. Gerçekten muhteşem bir yazılımcı kitlesi ile karşılaştım. Silverlight konusunda ilgileri ve Flash konusunda bilgileri şaşırtıcıydı. Her şey o kadar rahat yerli yerine oturdu ki ben daha gösterdiğim özelliklerden hangisi nerede kullanabileceklerini anlatmadan onlar Silverlight'ın hangi senaryolarda çok daha uygun bir çözüm olabileceğini çözüp bana tavsiyelerde bulunmaya başladılar :) Ben de üzerine örnekleri sıraladım ve gerçek zamanlı olarak uygun örnekleri de derste yaptık. Şu ana kadar yaşadığım "eğitim verme" deneyimleri arasında en ilginçlerinden birini yaşadım diyebilirim.

Microsoft Dubai binası.
Microsoft Dubai binası.

Bu sefer eğitim sonunda toplu fotoğraf çekildik fakat çeken arkadaş hala mail atmadı :) Her zamanki gibi bu bana ders oldu :) Her neyse ben de şimdilik sizinle Microsoft Dubai binasının bir fotoğrafını paylaşıyorum.

Dubai ilginç bir şehir, modernlik konusunda söylenecek pek bir şey yok, ciddi anlamda maddi rahatlık olduğu kesin. Diğer yandan hala hava sıcaklığı 45 derecenin altına inmiyor, o nedenle en azından benim yaşayabileceğim bir ortam pek değil. Fakat alışveriş, özellikle elektronik alışverişi konusunda süper bir cennet Dubai. Ürüne ve modelinin yeniliğine göre yaklaşık Türkiye ile %15 ile %40 arası fiyat farkı var. Yoldan çıkmayıp kredi kartı limitlerini doldurmamak çok zor :)

Yarın Türkiye'de Riatalks.com aktivitesinde olacağım, hepinizi beklerim.

Not:Toplu fotoğraf elime ulaştı ;)

Microsoft Dubai Silverlight 2.0 Eğitimi Sonu
Microsoft Dubai Silverlight 2.0 Eğitimi Sonu

Friday, June 27, 2008 1:14:37 AM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Eğitimler | Silverlight 2.0  | 
 Thursday, June 26, 2008

Özellikle dikdörtgen köşelere sahip olmayan Silverlight uygulamalarında sayfanın fonunun Silverlight'ın fonunda da gözükmesini isteyebilirsiniz. Aslında basit bir şekilde Silverlight 2.0 Beta 2 uygulamasının fonunu şeffaf yapabilsek sorunumuz çözülmüş olacaktır. Bunun için yapmamız gereken ufak bir kaç ayar var.

Eğer bir ASP.NET sayfasında Silverlight sunucu kontrolünü kullanıyorsanız aşağıdaki şekilde PluginBackground özelliğini Transparent ve Windowless özelliğini de True olarak ayarlamanız yeterli olacaktır. ASP.NET Silverlight sunucu kontrolü gerekli HTML içeriği sizin için üretecektir.

            <asp:Silverlight PluginBackground="Transparent" Windowless="true"

            ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication29.xap"

            MinimumVersion="2.0.30523" Width="100%" Height="100%" />

Eğer Silverlight uygulamanızı ASP.NET dışı bir sayfada kullanacaksanız bu sefer söz konusu parametreleri OBJECT tagları arasında belirtmeniz gerekiyor.

        <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="100%" height="100%">

            <param name="source" value="ClientBin/SilverlightApplication29.xap"/>

            <param name="onerror" value="onSilverlightError" />

            <param name="background" value="Transparent" />

            <param name="pluginbackground" value="Transparent" />

            <param name="windowless" value="true" />

            <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

            </a>

        </object>

Tabi tüm bunları yaparken Silverlight uygulaması içerisinde Root görselinizin fonunun da şeffaf bırakıldığını kontrol etmekte fayda var.

Hepinize kolay gelsin.

Thursday, June 26, 2008 8:43:49 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Wednesday, June 25, 2008

Son üç gündür Qatar, Doha'da Microsoft Qatar için Aljazeera TV IT departmanın Silverlight 2.0 eğitimi veriyorum. Eğitim boyunca Silverlight 2.0 Beta 2 kullanarak birçok proje yapmakla beraber tabi ki ürün Beta olduğu için birçok da Bug bulduk :) Bunları da zamanla sizlerle blogdan paylaşıyor olacağım.

Eğitimi yaptığımız binadan TV yayını da yapıldığı için güvenlik nedeniyle fotoğraf çekilmesi yasaktı. O nedenle sizinle ancak bir gece yakaladığım Doha manzarasını paylaşabileceğim.

Qatar, Doha Gece Manzarası
Qatar, Doha Gece Manzarası

İlk defa bu kadar sıcak bir ülkeye seyahatim oldu, gerçekten dayanılır gibi değil. Sıcaklık 45 derecenin altına inmiyor. Sokakta yürürken kendimi "cehennemde" yanıyor gibi hissediyordum. Yine de üçüncü gün epey alışmış olduğumu söyleyebilirim. Şehrin %80'i inşaat alanı, yeni yapılanan bir şehir diyebiliriz. Ama benim güzelim ege sahillerim varken :) Doha'nın şansı biraz az. 4 mevsim ülkemizin değerini bilelim ;)

Wednesday, June 25, 2008 9:02:30 PM (GTB Standard Time, UTC+02:00)  #    Comments [4]   Eğitimler | Silverlight 2.0  | 
 Tuesday, June 24, 2008

Silverlight 2.0 ile beraber artık tüm yazdığımız kodların DLL olarak XAP dosyaları içerisinde istemciye gönderildiği bir ortamda harici DLL kütüphaneleri de kullanabiliyor olmak büyük avantajlar getiriyor. Tabi ki bu avantajlardan ürünün kendisi de faydalanıyor ve Silverlight 2.0 Beta 2 Runtime ve SDK ile beraber gelen çoğu harici kontrol normal şartlarda Expression Blend 2.5 içerisinde gözükmese de aslında DLL'ler şeklinde bilgisayarlarımızda bulunuyor. Bu yazımızda Silverlight 2.0 Runtime'ın ve SDK'nın derinliklerine inip bahsettiğimiz DLL'leri inceleyerek neler yapabileceğimize göz atacağız.

Silverlight Runtime yüklemesinde bilgisayarınızda C:\Program Files\Microsoft Silverlight\2.0.30523.6 konumuna yerleştirilecek olan DLL'leri söz konusu klasörü açarak bir inceleyelim.

Silverlight 2 Beta 2 Runtime DLL'leri.
Silverlight 2 Beta 2 Runtime DLL'leri.

Yukarıdaki DLL'lere baktığımızda özellikle eski VB sınıflarını desteklemek adına Microsoft.VisualBasic.dll'in Silverlight RunTime ile beraber de dağıtıldığını görüyoruz. Buradaki DLL'lerden bazılarına özellikle eğilmek gerekirse dikkati çekenler arasında System.XML.dll yer alıyor. Windows'takine kıyasla bu DLL içerisinde artık XSL veya XPath sınıfları bulunmuyor, tabi ki bunun çok mantıklı bir nedeni var; özellikle XPATH yerine artık elimizde XLINQ olduğu için bu sınıfları muhafaza etmek saçma olurdu. System.Core.dll ve System.Xml.Linq.dll işte tam bu noktada yardımımıza koşuyor ve LINQ'in neredeyse tüm özelliklerini Silverlight tarafına taşıyor. Son olarak System.Windows.Browser.dll ise bir Silverlight uygulamasının içerisinde bulunduğu tarayıcı ile ilgili işlemler yapabilmesi için gerekli sınıfları içeriyor.

Şimdi de gelin SDK ile beraber gelen DLL'lere göz atalım; bunun için bilgisayarınızda C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client klasörüne ufak bir yolculuk yapmanız yeterli olacaktır.

Silverlight 2 SDK paketindeki DLL Kütüphanaleri
Silverlight 2 SDK paketindeki DLL Kütüphanaleri

SDK içerisinde DLL'leri RunTime içerisindekilerden daha heyecan verici. İlk olarak IronPython ve IronRuby programlama altyapısını sunan DLL'lerini burada bulabiliyoruz. Tüm bu DLL'ler arasında bize DataGrid gibi farklı kontroller sunan DLL'ler ise System.Windows.Controls sınıfındaki dosyalar. System.Windows.Controls.dll içerisinde standart Silverlight kontrolleri, System.Windows.Controls.Extended.dll içerisinde Calendar, DatePicker, Slider, WatermarkedTextBox gibi kontroller, System.Windows.Controls.Data.dll içerisinde ise daha WPF'de bile olmayan DataGrid bulunuyor.

Tüm bu DLL kütüphaneleri Silverlight uygulamalarınız çalışması için hayati önem taşırken özellikle ek kontrolleri kullanabilmek adına gerekli DLL'leri projenize referans olarak da eklemeniz gerekecektir.

Hepinize kolay gelsin.

Tuesday, June 24, 2008 10:29:39 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, June 23, 2008

Silverlight 2.0 Beta 2 kullanarak analog bir saat gösterimi yapacağımız bu yazı içerisinde StoryBoard kullanımını ve StoryBoard'ların belirli zamanlara özel olarak konumlandırılmasını inceleyeceğiz. Gelin ilk olarak işin görsel tarafını halledelim ve Expression Blend 2.5 ile bir saat görseli yaratalım.

Saatimizde toplam üç adet dikdörtgene ihtiyacımız var. Bu dikdörtgenler saatin akrep, yelkovan ve saniye göstergesini temsil edecek. Ayrıca saatin ana gövdesini oluşturacak bir de Ellipse kullanacağız.

<UserControl x:Class="SilverlightApplication16.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">

    <Grid x:Name="LayoutRoot" Background="White">

        <Ellipse HorizontalAlignment="Stretch" Margin="0,0,120,20" VerticalAlignment="Stretch" Fill="#FFFF0000" Stroke="#FF000000" x:Name="Govde"/>

        <Rectangle Height="80" HorizontalAlignment="Left" Margin="136,59,0,0" VerticalAlignment="Top" Width="8" Fill="#FFFFFFFF" Stroke="#FF000000" x:Name="Saat"/>

        <Rectangle Height="107" HorizontalAlignment="Left" Margin="136,32,0,0" VerticalAlignment="Top" Width="8" Fill="#FF00C6FF" Stroke="#FF000000" x:Name="Dakika"/>

        <Rectangle Height="131" HorizontalAlignment="Left" Margin="136,8,0,0" VerticalAlignment="Top" Width="8" Fill="#FFD600FF" Stroke="#FF000000" x:Name="Saniye"/>

    </Grid>

</UserControl>

Bu noktadan sonra animasyonlarımızı hazırlamaya başlayalım. Saniyeyi gösterecek olan saat kolunun toplam 60 saniye içerisinde 360 derece dönmesi gerekiyor. Buna uygun animasyon yaratmadan önce tüm dikdörtgenlerimizin merkez noktasını saatin ortasına gelecek şekilde düzenleyelim. Böylece dikdörtgenler saatin merkez noktasın etrafında dönecektir.

<UserControl x:Class="SilverlightApplication16.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">

    <Grid x:Name="LayoutRoot" Background="White">

        <Ellipse HorizontalAlignment="Stretch" Margin="0,0,120,20" VerticalAlignment="Stretch" Fill="#FFFF0000" Stroke="#FF000000" x:Name="Govde"/>

        <Rectangle Height="80" HorizontalAlignment="Left" Margin="136,59,0,0" VerticalAlignment="Top" Width="8" RenderTransformOrigin="0.5,1" Fill="#FFFFFFFF" Stroke="#FF000000" x:Name="Saat"/>

        <Rectangle Height="107" HorizontalAlignment="Left" Margin="136,32,0,0" VerticalAlignment="Top" Width="8" RenderTransformOrigin="0.5,1" Fill="#FF00C6FF" Stroke="#FF000000" x:Name="Dakika"/>

        <Rectangle Height="131" HorizontalAlignment="Left" Margin="136,8,0,0" VerticalAlignment="Top" Width="8" RenderTransformOrigin="0.5,1" Fill="#FFD600FF" Stroke="#FF000000" x:Name="Saniye"/>

    </Grid>

</UserControl>

Uygulamamızın XAML kodunun son hali yukarıdaki şekilde. Hemen saniye koluna ait animasyonu hazırlayalım. SaniyeAnim adını vererek yeni bir StoryBoard yaratıyoruz ve söz konusu StoryBoard'un 60. saniyesinde saniye adındaki dikdörtgeni dönüş açısını 360 derece olarak tanımlıyoruz.

        <Storyboard x:Name="SaniyeAnim" RepeatBehavior="Forever">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Saniye" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">

                <SplineDoubleKeyFrame KeyTime="00:01:00" Value="360"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

Yukarıdaki animasyon içerisinde de gördüğünüz üzere ilk olarak animasyonun RepeatBehavior özelliğine Forever değerini vererek animasyonun sürekli tekrar edeceğini belirtiyoruz. Sonrasında Saniye dikdörtgenini hedef alan animasyon dikdörtgenin dönüş açısını bir dakika içinde 360 dereceye getiriyor.

Saniye kolu için yaptığımız animasyonlarla aynı mantıkta dakika ve saat kolları için de animasyonlar düzenleyeceğiz. Dakika kolu için düzenlediğimiz animasyon dakika kolunu 60 dakika içerisinde 360 derece döndürecek.

        <Storyboard x:Name="DakikaAnim" RepeatBehavior="Forever">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Dakika" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">

                <SplineDoubleKeyFrame KeyTime="01:00:00" Value="360"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

Son olarak saat kolu için düzenleyeceğimiz animasyonda da saat kolunu 12 saat içerisinde 360 derece döndüreceğiz.

        <Storyboard x:Name="SaatAnim" RepeatBehavior="Forever">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Saat" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">

                <SplineDoubleKeyFrame KeyTime="12:00:00" Value="360"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

Tüm bu animasyonlar çalıştığında saatimiz doğru bir şekilde işliyor olacak. Fakat esas mesele Silverlight uygulaması ilk açıldığında tüm saat kollarını doğru başlangıç noktalarına getirmek. Bunu yapabilmek için StoryBoard'ların Seek metodundan faydalanacağız. Seek metodu ile istediğimiz bir StoryBoard'u kendi içinde istediğimiz zaman aralığına getirebiliyoruz.

        SaniyeAnim.Begin()

        DakikaAnim.Begin()

        SaatAnim.Begin()

 

        SaniyeAnim.Seek(New TimeSpan(0, 0, Now.Second))

        DakikaAnim.Seek(New TimeSpan(0, Now.Minute, Now.Second))

        SaatAnim.Seek(New TimeSpan(Now.Hour, Now.Minute, Now.Second))

Yukarıdaki kodun başında tüm animasyonlarımızı hemen başlatıyoruz sonra da her animasyonu uygun başlangıç noktasına getirmek için Seek metodunu kullanıyoruz. Seek metoduna verdiğimiz TimeSpan parametresini yaratırken her bir kola uygun değerleri aktarıyoruz. Saniye koluna sadece içerisinde bulunduğumuz zamanın saniyesini, dakika koluna dakikayı ve saat koluna da saat bilgisini veriyoruz ve animasyonlarımız o konumdan gelerek oynamaya devam ediyor.

Saat uygulamamızı tamamladık, hepinize kolay gelsin.

Monday, June 23, 2008 10:08:26 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, June 22, 2008

Silverlight uygulamaları içerisinden "Clipboard"a ulaşmak istediğinizde maalesef hazır bir altyapı ile en azından şimdilik Silverlight 2.0 Beta 2 içerisinde karşılaşmıyoruz. Aynı şekilde Silverlight 1.0 içerisinde de bu sorun için bir çözüm yok. Fakat özellikle Silverlight 1.0 tarafında zaten JavaScript'in ana programlama yapısı olduğunu düşünürsek "Acaba tarayıcı içerisinde JavaScript ile bir çözüm oluşturabilir miyiz?" sorusu akla geliyor. Bu sorunun cevabı en azından Internet Explorer için "Evet". FireFox varsayılan ayarları ile bu gibi işlemlere JavaScript tarafında olanak tanımıyor.

Silverlight 1.0 ile Clipboard kullanımı

Yeni bir Silverlight 1.0 projesi yaratarak içerisine bir TextBlock ve Rectangle yerleştirelim. Yapacağım işlem TextBlock içerisinde yazılı metni Rectangle'a basıldığında ClipBoard'a taşımak olacak.

<Canvas

  xmlns="http://schemas.microsoft.com/client/2007"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="640" Height="480"

  Background="White"

  x:Name="Page">

  <TextBlock Width="274.242" Height="43.939" Canvas.Left="31.818" Canvas.Top="27.273" Text="Kopyalanacak Metin" TextWrapping="Wrap" x:Name="Etiket"/>

  <Rectangle MouseLeftButtonDown="Kopyala" Width="122.727" Height="43.939" Fill="#FFFF0000" Stroke="#FF000000" Canvas.Left="31.818" Canvas.Top="92.425" RadiusY="16.167" RadiusX="16.167" x:Name="Dugme"/>

</Canvas>

Yukarıdaki kod uygulamamızın görsel arayüzünü oluşturuyor. "Dugme" adındaki Rectangle nesnemizin MouseLeftButtonDown durumunda çalıştırılacak olan kodu birazdan yazacağız.

function Kopyala(sender)

{

    window.clipboardData.setData("text", sender.findName("Etiket").Text); 

}

Kodumuz içerisinde kullandığımız clipboardData sınıfı ile ilgili detaylara MSDN üzerinden ulaşabilirsiniz. setData metodu toplamda iki parametre alıyor; bunlardan ilki ClipBoard'a kopyalanacak olan verinin tipi, ikincisi ise kopyalanacak olan içeriğin ta kendisi. Aynı şekilde isterseniz ClipBoard'dan veri almak için getData metodunu da kullanabilirsiniz.

function Getir(sender)

{

    sender.findName("Etiket").Text = window.clipboardData.getData("text");   

}

getData metodu sadece ClipBoard'dan alacağı verinin tipini parametre olarak alarak geriye doğrudan elde ettiği veriyi döndürüyor.

Peki ya Silverlight 2.0 tarafında neler yapacağız?

Aslında çok farklı bir işlem yapmayacağız. Silverlight 2.0 Beta 2 tarafında da şimdilik JavaScript'in nimetlerinden faydalanmak zorundayız. O nedenle istemci tarafındaki VB veya C# kodumuz ile sayfanın JavaScript tarafındaki özelliklerine ulaşıp yine JavaScript tarafındaki metodlarını çalıştıracağız.

İlk olarak Silverlight 2.0 Beta 2 uygulamamızın arayüzünü aşağıdaki şekilde düzenleyelim.

<UserControl x:Class="SilverlightApplication14.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBox Height="40" HorizontalAlignment="Left" Margin="16,8,0,0" VerticalAlignment="Top" Width="120" Text="Herhangi bir Metin" TextWrapping="Wrap" x:Name="txtMetinKutusu"/>

        <Button Height="24" HorizontalAlignment="Left" Margin="16,72,0,0" VerticalAlignment="Top" Width="88" Content="Kopyala" x:Name="btnKopyala"/>

        <Button Height="24" HorizontalAlignment="Left" Margin="16,112,0,0" VerticalAlignment="Top" Width="88" Content="Yapıştır" x:Name="btnYapistir"/>

    </Grid>

</UserControl>

Bir TextBox ve iki Button'dan oluşan uygulamamızın ilk olarak kopyalama işlemini yapacak olan kodunu yazalım.

[VB]

    Private Sub btnKopyala_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnKopyala.Click

        Dim Clipboard As Browser.ScriptObject = Browser.HtmlPage.Window.GetProperty("clipboardData")

        Clipboard.Invoke("setData", "text", txtMetinKutusu.Text)

    End Sub

[C#]

        void btnKopyala_Click(object sender, RoutedEventArgs e)

        {

            System.Windows.Browser.ScriptObject Clipboard = (System.Windows.Browser.ScriptObject)System.Windows.Browser.HtmlPage.Window.GetProperty("clipboardData");

            Clipboard.Invoke("setData", "text", txtMetinKutusu.Text).ToString();

        }

Kodumuz içerisinde ilk olarak tarayıcının clipboardData sınıfını yakalamamız gerekiyor. Bunun için içerisinde olduğumuz tarayıcının (Browser) yine mevcut HTML sayfasının (HtmlPage) ait olduğu pencereyi (Window) yakalayıp onun üzerinden GetProperty ile clipboardData'yı alarak ScriptObject tipinde yarattığımız Clipboard değişkenimize aktarıyoruz. Sonrasında doğrudan değişkenimiz üzerinden Invoke diyerek aynı Reflection yapar gibi setData metodunu çalıştırıyoruz. Normal şartlarda JavaScript tarafına vereceğimiz parametreleri de yine Invoke metoduna aktarıyoruz. Böylece kopyalama işlemini tamamlamış olduk. Aynı şekilde ClipBoard'dan veri almayı da hemen getData ile yapabiliriz.

[VB]

    Private Sub btnYapistir_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnYapistir.Click

        Dim Clipboard As Browser.ScriptObject = Browser.HtmlPage.Window.GetProperty("clipboardData")

        txtMetinKutusu.Text = Clipboard.Invoke("getData", "text")

    End Sub

[C#]

        void btnYapistir_Click(object sender, RoutedEventArgs e)

        {

            System.Windows.Browser.ScriptObject Clipboard = (System.Windows.Browser.ScriptObject)System.Windows.Browser.HtmlPage.Window.GetProperty("clipboardData");

            txtMetinKutusu.Text = Clipboard.Invoke("getData", "text").ToString();

        }

Clipboard'dan veri alırken de aynı şekilde clipboardData nesnemizi yakaladıktan sonra bu sefer getData metodunu çalıştırıyoruz ve geriye dönen değeri de örneğimizde TextBox içerisine yazdırıyoruz.

C# kullananların haricen aşağıdaki şekilde uygulama başlangıcında Event-Handlar bağlantılarını yapmaları gerekecektir. VB kodlarındaki Handles keyword'ü ile bu işlem satır içinde yapılabildiği için ek olarak yazmak gerekmiyor.

[C#]

        public Page()

        {

            InitializeComponent();

            btnKopyala.Click += new RoutedEventHandler(btnKopyala_Click);

            btnYapistir.Click += new RoutedEventHandler(btnYapistir_Click);

        }

Böylece hem Silverlight 1.0 hem 2.0 içerisinde Clipboard'dan veri alarak veri aktarımı yapabildik. Tabi tüm bu işlemlerin sadece Internet Explorer içerisine olması üzücü. Diğer tarayıcılar için de geçerli olacak şekilde umarız ileride Silverlight Runtime içerisine standart işlevsellikler eklenir.

Hepinize kolay gelsin.

Sunday, June 22, 2008 12:19:37 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight | Silverlight 2.0  | 
 Wednesday, June 18, 2008

Silverlight 2.0 Beta 2 ile beraber gelen değişikliklerden biri de dinamik olarak Image nesneleri yaratmak ve bu nesnelere farklı resimler yüklemekle ilgili. Eskiden Beta 1 içerisinde sadece Source özelliğini değiştirerek resimleri dinamik olarak yükleyebiliyorken artık biraz daha uğraşmamız gerekiyor.

İlk olarak yeni bir Silverlight 2.0 Beta 2 projesi yaratarak projemize kullanacağımız resimleri ekleyelim. Sonrasında dinamik olarak bir Image nesnesi yaratıp içerisini ImageSource ile dolduruyoruz.

[VB]

Dim Foto As New Image

Dim Adres As New Uri("garden.jpg", UriKind.Relative)

Dim FotoKaynak As ImageSource = New System.Windows.Media.Imaging.BitmapImage(Adres)

Foto.SetValue(Image.SourceProperty, FotoKaynak)

Me.LayoutRoot.Children.Add(Foto)

[C#]

Image Foto = new Image();

Uri Adres = new Uri("garden.jpg", UriKind.Relative);

ImageSource FotoKaynak = new System.Windows.Media.Imaging.BitmapImage(Adres);

Foto.SetValue(Image.SourceProperty, FotoKaynak);

this.LayoutRoot.Children.Add(Foto);

Yukarıdaki kodumuzun ilk satırında yarattığım Silverlight Image nesnesini doldurmak için bir ImageSource'a ihtiyacımız var. Bunun için ilk olarak yükleyeceğimiz resim adresini Uri tipinde yaratıyoruz. Relative konumlandırma ile doğrudan uygulamanın içerisindeki resim dosyasını kullanacağız. Sonrasında elimizdeki Uri'den bir ImageSource yaratıyoruz ve bu ImageSource'u da Image nesnemizin SourcePropoerty'sine atıyoruz. Tüm bu işlemler tamamlandıktan sonra tabi ki eldeki Image Silverlight nesnesini de sahneye eklememiz lazım.

Peki ya proje harici bir resmi yüklemek istersek?

Harici resmin bulunduğu internet adresi üzerinden bir Uri yaratarak yukarıdaki kodun aynısını kullanabilirsiniz. Böylece uygulamanız söz konusu adresteki fotoğrafı yükleyecektir.

[VB]

Dim Adres As New Uri("www.alanadi.com/resim.jpg", UriKind.Absolute)

[C#]

Uri Adres = new Uri("www.alanadi.com/resim.jpg", UriKind.Absolute);

Hepinize kolay gelsin.

Wednesday, June 18, 2008 8:42:05 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, June 17, 2008

Silverlight 2.0 ile ilgili "Control Templating" yazılarımda Silverlight kontrollerinin bazılarının tasarımlarının nasıl değiştirilebileceğini gösterirken varsayılan tasarımları ile ilgili XAML kodlarını alabileceğimiz MSDN adreslerini de sizlerle paylaştım. Devam eden günlerde farklı kontrollerin tasarımı ile ilgili ek makaleler de hazırlayacağım. Fakat bazı durumlarda MSDN'e ulaşma şansınız olmayabilir veya MSDN içerisinde istediğiniz kontrolün tasarımı ile ilgili XAML kodunu bulamayabilirsiniz. Peki ne yapabiliriz?

Aslında bahsettiğimiz bütün tasarımlar sonuçta Silverlight Library içerisinde duruyor. Bu assembly içerisinden generic.xaml adındaki Resource'u dışarı çıkardığınız içerisinde tüm varsayılan tasarımlara ait XAML kaynağını bulabiliyorsunuz. Ama durun :) tüm bunları tek tek elle yapmanıza gerek yok. Bahsettiğim işleri otomatik olarak yaparak Silverlight 2.0 SDK yüklü bir makineden tüm varsayılan XAML tasarımlarını almanızı sağlayan uygulamayı ClickOnce ile buradan yükleyebilirsiniz. Böylece yeni sürümleri çıktığında program kendini otomatik olarak yenileyecektir.

Ayrıca programı aşağıdaki adresten de bilgisayarınıza indirebilirsiniz.

Silverlight Default Style Browser - 17062008_1.zip (20,46 KB)

Kolay gelsin...

Tuesday, June 17, 2008 2:57:24 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, June 12, 2008

Bugüne kadar Silverlight içerisinde herhangi bir düğme veya farklı bir kontrolün değişik durumlarında ayrı şekiller alması için maalesef birbirinden bağımsız animasyonlar hazırlayarak tek tek gerekli eventlar ile koddan eşleştirmemiz gerekiyordu. Örneğin bir düğmenin üzerine gelindiğinde kırmızı olması ve bunu ufak bir animasyonla yapması için ilk önce animasyonumuzu hazırlıyor sonra da düğmenin MouseOver event'ına event-handlar kodumuzu bağlayarak animasyonu elle çalıştırıyorduk. Bu şekilde çok sayıda proje yapıldı.

Oysa artık Silverlight 2.0 Beta 2 ile beraber karşımıza yepyeni bir sistem geliyor : VisualStateManager!

Artık bir nesnenin farklı durumlarında nasıl gözükeceğini önceden tanımlanmış durumlar için Expression Blend 2.5 arayüzünden ayarlayabiliyorsunuz. Silverlight bununla kalmayıp bu farklı durumlar arasında geçiş efektlerini kendisi otomatik olarak yaratarak otomatik olarak oynatabiliyor. Gelin biraz işin içine girip nasıl yapıldığına göz atalım.

Animasyonlu bir Button...

Expression Blend 2.5 içerisinde sahneye bir Button yerleştiriyoruz. Hedefimiz bu Button'un farklı durumlarda fon rengini değiştirmek. Örneğin fare ile üzerine geldiğimizde düğme kırmızı olsun. Peki bunu Expression Blend 2.5 içerisinde nasıl yapacağız?

Düğmemizi Template'ini düzenliyoruz.
Düğmemizi Template'ini düzenliyoruz.

İlk olarak sahnedeki düğmemizin "Template"'ini düzenlememiz lazım. Düğmemizin zaten hali hazırda bir tasarımı ve animasyonları var. Bunları projenizi çalıştırdığınızda görebilirsiniz. Düğmenin üzerine geldiğinizde rengi değişecektir. Biz tamamen sıfırdan bir düğme tasarlamayacağımız için "Edit Control Parts" menüsünden "Edit a Copy" seçeneğini kullanarak var olan tasarımın bir kopyasını alarak yola devam edeceğiz. Eğer sıfırdan bir düğme tasarlamak isterseniz bu ekranda "Create Empty" demeniz gerekecektir.

Düğme Template'imize bir isim verelim.
Düğme Template'imize bir isim verelim.

Düğmemizin "Template"'ini yaratırken Expression Blend bize minik bir soru soruyor. Şablonumuz bir "Resource" olarak yaratılacak ve projemizde istediğimiz bir isimle istediğimiz bir yere konabilecek. Bu ekranda eğer "Application" seçeneğini seçersen hazırlayacağımız şablonla ilgili tüm özellikleri tanımlayan XAML kodu projenin içerisinde App.XAML dosyası içerisinde saklanacaktır. Böylece şablonumuz aynı projedeki tüm Page'lerde kullanılabilecek. Eğer varsayılan ayar olan "This document" seçeneğini tercih ederseniz şablonla ilgili XAML kodları içerisinde çalıştığınız Page.XAML dosyasına kaydedilecektir. Bu durumda bu şablonu diğer Silverlight sayfalarınızda kullanmanız daha zor olacaktır. Son bir seçenek ise harici bir Resource.xaml dosyasında tüm kaynakları (şablonları) saklamak olabilir. "Resource dictionary" seçeneği üzerinden yeni bir XAML dosyası yaratarak saklayacağınız şablonlarınızı böylece birden fazla projede kullanabilirsiniz.

Biz şimdilik "This document" diyerek şablonumuza isim olarak da "DugmeStil" değerini verelim.

Düğmemizin farklı durumlarında tasarım değişiklikleri yapacağız.
Düğmemizin farklı durumlarında tasarım değişiklikleri yapacağız.

Yukarıdaki ekran görüntüsünde de inceleyebileceğiz üzere düğmemizin şablonuna girdiğimiz anda düğmemizle ilgili farklı durumların listelendiği bir "Interaction" penceresi Expression Blend içerisine ekleniyor. Buradan herhangi bir durumu fare ile seçtikten sonra düğme üzerinde yapmak istediğiniz görsel değişiklikleri gerçekleştirebilirsiniz.

Düğmemizin fon gölge rengini değiştiriyoruz.
Düğmemizin fon gölge rengini değiştiriyoruz.

Biz örneğimizde düğmenin üzerindeki mavi gölgenin rengini değiştirmeye çalışalım. Standart bir düğmenin fare ile üzerine geldiğinde alt tarafa doğru ek mavi bir gölge geliyor. Expression Blend içerisinde baktığımızda bu gölge "Background" adı verilen bir Rectangle ile sağlanmış. Söz konusu Rectangle'ın Fill rengi aşağıdaki gibi DataBound gözüküyor.

DataBound görsel değeri lokal bir değere aktarıyoruz.
DataBound görsel değeri lokal bir değere aktarıyoruz.

Yukarıdaki görselde Rectangle'ın Fill değerinin tanımlandığı bölgenin turuncu bir çizgi ile çevrelendiği görebilirsiniz. Bu durum söz konusu özelliğin bir sistem değişkenine bağlı olduğu anlamına geliyor. Biz bu değeri değiştirmek istediğimiz için Fill özelliğinde değerin bir kopyasını almak amacıyla "Fill"'in hemen yanındaki ufak kareye tıklayıp gelen menünden "Convert to Local Value" diyoruz. Artık söz konusu değer bizim şablon içerisine taşındı, böylece üzerinde istediğimiz değişikliği yapıp gölgeyi kırmızı hale getirebiliriz. Renk paletinden yeni bir renk seçmeniz yeterli.

Transition efektlerini ve süreleri ayarlayalım.
Transition efektlerini ve süreleri ayarlayalım.

Normal şartlarda bir düğmenin üzerine geldiğinde yeni görsel duruma geçiş esnasında bir animasyon çalıştırılıyor, fakat fareyi düğmenin üzerinden çektiğinizde normal haline "anında" geçiyor yani herhangi bir animasyon çalıştırılmıyor. MouseOver durumundan Normal'e geçişte de bir animasyon çalıştırılmasını istiyorsanız hemen Blend arayüzünde "MouseOver" durumunun yanındaki oka tıklayarak gelen menüden "Mousevoer > Normal" seçeneğini seçerek bu geçiş esnasında da bir animasyon yaratılmasını istediğinizi belirtebilirsiniz. Böylece kırmızı hale geçişte ve eski hale dönüşte birer animasyon oynatılarak geçişler sağlanacaktır. Bu animasyonların sürelerini de hemen yanlarındaki 0.2s değerlerini düzenleyerek değiştirebilirsiniz.

Dikkat dikkat!

"MouseOver" veya "MouseLeave" gibi durumlarda görsel değişiklikler yaratırken aklınızda olması gereken ufak bir ipucu var. Animasyon uygulayacağınız nesnelerin her durumda sahnede yer alması gerekiyor. Yani sadece MouseOver durumunda gözükecek olan bir Rectangle'ın Normal durumdan MouseOver duruma bir animasyonda kullanılması mümkün olmaz. Görünmezden görünüre doğru bir animasyon tasarlayacak olsanız da hedef nesnenin hem başlangıç hem de son durumlarında sahnede bulunması gerekiyor. Tek yapacağınız başlangıç noktasında söz konusu nesneyi görünmez ayarlamaktır.

Şablon düzenleme modundan geri çıkalım.
Şablon düzenleme modundan geri çıkalım.

Arka planda neler oluyor?

Maalesef Expression Blend'in yaratmış olduğu tüm XAML kodunu burada yapıştırmayacağız, yaklaşık 180 satırlık bir kod söz konusu. Onun yerine özellikle bizim yaptığımız işlemleri ilgili kısmını buraya alarak bir inceleyelim.

<vsm:VisualStateGroup.Transitions>

  <vsm:VisualTransition Duration="00:00:00.5000000"

                        To="MouseOver"/>

  <vsm:VisualTransition Duration="0:0:0.1"

                        To="Pressed"/>

  <vsm:VisualTransition Duration="00:00:00.5000000"

                        From="MouseOver"

                        To="Normal"/>

</vsm:VisualStateGroup.Transitions>

<vsm:VisualState x:Name="Normal"/>

<vsm:VisualState x:Name="MouseOver">

  <Storyboard>

    <ColorAnimationUsingKeyFrames Duration="0"

                                  Storyboard.TargetName="BackgroundGradient"

                                  Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)">

      <SplineColorKeyFrame KeyTime="0"

                          Value="{StaticResource MouseOverLinearBevelDarkEndColor}"/>

    </ColorAnimationUsingKeyFrames>

    <ColorAnimationUsingKeyFrames BeginTime="00:00:00"

                                  Duration="00:00:00.0010000"

                                  Storyboard.TargetName="Background"

                                  Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">

      <SplineColorKeyFrame KeyTime="00:00:00"

                          Value="#FFFF0000"/>

    </ColorAnimationUsingKeyFrames>

  </Storyboard>

</vsm:VisualState>

Kod içerisinde de görebileceğiniz üzere MouseOver durumu içerisinde toplam iki adet animasyon var. Bunlardan biri Background'u diğeri de BackgroundGradient'i değiştiriyor. Adı Background olan animasyon bizim biraz önce Blend arayüzünden hazırladığımız animasyonun ta kendisi. Peki bu animasyon ne zaman nasıl çalıştırılacak? İşte tüm bunlara VisualStateGroup.Transitions tagları arasındaki bilgiler karar veriyor. Kaç saniyede hangi durumdan hangi duruma göre animasyonlar oynatılacağı doğrudan bu taglar arasında belirlenmiş durumda. Oynatılacak animasyonlar da zaten her durumun ismiyle ilişkilendirilmiş şekilde kod içerisinde duruyor.

Koddan geçişleri çalıştırmak istersek?

Bazı durumlarda hazırlanan bu animasyonları kod ile de çalıştırmak isteyebilirsiniz. Örneğin kullanıcının tıklaması gereken bir düğme vardır, fakat tıklamıyordur :) bu durumda sanki MouseOver olmuş gibi bir düğmeyi parlatıp söndürmek hoş olabilir.

[VB]

VisualStateManager.GoToState(Dugme, "MouseOver", true)

[C#]

VisualStateManager.GoToState(Dugme, "MouseOver", true);

Yukarıdaki kod ile Dugme adındaki düğmemizin MouseOver durmuna geçmesini ve arada gerekli animasyonun da oynatılmasını sağlamış oluyoruz. Eğer son Boolean parametreyi False olarak verirseniz geçiş animasyonu oynatılmaksızın söz konusu duruma geçilecektir.

Hepinize kolay gelsin.

Thursday, June 12, 2008 5:05:30 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, June 11, 2008

Özellikle Windows uygulamalarında "erişilebilirlik" açısından çok önemli olan noktalardan biri de "İpucu" balonlarıdır. "Tooltip" olarak geçen bu sistem sayesinde herhangi bir kontrolün veya nesnenin üzerinde fare ile belirli bir süre durduğunuzda gerekli açıklama metni gösterilir. Böylece kullanıcı ufak yardım yönergeleri ile yönlendirilebilir.

Silverlight 2.0 Beta 2 için Tooltip işlevselliğini otomatik olarak sağlayan bir TooltipService sınıfımız var. Gelin hemen bir örnekle konumuzu inceleyelim.

<UserControl x:Class="SilverlightApplication6.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <Button Margin="35,41,170,124"

            Content="Button"

            x:Name="Dugme">

      <ToolTipService.ToolTip>

        <ToolTip Content="Bu bir düğme"></ToolTip>

      </ToolTipService.ToolTip>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde bir düğmeye ToolTipService ekleyerek service de bir ToolTip kontrolü aktarıyoruz. ToolTip kontrolümüzün Content özelliğine bir metin aktararak ip ucu olarak bu metnin gösterilmesini sağlıyoruz. Bu şekilde istediğiniz Silverlight kontrolüne ToolTipService ekleyebilirsiniz.

Basit bir Tooltip.
Basit bir Tooltip.

Eğer Tooltip'in görünümünü değiştirmek isterseniz Background, FontSize, FontWeight, Foreground gibi birçok özelliğe sahipsiniz. İsterseniz fon rengi gibi özelliklere farklı Brush yapıları da aktarabilirsiniz.

<UserControl x:Class="SilverlightApplication6.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <Button Margin="35,41,170,124"

            Content="Button"

            x:Name="Dugme">

      <ToolTipService.ToolTip>

        <ToolTip Content="Bu bir düğme">

          <ToolTip.Background>

            <LinearGradientBrush EndPoint="0.5,1"

                                StartPoint="0.5,0">

              <GradientStop Color="#FF000000" />

              <GradientStop Color="#FFFFFFFF"

                            Offset="1" />

            </LinearGradientBrush>

          </ToolTip.Background>

          <ToolTip.BorderBrush>

            <LinearGradientBrush EndPoint="0.519999980926514,-0.0670000016689301"

                                StartPoint="0.519999980926514,0.899999976158142">

              <GradientStop Color="#FF000000" />

              <GradientStop Color="#FFFFFFFF"

                            Offset="1" />

            </LinearGradientBrush>

          </ToolTip.BorderBrush>

        </ToolTip>

      </ToolTipService.ToolTip>

    </Button>

  </Grid>

</UserControl>

Görüldüğü üzere rahatlıkla Tooltip'in görselliği değiştirilebiliyor. Bir Tooltip'in fonuna VideoBrush yerleştirmeye sizin hayallerinize bırakıyorum. Tooltip'e ait VerticalOffset ve HorizontalOffset özellikleri ile Tooltip'in fareden ne kadar uzakta gözükeceğini de ayarlayabilirsiniz.

Özelleştirilmiş Tooltip
Özelleştirilmiş Tooltip

Biraz daha ileri giderek ToolTip'in Content özelliğine istersek farklı Silverlight kontrolleri de yerleştirebiliriz. Content içerisine sadece bir Silverlight kontrolü yerleştirebilirsiniz fakat bu kontrolün içerisinde başka kontroller bulunabilir, yani Canvas veya Grid gibi Container kontrollerini kullanarak farklı görsel şemalar yaratabilirsiniz. Aşağıdaki kod içerisinde biraz olayı abartarak ToolTip içerisine bir video yerleştirdik.

<UserControl x:Class="SilverlightApplication6.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <Button Margin="35,41,170,124"

            x:Name="Dugme"

            Content="TIKLA">

      <ToolTipService.ToolTip>

        <ToolTip>

          <ToolTip.Content>

            <MediaElement Height="66"

                          VerticalAlignment="Bottom"

                          Source="http://localhost:49167/SilverlightApplication6Web/Bear.wmv"

                          Stretch="Fill" />

          </ToolTip.Content>

        </ToolTip>

      </ToolTipService.ToolTip>

    </Button>

  </Grid>

</UserControl>

Tooltip içerisinde stream video!
Tooltip içerisinde stream video!

Özel Tooltip!

Tooltip kontrolünün içerisinde gösterilecek Content'i değiştirmenin yanı sıra tamamen Tooltip'in görsel durumunu da değiştirebiliriz. Örneğin yuvarlak bir Tooltip yapılabilir. Bunun için ilk olarak Tooltip kontrolünün varsayılan Template yapısını MSDN üzerinden almamız gerekiyor. Adres şu şekilde; http://msdn.microsoft.com/en-us/library/cc296244(VS.95).aspx

Elimizdeki Template içerisindeki ControlTemplate tagları arasındaki herşey bizim Tooltip'in görüntü şablonunu oluşturuyor. Buradaki Binding'lere dokunmamaya çalışıyoruz. Özellikle ContentPresenter'ı silmememiz gerekiyor çünkü ToolTip'in Content'ına verilen içerik Template içerisinde buraya yerleştiriliyor olacak.

Gelin farklı bir şey yapalım ve kendi içine konan metni Scrollbar ile gösterebilen bir Tooltip oluşturalım. Bunun için hemen ControlTemplate'i düzenlememiz gerekiyor.

<UserControl x:Class="SilverlightApplication6.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <UserControl.Resources>

    <Style x:Key="ToolTipStili"

          TargetType="ToolTip">

      <Setter Property="Foreground"

              Value="#FF313131" />

      <Setter Property="FontSize"

              Value="11" />

      <Setter Property="Background">

        <Setter.Value>

          <LinearGradientBrush x:Name="ToolTipBackground"

                              StartPoint="0,0"

                              EndPoint="0,1">

            <LinearGradientBrush.GradientStops>

              <GradientStop Color="#FFF9FAFA"

                            Offset="0" />

              <GradientStop Color="#FFEDF1F4"

                            Offset="0.37259" />

              <GradientStop Color="#FFE2E8EF"

                            Offset="0.372881" />

              <GradientStop Color="#FFC3C9CD"

                            Offset="1" />

            </LinearGradientBrush.GradientStops>

          </LinearGradientBrush>

        </Setter.Value>

      </Setter>

      <Setter Property="Template">

        <Setter.Value>

          <ControlTemplate TargetType="ToolTip">

            <ScrollViewer Height="30"

                          Width="100"

                          Background="WhiteSmoke">

              <ScrollViewer.Content>

                <ContentPresenter Content="{TemplateBinding Content}"

                                  ContentTemplate="{TemplateBinding ContentTemplate}"

                                  Cursor="{TemplateBinding Cursor}"

                                  FontFamily="{TemplateBinding FontFamily}"

                                  FontSize="{TemplateBinding FontSize}"

                                  FontStretch="{TemplateBinding FontStretch}"

                                  FontStyle="{TemplateBinding FontStyle}"

                                  FontWeight="{TemplateBinding FontWeight}"

                                  Foreground="{TemplateBinding Foreground}"

                                  HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"

                                  Padding="{TemplateBinding Padding}"

                                  TextAlignment="{TemplateBinding TextAlignment}"

                                  TextDecorations="{TemplateBinding TextDecorations}"

                                  TextWrapping="{TemplateBinding TextWrapping}"

                                  VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />

              </ScrollViewer.Content>

            </ScrollViewer>

          </ControlTemplate>

        </Setter.Value>

      </Setter>

    </Style>

  </UserControl.Resources>

  <Grid x:Name="LayoutRoot"

        Background="White">

    <Button Margin="35,41,170,124"

            x:Name="Dugme"

            Content="TIKLA">

      <ToolTipService.ToolTip>

        <ToolTip Style="{StaticResource ToolTipStili}"

                Content="Herhangi bir açıklama metni burada olabilirdi.">

        </ToolTip>

      </ToolTipService.ToolTip>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kodumuz içerisinde ControlTemplate'in doğrudan içine bir ScrollViewer yerleştirdik ve Template içerisinde ContentPresenter'ı da ScrollViewer'ın Content değerine aktardık. Böylece bu ToolTip kontrolüne aktarılan tüm Content bir ScrollViewer içerisinde gösterilecek.

Custom Tooltip
Custom Tooltip

Siz de bu şekilde farklı ToolTip kontrolleri tasarlayarak uygulamalarınıza kullanabilirsiniz.

Hepinize kolay gelsin.

Wednesday, June 11, 2008 11:07:51 AM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Tuesday, June 10, 2008

Silverlight 2.0 Beta 1 ile beraber gelen DataGrid kontrolünün ana yapılarını daha önce incelemiştik. Bu yazımızda da Silverlight 2.0 Beta 2 ile beraber gelen DataGrid yeniliklerine göz atacağız.

Sıralama İşlemleri

Maalesef Silverlight 2.0 Beta 1 ile beraber gelen DataGrid içerisinde herhangi bir otomatik sıralama yapısı gelmiyordu. Oysa çoğu ASP.NET'teki GridView'den de alışık olduğumuz üzere bazı durumlarda kolonların en üst başlık kısımlarını tıklanabilir hale getirerek kolon içerisindeki veriye göre satırları sıralatabiliyor olmak çok önemli bir işlevsellik. Artık Silverlight 2.0 Beta 2 ile beraber gelen DataGrid içerisinde bu özelliği sağlayan hazır bir yapı var.

Peki neler yapmamız gerekiyor? Aslında yapmanız gereken neredeyse hiçbir şey yok. IList sınıfından türetilmiş herhangi bir listeyi DataGrid'e bağladığınızda sıralama (sorting) işlemleri otomatik olarak yapılabilecektir. Zaten baktığımızda DataGrid'lerimizi bu yapıyı destekleyen List veya ObservableCollection listeleri bağlıyoruz.

Normal şartlarda listeleme için kullanılan veri tıklanan kolona bağlı olan ve DisplayMemberBinding'de gözüken veri kaynağı oluyor. Oysa bazı durumlarda bu senaryo da düzgün çalışmayacaktır. Örneğin normal kolonlar yerine bir TemplateColumn kullanıyorsanız DisplayMember olmadığı için sıralama işlemi de yapılamayacaktır. Bu gibi durumlarda kolonun görsel kısmından bağımsız olarak SortMemberPath özelliğini ayarlayarak kolonda ne gözükürse gözüksün arka planda sıralama işleminin farklı bir kolona veya veriye göre yapılmasını sağlayabilirsiniz.

Görsel Değişiklikler

Özellikle listeleme işlemini yaptığınız kolonların başlıklarında oklar meydana gelecektir. Bu okların tasarımından tutun, meydana gelme animasyonlarına kadar her şeyi tek tek değiştirebilirsiniz. Bunun için MSDN'den aşağıdaki adresi incelemeniz yeterli olacaktır.

http://msdn.microsoft.com/tr-tr/library/cc278066(en-us,vs.95).aspx

Bu adreste hali hazırda DataGrid içerisinde kullanılan tüm kaynakların, stillerin ve animasyonların kodları bulunuyor. Bunları alıp özelleştirip rahatlıkla uygulamanıza ekleyebilirsiniz. Örneğin aşağıda sadece kolonların başlıklarına ait kısımların özelleştirildiği bir XAML kodunu inceleyebilirsiniz. Satır arası yorumlarıma özellikle dikkat etmenizde fayda var.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication5.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

    <UserControl.Resources>

        <Style x:Key="KolonBasi" TargetType="local:DataGridColumnHeader"

              xmlns:local="clr-namespace:System.Windows.Controls;

              assembly=System.Windows.Controls.Data"

              xmlns:controls="clr-namespace:System.Windows.Controls;

              assembly=System.Windows">

 

            <Setter Property="SeparatorBrush">

                <Setter.Value>

                    <SolidColorBrush Color="#FFA4A4A4" />

                </Setter.Value>

            </Setter>

            <Setter Property="SeparatorVisibility"

                    Value="Visible" />

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="local:DataGridColumnHeader">

                      <!-- Gridi boyayan Gradient. -->

                        <Grid Name="RootElement">

                            <Grid.Background>

                                <LinearGradientBrush StartPoint="0.276463,-0.00385181"

                                                    EndPoint="0.276463,0.71">

                                    <GradientStop Color="#FFF9FAFA"

                                                  Offset="0" />

                                    <GradientStop Name="StopColor2"

                                                  Color="#FFEDF1F4"

                                                  Offset="0.37259" />

                                    <GradientStop Name="StopColor3"

                                                  Color="#FFE2E8EF"

                                                  Offset="0.372881" />

                                    <GradientStop Name="StopColor4"

                                                  Color="#FFC3C9CD"

                                                  Offset="1" />

                                </LinearGradientBrush>

                            </Grid.Background>

 

                            <Grid.Resources>

                              <!-- Normal duruma getirme animasyonu. -->

                                <Storyboard x:Key="Normal State">

                                    <ColorAnimation Storyboard.TargetName="StopColor2"

                                                    Storyboard.TargetProperty="(Color)"

                                                    Duration="00:00:0.3"

                                                    To="#FFEDF1F4" />

                                    <ColorAnimation Storyboard.TargetName="StopColor3"

                                                    Storyboard.TargetProperty="(Color)"

                                                    Duration="00:00:0.3"

                                                    To="#FFE2E8EF" />

                                    <ColorAnimation Storyboard.TargetName="StopColor4"

                                                    Storyboard.TargetProperty="(Color)"

                                                    Duration="00:00:0.3"

                                                    To="#FFC3C9CD" />

                                </Storyboard>

                              <!-- Fare üzerine gelince çalışan animasyon. -->

                                <Storyboard x:Key="MouseOver State">

                                    <ColorAnimation Storyboard.TargetName="StopColor2"

                                                    Storyboard.TargetProperty="(Color)"

                                                    Duration="00:00:0.3"

                                                    To="#FFE6EFF7" />

                                    <ColorAnimation Storyboard.TargetName="StopColor3"

                                                    Storyboard.TargetProperty="(Color)"

                                                    Duration="00:00:0.3"

                                                    To="#FFD3E4F5" />

                                    <ColorAnimation Storyboard.TargetName="StopColor4"

                                                    Storyboard.TargetProperty="(Color)"

                                                    Duration="00:00:0.3"

                                                    To="#FF87A5BA" />

                                </Storyboard>

                              <!-- Sıralama bozulduğunda gösterilen animasyon. -->

                                <Storyboard x:Key="Unsorted State">

                                    <DoubleAnimation Storyboard.TargetName="SortIconElement"

                                                    Storyboard.TargetProperty="Opacity"

                                                    Duration="00:00:0.3"

                                                    To="0.0" />

                                    <DoubleAnimation Storyboard.TargetName="SortIconTransform"

                                                    Storyboard.TargetProperty="ScaleY"

                                                    BeginTime="00:00:0.3"

                                                    Duration="00:00:0.0"

                                                    To="1" />

                                </Storyboard>

                              <!-- Sıralama anındaki animasyon -->

                                <Storyboard x:Key="SortedAscending State">

                                    <DoubleAnimation Storyboard.TargetName="SortIconElement"

                                                    Storyboard.TargetProperty="Opacity"

                                                    Duration="00:00:0.3"

                                                    To="1.0" />

                                    <DoubleAnimation Storyboard.TargetName="SortIconTransform"

                                                    Storyboard.TargetProperty="ScaleY"

                                                    Duration="00:00:0.3"

                                                    To="-1" />

                                </Storyboard>

                              <!-- Sıralama anındaki animasyon -->

                                <Storyboard x:Key="SortedDescending State">

                                    <DoubleAnimation Storyboard.TargetName="SortIconElement"

                                                    Storyboard.TargetProperty="Opacity"

                                                    Duration="00:00:0.3"

                                                    To="1.0" />

                                    <DoubleAnimation Storyboard.TargetName="SortIconTransform"

                                                    Storyboard.TargetProperty="ScaleY"

                                                    Duration="00:00:0.3"

                                                    To="1" />

                                </Storyboard>

                            </Grid.Resources>

 

                            <Grid.RowDefinitions>

                                <RowDefinition Height="*" />

                                <RowDefinition Height="*" />

                                <RowDefinition Height="Auto" />

                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>

                                <ColumnDefinition Width="*" />

                                <ColumnDefinition Width="Auto" />

                                <ColumnDefinition Width="Auto" />

                            </Grid.ColumnDefinitions>

 

                            <Rectangle Stretch="Fill"

                                      StrokeThickness="2"

                                      Stroke="#FFFFFFFF"

                                      Grid.ColumnSpan="2"

                                      Grid.RowSpan="2" />

                            <Rectangle Grid.Row="2"

                                      Grid.ColumnSpan="3"

                                      Height="1"

                                      HorizontalAlignment="Stretch"

                                      Fill="#FFA4A4A4" />

                            <Rectangle Grid.RowSpan="2"

                                      Grid.Column="2"

                                      Width="1"

                                      VerticalAlignment="Stretch"

                                      Fill="{TemplateBinding SeparatorBrush}"

                                      Visibility="{TemplateBinding SeparatorVisibility}" />

                          <!-- Kolonun için kolon adı buraya yazılıyor Bind edilmiş -->

                            <controls:ContentPresenter Margin="3,0,3,0"

                                                      Content="{TemplateBinding Content}"

                                                      VerticalAlignment="Center" />

                          <!-- Sıralam oku görseli burada -->

                            <Path Name="SortIconElement"

                                  Margin="3,0,3,0"

                                  Opacity="0"

                                  Grid.Column="1"

                                  Stretch="Uniform"

                                  Width="8"

                                  Data="F1 M -5.215,0.0L 5.215,0.0L 0,6.099L -5.215,0.0 Z ">

                                <Path.Fill>

                                    <SolidColorBrush Color="#FF313131" />

                                </Path.Fill>

                                <Path.RenderTransform>

                                    <ScaleTransform Name="SortIconTransform"

                                                    CenterX="4"

                                                    CenterY="2.5"

                                                    ScaleX="1"

                                                    ScaleY="1" />

                                </Path.RenderTransform>

                            </Path>

                        </Grid>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

        </Style>

 

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot"

          Background="White">

        <!-- Stilimizi gride bağladık. -->

        <my:DataGrid x:Name="Veri"

                    ColumnHeaderStyle="{StaticResource KolonBasi}"

                    AutoGenerateColumns="False"

                    AlternatingRowBackground="#FFFFFF00"

                    HorizontalGridlinesBrush="#FFD4FF00"

                    RowBackground="#FFE3E3E3">

            <my:DataGrid.Columns>

                <my:DataGridTextColumn Header="Adi"

                                      DisplayMemberBinding="{Binding Adi}" />

            </my:DataGrid.Columns>

        </my:DataGrid>

    </Grid>

</UserControl>

Otomatik boyutlandırma

Yeni bir Silverlight uygulaması yarattığınızda sahnede yer alan LayoutRoot aslında bir Grid nesnesidir. Silverlight 2.0 Beta 1'den farklı olarak Beta 2 ile beraber gelen DataGrid'in kendi içerisindeki veriye göre kendini otomatik boyutlandırma şansı var. Varsayılan ayarları ilebir DataGrid yarattığınızda bu özellik açık geliyor. Tabi DataGrid'in istediği kadar büyüyebilmesi için uygun kontroller içerisine yerleştirilerek herhangi bir şekilde boyutlarının sınırlandırılmamış olması gerekiyor. Programatik olarak bir nesnenin yükseklik veya genişliğini otomatik olarak ayarlamak istiyorsanız Double.NaN 'a eşitlemeniz yeterli olacaktır.

DataGrid'in genişliğini otomatik olarak ayarlamanın yanı sıra artık kolonlar da içlerindeki veriye göre otomatik olarak boyutlandırılabiliyorlar. Bu boyutlandırma için ise 4 farklı teknik kullanılabiliyor. Birincisi "Auto" değerini vererek işlemi tamamen otomatiğe bırakmak, ikincisi SizeToHeader diyerek kolonun kendi başlığı kadar genişleyebilmesini sağlamak, üçüncüsü SizeToCells diyerek kolonun başlığından bağımsız olarak içeriğindeki veri kadar genişlemesini sağlamak ve dördüncüsü de doğrudan sayısal bir değer vererek kolonun genişliğini ayarlamak. Aşağıda örnek bir kullanımı görebilirsiniz.

<my:DataGrid x:Name="Veri"

            ColumnHeaderStyle="{StaticResource KolonBasi}"

            AutoGenerateColumns="False"

            AlternatingRowBackground="#FFFFFF00"

            HorizontalGridlinesBrush="#FFD4FF00"

            RowBackground="#FFE3E3E3">

  <my:DataGrid.Columns>

    <my:DataGridTextColumn Width="SizeToHeader"

                          Header="Adi"

                          DisplayMemberBinding="{Binding Adi}" />

  </my:DataGrid.Columns>

</my:DataGrid>

Aynı işlemi kod ile yaptığınızda ise doğrudan DataGridLength sınıfı üzerinden gerekli seçeneklere ulaşabiliyorsunuz. Sayısal bir değer atayarak kolonun genişliğini sabitlemek istediğinizde ise maalesef sizi ufak bir sorun bekliyor. Kolon genişliğini DataGridLength olarak atamanız lazım, integer veya double kesinlikle kabul edilmiyor. Bu durumda yardımımıza DataGridLengthConverter adında bir sınıf yetişiyor.

[VB]

kolon.Width = (New DataGridLengthConverter).ConvertFrom(50)

[C#]

kolon.Width = (DataGridLength)(new DataGridLengthConverter()).ConvertFrom(100);

DataGridLengthConverter sınıfındaki ConvertFrom metodu ile elimizdeki herhangi bir değişkenden DataGridLenght yaratarak kolonlarımızın genişliğini kod tarafından da düzenleyebiliyoruz.

Hepinize kolay gelsin.

Tuesday, June 10, 2008 9:00:37 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, June 09, 2008

Silverlight 2.0 Beta 2 ile beraber uygulamanızı hazırladınız ve kullandığınız kontrollerin görsel özelliklerini öyle bir ayarladınız ki istemci tarafında kullanıcı tarayıcı penceresinin boyutunu değiştirse de uygulamanız herhangi bir sorun yaşamıyor. Ama keşke programatik olarak da tarayıcının boyutu değiştiğinde haberim olsaydı diyorsanız işte size çözüm;

[VB]

Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

    AddHandler App.Current.Host.Content.Resized, AddressOf Resized

End Sub

[C#]

public Page()

{   

    InitializeComponent();   

    App.Current.Host.Content.Resized += new EventHandler(Resized);

}

Yukarıdaki şekliyle o an için geçerli olan uygulamanın içerisinde yer aldığı sunucu elementi bulup Resized durumunu yakalıyoruz. Aslında Resized durumundan bağımsız bir şekilde istediğiniz zaman Silverlight uygulamanızın içerisinde bulunduğu pencerenin boyutunu aşağıdaki kodlar ile alabilirsiniz.

[VB]

Private Sub Resized(ByVal sender As Object, ByVal e As System.EventArgs)

    Dim Yukseklik As Double = App.Current.Host.Content.ActualHeight

    Dim Genislik As Double = App.Current.Host.Content.ActualWidth

End Sub

[C#]

void Resized(object sender, EventArgs e)  

{  

    double yukseklik = App.Current.Host.Content.ActualHeight;  

    double genislik = App.Current.Host.Content.ActualWidth

}

Bu işlemi Resized event'ı içerisinde yaptığımızda ise internet tarayıcısının boyutları değiştiğinde yeni boyutları almış oluyoruz. Ufak bir uyarı yaparak yazımı tamamliyim, yukarıdaki kodların doğru çalışabilmesi için tarayıcı içerisinde Silverlight uygulamanızın %100 genişlik ve yükseliğe sahip olması gerekiyor. Aslına bakılırsa tarayıcı penceresinin değil Silverlight uygulamasının container'ının boyutunu alıyoruz o nedenle eğer Silverlight uygulamasının boyutları sayfada sınırlanmış olursa elimize sürekli aynı değerler ulaşacaktır.

Hepinize kolay gelsin.

Monday, June 09, 2008 9:13:32 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, June 08, 2008

Silverlight 2.0 Beta 2 ile beraber gelen yeni kontrollerden biri olan TabControl özellikle Windows uygulamalarından alışmış olduğumuz sayfalı uygulama tasarımlı ekranları web ortamında da rahatlıkla oluşturabilmemizi sağlıyor. System.Windows.Controls.Extended sınıfı altında bulunan TabControl'u kullanabilmek için projenize söz konusu sınıfı reference olarak eklemiş olmanız gerekiyor. Visual Studio içerisinde Silverlight projenize sağ tuş tıklayarak "Add Reference" dedikten sonra gerekli eklemeleri yapabilirsiniz. Visual Studio içerisinde araç çubuğundan bir TabControl alarak sahneye yerleştirdiğinizde de işlem otomatik olarak gerçekleşecektir. Referanslama kısmı tamamlandıktan sonra Expression Blend içerisinde de Asset Library'de Custom Controls kısmında projenize referans olarak eklediğiniz sınıfların altındaki kontrolleri bulabilirsiniz.

Expression Blend 2 June Preview içerisinde TabControl ve TabItem
Expression Blend 2 June Preview içerisinde TabControl ve TabItem

Expression Blend içerisinde sahneye bir TabControl yerleştirdikten sonra sıra geldi söz konusu TabControl içerisinde TabItem (sayfa) yerleştirmeye. Kolaylık olması açısından Blend içerisinde yerleştirmiş olduğunuz TabControl'a "Objects and Timeline" penceresinde çift tıklarsanız söz konusu kontrolün sarı bir çerçeve içerisine alındığını göreceksiniz. Bu şekilde herhangi bir kontrol sarı bir çerçeve ile işaretlendiğinde o kontrol dışında ekranda bulunan her şey kilitlenmiş olacaktır. Böylece rahatlıkla ekrana yerleştireceğimiz yeni TabItem kontrollerinin kesinlikle TabControl içerisine yerleştirileceğini garanti edebiliriz. Aksi halde fare ile kontrol eklerken özel olarak dikkat etmeniz gerekecektir.

<UserControl x:Class="SilverlightApplication3.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300"

            xmlns:System_Windows_Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended"

            xmlns:System_Windows_Controls_Primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Extended">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <System_Windows_Controls:TabControl HorizontalAlignment="Left"

                                        Margin="8,34,0,64"

                                        Width="184">

      <System_Windows_Controls:TabItem Content="TabItem"

                                      Header="Tab1"/>

      <System_Windows_Controls:TabItem Content="TabItem2"

                                      Header="Tab2"/>

    </System_Windows_Controls:TabControl>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde yerleştirdiğimiz TabControl ve TabItem'ların XML kodunda namespace olarak uzun uzun System_Windows_Controls adını gözüyorsunuz. Aslında bu yapıyı değiştirebiliriz; eğer dokümanın üzerindeki namespace isimlerini değiştirirseniz aynı isimleri kodunuz içerisinde de rahatlıkla kullanabilirsiniz.

TabItem'ların iki önemli özelliği var; bunlardan ilki Header yani TabItem'ım sayfa bilgisinin gözüktüğü yerde yazılacak olan yazı, diğeri ise Content yani TabItem'ın temsil ettiği sayfada gösterilecek olan içerik. Şimdi örneğimizdeki hem namespace'leri değiştirerek daha okunaklı bir isim verelim hem de TabItem'larımızın içerisine daha farklı içerikler yerleştirelim.

<UserControl x:Class="SilverlightApplication3.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300"

            xmlns:Ex="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended"

            xmlns:Pri="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Extended"

            xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <Ex:TabControl HorizontalAlignment="Left"

                  Margin="8,34,0,64"

                  Width="184">

      <Ex:TabItem>

        <Ex:TabItem.Header>

          <Grid>

            <Image HorizontalAlignment="Right"

                  Width="76"

                  Source="Dock.jpg"/>

            <TextBlock>Bölüm 1</TextBlock>

          </Grid>

        </Ex:TabItem.Header>

        <TextBlock>Deneme amaçlı metin</TextBlock>

      </Ex:TabItem>

      <Ex:TabItem Content="TabItem2"

                  Header="Tab2"/>

    </Ex:TabControl>

  </Grid>

</UserControl>

Kodumuz içerisinde yer alan TabItem'ın hem Header (başlık) kısmını hem de içeriğini özel olarak düzenliyoruz. <Ex:TabItem.Header> tagları arasında TabItem için header görseli olarak farklı Silverlight kontrolleri kullanabiliyoruz. Tek bir sınırlamamız var; Header içerisinde kök element sadece bir adet olabiliyor. Bu sorunu aşmak için Container Elementlerimizden Grid'i kullanabiliriz. Header içerisine yerleştirdiğimiz bir Grid içerisine istediğimiz kadar Silverlight kontrolü koyabiliriz. Header tagları haricinde doğrudan TabItem'ın içerisine de TabItem'ın sayfa içeriğinde gözükmesini istediğimiz kontrolleri koyabiliyoruz.

Özelleştirilmiş TabItem kontrolümüz karşımızda!
Özelleştirilmiş TabItem kontrolümüz karşımızda!

TabItem'ların Header'ları içerisine farklı Silverlight kontrollerini koymanın yanı sıra istersek Header'ın tamamen görsel şablonunu da değiştirebiliriz. Bunun için bir ControlTemplate hazırlayarak TabItem'ımıza bağlamamız gerekecek.

<UserControl x:Class="SilverlightApplication3.Page"

            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300"

            xmlns:Ex="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended"

            xmlns:Pri="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Extended"

            xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">

  <UserControl.Resources>

    <ControlTemplate x:Key="TabItemControlTemplate1"

                    TargetType="Ex:TabItem">

      <Grid>

        <Image HorizontalAlignment="Left"

              Width="100"

              Source="Forest.jpg"/>

        <ContentPresenter Content="{TemplateBinding Header}"/>

      </Grid>

    </ControlTemplate>

  </UserControl.Resources>

  <Grid x:Name="LayoutRoot"

        Background="White">

    <Ex:TabControl HorizontalAlignment="Left"

                  Margin="8,34,0,64"

                  Width="184">

      <Ex:TabItem Template="{StaticResource TabItemControlTemplate1}">

        <Ex:TabItem.Header>

          <Grid>

            <Image HorizontalAlignment="Right"

                  Width="76"

                  Source="Dock.jpg"/>

            <TextBlock>Bölüm 1</TextBlock>

          </Grid>

        </Ex:TabItem.Header>

        <TextBlock>Deneme amaçlı metin</TextBlock>

      </Ex:TabItem>

      <Ex:TabItem Content="TabItem2"

                  Header="Tab2"/>

    </Ex:TabControl>

  </Grid>

</UserControl>

Kodumuzda yarattığımız ControlTemplate içerisinde bir Grid ve onun içinde de bir Image ile ContentPresenter yer alıyor. Söz konusu ContentPresenter'ın Content özelliğini Template'in uygulanacağı kontrolün Header özelliğine bağlanmış. Böylece bu şablonu bağlı bir TabItem'ın Header'ına yerleştirilen kontrollerin bu şablon uygulandığında şablon içerisindeki ContentPresenter'ın içerisine yerleştirilecek. XAML kodunu çok uzatmamak adına örnekte sürekli Image nesneleri kullandığımız için ortaya çıkan örnek çok anlamlı olmayacaktır fakat Expression Blend içerisinde biraz daha detaylı bir çalışma ile güzel sonuçlar alınabilir.

Expression Blend 2 July Preview içerisinde Silverlight ControlTemplate desteği.
Expression Blend 2 July Preview içerisinde Silverlight ControlTemplate desteği.

Tüm bu yapıları tamamen XAML kodları yazarak oluşturabileceğiniz gibi Expression Blend içerisinde araçları kullanarak da yapabilirsiniz. Herhangi bir TabItem kontrolüne sağ tuş ile tıklayarak yukarıdaki şekilde "Edit Control Parts / Edit Template" diyerek TabItem'ların görselliklerini Blend içerisinde de ayarlayabilirsiniz. Her kontrol için ilk başta "Edit a Copy" diyerek var olan görsellikten bir şablon kopyası alarak veya "Create Empty" diyerek boş bir şablon yaratarak ilerleyebilirsiniz.

Son olarak her TabControl'ün bir de TabStripPlacement özelliği olduğundan bahsetmek gerek. Bu özelliğe verdiğiniz değerler ile TabItem'ların Header kısımlarının TabControl'ün üstünde, sağında, solunda veya altında gözükmesini sağlayabilirsiniz.

Hepinize kolay gelsin.

Sunday, June 08, 2008 6:25:49 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, June 07, 2008

Hafta sonuna gelmesi gerçekten muhteşem :) Ne kadar heyecanlı olduğumu anlatamam. Silverlight 2.0 Beta 2 ile beraber gelen yenilikler ve diğer Silverlight 2.0 yazılarımı sizlerle paylaşmaya devam edeceğim. Fakat onun öncesinde gelin hızlı bir şekilde Silverlight 2.0 Beta 2 ile beraber gelen yeniliklere bir göz atalım.

  • Runtime içerisinde daha çok kontrol var!
  • Go-Live lisansı geldi!

İlk olarak Silverlight 2.0 Beta 1 ile beraber Plug-In haricinde gelen ve her seferinde DLL dosyalarını XAP paketimize eklemek zorunda kaldığımız kontrollerin çoğunun artık Plug-In'e dahil edildiğine dair müjdeyi vermem gerek. Böylece artık Silverlight 2.0 uygulamalarımızın XAP paketleri çok daha küçük olacak. Diğer yandan Silverlight 2.0 Beta 2 ile beraber artık Go-Live lisansı da geliyor, yani artık yavaş yavaş ticari uygulamalara geçiş yapabilir, hazırladığınız uygulamaları müşterilerinize sunabilirsiniz. Tabi ileriki sürümlerde yine altyapıda değişiklikler olacaktır, ürün RTM olana kadar bu risk geçerli olacak.

  • TabPanel kontrolü geldi
  • Calendar kontrolünde yenilikler var! (Çoklu gün seçimi artık mümkün)
  • WPF'deki Control Templating desteği Expression Blend 2.5 June Preview içerisinde

Control Templating muhteşem bir esneklik sağlıyor. Bu konuda daha önce bir makale yazmıştım fakat herşeyi XAML kodundan elle yapmak zorunda kalmak pek hoş değil. Artık Expression Blend 2.5'in yeni sürümü olan June Preview ile beraber Silverlight 2.0 projeleri için de Control Templating desteği geliyor.

  • TextBox içerisinde Copy/Paste desteği
  • Tam ekran uygulamalarda klavyedeki oklar, tab, enter, "home", "end", boşluk, "pageup" ve "pagedown" tuşlarına ek destek. Eski sürümlerde hiçbir tuş desteklenmiyordu.
  • Adaptive Streaming
  • DRM

Video konusunda "adaptive streaming" gerçekten çok önemli. Otomatik olarak istemcideki işlemci kullanımını ve bant genişliğine göz önüne alarak hedef video kaynağında varsa farklı bitrate ayarlarındaki videoları otomatik olarak seçebilen bu sistem çok değerli bir altyapı sunuyor. Diğer yandan DRM (Digital Rights Management) da artık karşımızda; Windows DRM ve PlayReady DRM destekleniyor.

  • Visual State Manager

Muhteşem bir sistem! Artık her kontrolün farklı durumlarında ne şekilde gözükebileceğini tek tek Expression Blend 2.5'in arayüzünden ayarlayabiliyorsunuz. Örneğin bir Button'un MouseOver durumunda nasıl gözükeceğini ayarlıyorsunuz ve farklı durumlar arasında geçiş animasyonlarını da sistem otomatik olarak sizin için yapıyor. Eskiye kıyasla kontrollerin özelleştirilmesi gerçekten kolaylaştıracak olan bu sistem ileride WPF'e de aktarılacak. Aslında Silverlight WPF'in torunu olmasına karşın yine ilk olarak Silverlight içerisinde karşımıza çıkan ve sonradan WPF'e aktarılacak bir sistem ile karşı karşıyayız :)

  • Cross-Domain Request desteği
  • WCF üzerinden Duplex Bağlantı

Beta 2 ile beraber hem HTTP hem de Socket programlamada cross-domain desteği policy XML dosyaları aracılığı ile sağlanabiliyor. Ayrıca hali hazırda Flash'ın da kullanmakta olduğu XML policy dosyalarına destek bulunuyor. Sunucu tarafında Push veri alımı ile ilgili sadece Socket programlama bir alternatif olarak gözükürken artık WCF servislerinde de aynı yapı kullanılabiliyor.

  • .NET Framework 3.5 SP1 ile beraber gelecek olan ADO.NET Data Servisleri'ne tam destek
  • LINQ to JSON

Yeni çıkan ASP.NET 3.5 AJAX kitabımda da bahsetmiş olduğum LINQ sorguları ile JSON verilerinin sorgulanmasına ait sistemin bir benzeri Silverlight içerisinde de entegre edildi. Böylece hali hazırda JSON formatında veri kaynağı sağlayan servislerden gelen verileri çok daha rahat sorgulayabileceğiz.

  • DataGrid Yenilikleri : Kolon bazlı sıralama yapabilme, sürükle ve bırak tekniği ile kolonların yerlerinin değiştirilebilmesi.
  • Isolated Storage içerisinde uygulamaların sakladıklarına artık son kullanıcılar da Silverlight uygulamalarında sağ tuş ile tıklayarak gelen menüden ulaşabilecekler.

Tüm bu yeniliklerle ilgili ayrı ayrı makaleleri tabi ki sizlerle paylaşıyor olacağım. Bu gerçek bir yenilik ziyafeti :) developer olmayı işte bu yüzden çok seviyorum ;)

Download adresleri:

Silverlight 2.0 Beta 2 Runtime (4,66MB)
Microsoft Silverlight Tools Beta 2 for Visual Studio 2008 (84,3MB)
Expression Blend 2.5 June Preview (32,3MB)

Saturday, June 07, 2008 5:17:02 PM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Expression Blend | Silverlight 2.0  | 
 Friday, June 06, 2008

Silverlight 1.0 içerisinde JavaScript tarafında sahip olduğumuz createFromXaml metodu çoğu durumda işimizi kolaylaştırıyordu. Dinamik olarak yaratmak istediğimiz nesnelerin XAML kodunu bir kereliğine Blend ile yaratarak sonrasında söz konusu XAML kodunu programatik olarak String tipinde değiştirip doğrudan createFromXaml metoduna verdiğimizde istediğimiz tüm Silverlight nesnelerini gerekli özellikleri ile beraber almış oluyorduk. Silverlight 2.0 tarafında ise tüm nesneler artık birer .NET nesnesi olduğuna göre aslında bu nesnelerin yaratılarak sahneye yerleştirilmesi çok daha kolay gibi gözüküyor. Gelin ufak bir örnek yaparak durumu inceleyelim.

<Ellipse Height="57" HorizontalAlignment="Left" Margin="20,22,0,0" VerticalAlignment="Top" Width="64" Stroke="#FF000000">

  <Ellipse.Fill>

    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

      <GradientStop Color="#FF000000"/>

      <GradientStop Color="#FFFFFFFF" Offset="1"/>

    </LinearGradientBrush>

  </Ellipse.Fill>

</Ellipse>

Tasarımcımız Expression Blend ile yukarıdaki gibi özünde çok basit olan bir Ellipse tasarladığını düşünelim ve biz de bu Ellipse'in yükseklik ve genişlik özelliklerini elimizdeki herhangi bir veriye bağlı olmak şartı ile değiştirerek birden çok Ellipse yaratmaya çalışacağız. Bu noktada Silverlight 1.0 içerisinde createFromXaml kullanırken SL 2.0 içerisinde .NET nesneleri şeklinde gerekli işlemleri yaparak Ellipse'ler yaratmaya karar verirsek aşağıdaki kodu yazmamız gerekiyor.

[VB]

Dim Daire As New Ellipse

Daire.Height = 57

Daire.HorizontalAlignment = HorizontalAlignment.Left

Daire.Margin = New Thickness(20, 22, 0, 0)

Daire.VerticalAlignment = VerticalAlignment.Top

Daire.Width = 64

Daire.Stroke = New SolidColorBrush(Color.FromArgb(100, 0, 0, 0))

Dim GradientFirca As New LinearGradientBrush

GradientFirca.StartPoint = New Point(0.5, 0)

GradientFirca.EndPoint = New Point(0.5, 1)

Dim GradStop As New GradientStop

GradStop.Color = Color.FromArgb(100, 0, 0, 0)

GradientFirca.GradientStops.Add(GradStop)

GradStop = New GradientStop

GradStop.Color = Color.FromArgb(100, 255, 255, 255)

GradStop.Offset = 1

GradientFirca.GradientStops.Add(GradStop)

Daire.Fill = GradientFirca

Me.LayoutRoot.Children.Add(Daire)

[C#]

Ellipse Daire = new Ellipse();

Daire.Height = 57;

Daire.HorizontalAlignment = HorizontalAlignment.Left;

Daire.Margin = new Thickness(20, 22, 0, 0);

Daire.VerticalAlignment = VerticalAlignment.Top;

Daire.Width = 64;

Daire.Stroke = new SolidColorBrush(Color.FromArgb(100, 0, 0, 0));

LinearGradientBrush GradientFirca = new LinearGradientBrush();

GradientFirca.StartPoint = new Point(0.5, 0);

GradientFirca.EndPoint = new Point(0.5, 1);

GradientStop GradStop = new GradientStop();

GradStop.Color = Color.FromArgb(100, 0, 0, 0);

GradientFirca.GradientStops.Add(GradStop);

GradStop = new GradientStop();

GradStop.Color = Color.FromArgb(100, 255, 255, 255);

GradStop.Offset = 1;

GradientFirca.GradientStops.Add(GradStop);

Daire.Fill = GradientFirca;

this.LayoutRoot.Children.Add(Daire);

Gördüğünüz gibi aslında her şeyi .NET kodumuz ile de yapabiliyoruz fakat tasarımcının Blend içerisinde yapmış olduğu tasarımı yukarıdaki koda çevirmek ciddi "işkence" kıvamında. Tabi ki tasarımcının sahneye koyduğu nesnelerin özelliklerine tek tek erişerek .NET kodumuz ile değiştirebiliriz fakat şu anda yapmak istediğim bu nesnelerden programatik olarak birden çok yaratıp özelliklerini de ayarlayarak sahneye yerleştirmek.

Çözümlerden ilki UserControl yapısı; eğer yaratacağınız nesnelerin yapıları sabit ise yani büyük değişiklikler yoksa söz konusu yapıyı bir UserControl olarak tasarlayarak belirli özelliklerini değiştirip sahneye yerleştirebilirsiniz. Fakat bazı durumlardan UserControl yapısı da gerekli esnekliği sağlayamayabiliyor. İşte böyle durumlarda yardımımıza System.Windows.Markup.XamlReader.Load metodu yetişiyor. Bu metod Silverlight 1.0'da alışık olduğumuz createFromXaml metodu ile birebir aynı mantıkta çalışıyor. Parametre olarak aldığı String XAML kodundan bize Silverlight nesneleri yaratarak geri döndürüyor. Şimdi de aşağıdaki şekilde XAML kodumuzun dinamik olarak yaratıp Silverlight nesnemizi oluşturalım.

[VB]

Dim EllipseXAML = <Ellipse xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Height="57" HorizontalAlignment="Left" Margin="20,22,0,0" VerticalAlignment="Top" Width="64" Stroke="#FF000000">

                      <Ellipse.Fill>

                          <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                              <GradientStop Color="#FF000000"/>

                              <GradientStop Color="#FFFFFFFF" Offset="1"/>

                          </LinearGradientBrush>

                      </Ellipse.Fill>

                  </Ellipse>

[C#]

string EllipseXAML = "<Ellipse xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" Height=\"57\" Visibility=\"Collapsed\" HorizontalAlignment=\"Left\" Margin=\"20,22,0,0\" VerticalAlignment=\"Top\" Width=\"64\" Stroke=\"#FF000000\">" +

                        "<Ellipse.Fill>" +

                            "<LinearGradientBrush EndPoint=\"0.5,1\" StartPoint=\"0.5,0\">" +

                                "<GradientStop Color=\"#FF000000\"/>" +

                                "<GradientStop Color=\"#FFFFFFFF\" Offset=\"1\"/>" +

                            "</LinearGradientBrush>" +

                        "</Ellipse.Fill>" +

                    "</Ellipse>";

XAML kodumuzu VB veya C# kod tarafına alıp System.Windows.Markup.XamlReader.Load ile kullanacağımız zaman kopyaladığımız XAML kodu içerisinde kullanılan tüm XML namespace tanımlamalarını ana XAML dosyasından kopyalamış olmamız gerekiyor. Yukarıdaki kodlarda kalın yazılı kısımlar bu şekilde kopyalanmıştır.

LINQ ile beraber VB içerisinde "inline XML" yapısı geliyor, bu yapıyı Silverlight içerisinde de kullanabiliyoruz. Bunun için tek yapmamız gereken Silverlight projemize sağ tuş tıklayarak "Add Reference" diyip System.XML.Linq kütüphanesini projemize eklemek. Böylece artık tasarımcının Blend içerisinde düzenlemiş olduğu XAML kodunu doğrudan Silverlight içerisinde VB dosyamıza kopyalayabiliriz. C# içerisinde ise XAML kodumuzu bir string değişkene aktarabilmek için bolca escape char kullanmamız gerekiyor.

Sıra geldi yarattığımız XAML kodu içerisinde istediğimiz özellikleri değiştirmeye. VB içerisinde yarattığımız değişken doğrudan XAML aldığı ve bir XElement nesnesi oluşturduğu için XML içerisindeki özelliklere rahatlıkla ulaşabiliyoruz.

[VB]

EllipseXAML.@Width = 300

Maalesef C# içerisinde böyle bir şansımız yok. Bir seçenek olarak C# içerisinde tüm XAML kodunu harici bir dosyada tutup söz konusu harici dosyayı bir XML dosyasıymış gibi XDocument olarak yükleyerek kullanmak olabilir. Yukarıdaki şekliyle özelliklere doğrudan ulaşmanın yanı sıra istersek XAML kodunun içerisine ilk tanımlama esnasında da yerleştirebiliriz.

[VB]

Dim Yukseklik As Integer = 57

Dim EllipseXAML = <Ellipse xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Height=<%= Yukseklik %> HorizontalAlignment="Left" Margin="20,22,0,0" VerticalAlignment="Top" Width="64" Stroke="#FF000000">

                      <Ellipse.Fill>

                          <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                              <GradientStop Color="#FF000000"/>

                              <GradientStop Color="#FFFFFFFF" Offset="1"/>

                          </LinearGradientBrush>

                      </Ellipse.Fill>

                  </Ellipse>

[C#]

int Yukseklik = 57;

string EllipseXAML = "<Ellipse xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" Height=\"" + Yukseklik + "\" HorizontalAlignment=\"Left\" Margin=\"20,22,0,0\" VerticalAlignment=\"Top\" Width=\"64\" Stroke=\"#FF000000\">" +

                        "<Ellipse.Fill>" +

                            "<LinearGradientBrush EndPoint=\"0.5,1\" StartPoint=\"0.5,0\">" +

                                "<GradientStop Color=\"#FF000000\"/>" +

                                "<GradientStop Color=\"#FFFFFFFF\" Offset=\"1\"/>" +

                            "</LinearGradientBrush>" +

                        "</Ellipse.Fill>" +

                    "</Ellipse>";

Yukarıdaki kod içerisinde yarattığımız bir Integer değişkenin değerini kendi XAML kodumuzdaki Elipse'in yüksekliğine atıyoruz. VB içerisinde bu işlemi yine Inline XML tekniğini kullanarak yaparken C# içerisinde standart string işlemi olarak ilerlememiz gerekiyor.

Son olarak sıra geldi elimizdeki bu XAML kodundan nesnemizi yaratarak sahneye yerleştirmeye.

[VB]

Dim BirElips = System.Windows.Markup.XamlReader.Load(EllipseXAML.ToString)

Me.LayoutRoot.Children.Add(BirElips)

[C#]

var BirElips = System.Windows.Markup.XamlReader.Load(EllipseXAML);

this.LayoutRoot.Children.Add((UIElement)BirElips);

Örneğimizi tamamladık. Fakat eğer bir veriye bağlı olarak birden çok nesne yaratacak olsak nasıl olurdu? Hemen minik bir örnek ile onu da inceleyelim. Farklı yüksekliklerden birden çok Ellipse yaratabilmek için elimizdeki yüksekliklerin bir listesinin dizi olarak bulunduğunu varsayalım.

[VB]

Dim Yukseklik() As Integer = {57, 67, 80}

Dim EllipseXAML = <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

                      <%= From GelenVeri In Yukseklik Select <Ellipse xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Height=<%= GelenVeri %> HorizontalAlignment="Left" Margin="20,22,0,0" VerticalAlignment="Top" Width="64" Stroke="#FF000000">

                                                                <Ellipse.Fill>

                                                                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                                                                        <GradientStop Color="#FF000000"/>

                                                                        <GradientStop Color="#FFFFFFFF" Offset="1"/>

                                                                    </LinearGradientBrush>

                                                                </Ellipse.Fill>

                                                            </Ellipse> %>

                  </Canvas>

Dim BirElips = System.Windows.Markup.XamlReader.Load(EllipseXAML.ToString)

        Me.LayoutRoot.Children.Add(BirElips)

VB programcıları için biraz yeni bir yapı olduğu için ilk önce yukarıdaki VB kodumuzu inceleyelim. Her zamanki gibi yine VB içerisinde inline XML özelliklerinden faydalanıyoruz. Birden çok Ellipse'i doğrudan XamlReader.Load'a verme şansımız yok. XamlReader aynı SL 1.0'daki createFromXaml'da olduğu gibi sadece tek bir nesne geri döndürebiliyor. O nedenle tüm Ellipse'lerimizi bir Canvas içerisine yerleştiriyoruz. XamlReader bize içerisinde Ellipse'lerin bulunduğu Canvas nesnesini geri döndürecek. VB kodumuzda Canvas XML tagları arasında <%=%> işaretleri içerisinde bir LINQ sorgusu görüyorsunuz. Bu sorgu kodumuzun en üstündeki veri kaynağımız olan Yukseklik dizisini sorgulayarak kayıtları alıyor. Alınan her kayıt için yapılan Select işleminde ise geriye bir XML döndürülüyor. Doğal olarak bu XML bizim Ellipse'in XAML kodu olacak. Tüm bu işlemleri yaparken Select esnasında yarattığımız XAML'ın yüksekliğine de sorgunun çalıştığı satırdaki değeri, yani dizinin içerisindeki değeri yükseklik olarak atıyoruz. Böylece sorgumuz geriye yükseklikleri veri kaynağından alınarak ayarlanmış bir Ellipse serisini XML olarak döndürüyor. Bu dönen değeri Canvas tagları arasına alarak doğrudan EllipseXAML değişkenimize aktarıyoruz. İşlem tamam.

[C#]

int[] Yukseklik = {57, 67, 87};

 

string EllipseXAML = "<Canvas xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">" +

                        string.Join("", (from GelenVeri in Yukseklik

                                            select "<Ellipse xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" Height=\"" + GelenVeri + "\" HorizontalAlignment=\"Left\" Margin=\"20,22,0,0\" VerticalAlignment=\"Top\" Width=\"64\" Stroke=\"#FF000000\">" +

                                                "<Ellipse.Fill>" +

                                                    "<LinearGradientBrush EndPoint=\"0.5,1\" StartPoint=\"0.5,0\">" +

                                                        "<GradientStop Color=\"#FF000000\"/>" +

                                                        "<GradientStop Color=\"#FFFFFFFF\" Offset=\"1\"/>" +

                                                    "</LinearGradientBrush>" +

                                                "</Ellipse.Fill>" +

                                            "</Ellipse>").ToArray()) +

                                            "</Canvas>";

var BirElips = System.Windows.Markup.XamlReader.Load(EllipseXAML);

this.LayoutRoot.Children.Add((UIElement)BirElips);

C# kodumuza baktığımızda ise "inline XML" desteği olmadığı için yine String üzerinden gitmek durumunda kalıyoruz. XamlReader'a verilmek üzere tüm Ellipse'lerimizi ana bir Canvas içerisine alırken Ellipse üretimi için LINQ'ın sorgularının yardımını istiyoruz. C# içerisinde LINQ sorgumuz gerekli değerleri de XML içerisine yerleştirerek bir string dizisi üretiyor. Son olarak elde ettiğimiz XAML kodundan nesnelerimizi yaratıp sahneye yerleştiriyoruz.

Sonuç

Yukarıdaki teknikler ile farklı uygulamalarında tüm Silverlight nesnelerini en alt seviyeden müdahale ederek XAML üzerinden üretebilirsiniz. Fakat unutmamakta fayda var ki bu tarz yazılmış uygulamaların sonradan değiştirilmesi, yönetilmesi çok zor olacaktır. Örneğin tasarımcı yukarıdaki örneklerdeki Ellipse'in tasarımını değiştirmeye karar vermesi programcı sanırım intihara epeyce yaklaşacaktır. O nedenle XamlReader.Load tekniği olabildiğince en zor durumlarda, en sıkıştığınız anlarda kullanmakta fayda var. Normal şartlarda UserControl yapıları çoğu zaman gerekli çözümü sunacak ve daha rahat bir çalışma ortamı sağlayacaktır.

Hepinize kolay gelsin...

Friday, June 06, 2008 5:13:12 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, June 05, 2008

Silverlight 2.0 Beta 1 ile beraber gelen ilginç kontrollerden biri de DataGrid kontrolüdür. Aslında kontrolün kendisinde herhangi bir ilginçlik yok, ilginç olan WPF'in ilk sürümlerinde böyle bir kontrol yokken Silverlight'ın ikinci sürümünde DataGrid'in geliyor olması. Bu yazımızda Silverlight 2.0 Beta 1 ile DataGrid kullanımına deyineceğiz.

Silverlight 2.0 projenizi Visual Studio 2008 ile yarattıktan sonra hemen araç çubuğunda DataGrid kontrolü ile karşılaşabilirsiniz. Expression Blend içerisinde ise varsayılan ayarlar ile gelmeyecektir. Bunun aslında basit bir nedeni var; DataGrid gibi veri kontrolleri Silverlight 2.0 için harici bir Control Library olan System.Windows.Controls.Data altında geliyor ve bu kütüphane normal şartlarda uygulamaları referans olarak eklenmiş olmuyor. Eğer uygulamanıza bu sınıfı referans olarak eklerseniz Blend içerisinde de gerekli seçenekler gelecektir. Visual Studio içerisinde sahneye bir DataGrid yerleştirdiğinizde gerekli referanslar otomatik olarak ekleniyor.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="SilverlightApplication25.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

      <my:DataGrid></my:DataGrid>

    </Grid>

</UserControl>

Yukarıdaki kodu incelediğinizde herhangi bir Silverlight uygulamasına DataGrid yerleştirildiğinde en üst satırdaki XML namespace tanımını görebilirsiniz. Söz konusu tanım veri kontrollerinin Assembly'lerine bağlı. Böylece artık uygulamamızda veri kontrollerini kullanabiliriz. Bunun bir sonucu olarak artık uygulamamızdan üretilecek XAP paketinde de System.Windows.Controls.Data.dll dosyası bulunacaktır.

İlk olarak istemci tarafındaki kodumuz ile DataGrid içerisinde gösterilmek üzere bir veri yığını yaratalım. Bu noktada siz uygulamalarınızda rahatlıkla farklı web servislerinden çektiğiniz verileri kullanabilirsiniz.

[VB]

    Public Class Urun

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

 

        Private PStok As Boolean

        Public Property Stok() As Boolean

            Get

                Return PStok

            End Get

            Set(ByVal value As Boolean)

                PStok = value

            End Set

        End Property

 

        Sub New()

 

        End Sub

 

        Sub New(ByVal adi As String, ByVal stok As Boolean)

            Me.Adi = adi

            Me.Stok = stok

        End Sub

 

    End Class

[C#]

    public class Urun

    {

 

        private string PAdi;

        public string Adi

        {

            get { return PAdi; }

            set { PAdi = value; }

        }

 

 

        private bool PStok;

        public bool Stok

        {

            get { return PStok; }

            set { PStok = value; }

        }

 

        public Urun()

        {

 

        }

 

        public Urun(string adi, bool stok)

        {

            this.Adi = adi;

            this.Stok = stok;

        }

 

    }

Yukarıdaki sınıf yapısını verimizi oluştururken kullanacağımız nesneler olarak hazırladık. Silverlight 2.0'daki DataBinding WPF ile büyük bir benzerliğe sahip. Özellikle LINQ ile beraber kullanıldığında nesneleri kontrollere bind edebiliyor olmak büyük avantaj sağlıyor. Şimdi gelelim bize geçici olarak veri yaratacak olan kodumuzu yazmaya.

[VB]

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim liste As New System.Collections.Generic.List(Of Urun)

        For x As Integer = 0 To 9

            liste.Add(New Urun("Urun Adi" & x, (Math.Round(Rnd() * 1) - 1)))

        Next

        BirGrid.ItemsSource = liste

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

 

            System.Collections.Generic.List<Urun> liste = new System.Collections.Generic.List<Urun>();

            Random RastGele = new Random();

            for (int x = 0; x <= 9; x++)

            {

                liste.Add(new Urun("Urun Adi" + x.ToString(), Convert.ToBoolean(RastGele.Next(0, 1) - 1)));

            }

            BirGrid.ItemsSource = liste;

        }

Kod içerisinde de gördüğünüz gibi elimizdeki veriyi doğrudan BirGrid adındaki DataGridimizin ItemsSource özelliğine bağlıyoruz. Böylece DataBinding işlemi tamamlanmış oldu. Fakat bağladığımız bu verinin Grid içerisinde kolonlara yerleşmesi için tabi bizim "kolon"lara ihtiyacımız var. Otomatik olarak veriye uygun kolon yaratılabilmesi için DataGrid'in AutoGenerateColumns özelliğinin True olarak ayarlanmış olması gerekiyor.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="SilverlightApplication25.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <my:DataGrid x:Name="BirGrid" AutoGenerateColumns="True"></my:DataGrid>

  </Grid>

</UserControl>

XAML kodumuzun son hali yukarıdaki gibi olmalı. Böylece uygulamamızı çalıştırdığımızda aşağıdaki manzara ile karşılaşabiliriz.

Silverlight 2.0 içerisinde DataGrid görüntüsü.
Silverlight 2.0 içerisinde DataGrid görüntüsü.

İsterseniz alternatif satırların fon renklerini hatta kolonlar arası çizgilerin renklerini bile tek tek belirleyebilirsiniz. Aşağıdaki kod yapabileceğiniz renk değişikliklerine dair bir ipucu olabilir.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="True"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3"></my:DataGrid>

  </Grid>

</UserControl>

Kendi kolonlarımızı tanımlayalım!

Aslında AutoGenerateColumns özelliği bizim ASP.NET'teki GridView'den de alışık olduğumuz bir özellik. Kolay bir kullanım sağlasa da çoğu zaman bu özellik istediğimiz uygulamaları hazırlayabilmemiz için yeterli değil. O nedenle gelin şimdi beraber bir DataGrid içerisinde kolonları nasıl elle ayarlayabileceğimizi inceleyelim.

Eğer AutoGenerateColumns özelliğini True yapmazsanız hali hazırda varsayılan ayarı zaten False olarak geliyor. O nedenle bir önceki projemize devam edeceğimiz için ilk olarak ya AutoGenerateColumns özelliğini XAML kodunuzdan silin ya da False olarak ayarlayın.

Bir DataGrid'in üç çeşit kolonu olabilir;

  • DataGridTextBoxColumn
  • DataGridCheckBoxColumn
  •  DataGridTemplateColumn

Adlarından da anlaşılacağı üzere ikisi kendi isimlerindeki kontrolleri kolonlara yerleştirirken TemplateColumn ise bize daha esnek bir yapı sağlıyor. İlk olarak gelin TextBoxColumn ve CheckBoxColumn kullanarak bir önceki adımdaki örneğimizin kolonlarını elle tanımlayalım.

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="False"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3">

      <my:DataGrid.Columns>

        <my:DataGridTextBoxColumn Header="Adi"

                                  DisplayMemberBinding="{Binding Adi}" />

        <my:DataGridCheckBoxColumn Header="Stokta Var?"

                                  DisplayMemberBinding="{Binding Stok}" />

 

      </my:DataGrid.Columns>

    </my:DataGrid>

Kolonlarımızı ekledikten sonra her kolonun Header özelliğini değiştirerek o kolonda gözükecek olan başlığı ayarlayabiliyoruz. Son olarak da veri kaynağından hangi Property'nin söz konusu kolonda gözükeceğini belirlemek için bir Binding kullanıyoruz. Görsel olarak sonuç bir önceki örneğimizdeki ile aynı olacak fakat bu sefer kolonları biz el ile tek tek ayarlamış olduk. Bunun getireceği esnekliği özellikle TemplateColumn ile çok daha rahat görebiliriz.

Özel kolonlar : TemplateColumn

Özel bir kolon tanımlarken yapmamız gereken iki şey var; ilk olarak kolonun normal görüntüsünü tanımlamak, ikincisi ise "edit" modundaki görüntüsünü tanımlamak. Eğer ReadOnly özelliklerini değiştirmezseniz normal şartlarda hem TextBoxColumn hem de CheckBoxColumn üzerlerine tıklandıklarında içlerindeki verinin değiştirilebilmesine olanak tanırlar. Hatta Binding Mode olarak da TwoWay parametresini aktarırsanız arka planda Bind ettiğiniz List içerisinde gerekli değişiklikler de otomatik olarak yapılır. Şimdi biz tüm bunları bir TemplateColumn ile deneyeceğiz. Amacımız Stok bilgisi gösteren kolonu biraz değiştirerek normalde içerisinde True veya False yazmasını sağlamak. Yani normal şartlarda o kolonda bir CheckBox gözükmeyecek, fakat kullanıcına kolona çift tıklar ve değeri değiştirmek isterse karşınızda bu sefer bir CheckBox gelecek.

        <my:DataGridTemplateColumn Header="Stokta Var?">

          <my:DataGridTemplateColumn.CellTemplate>

            <DataTemplate>

              <TextBlock Text="{Binding Stok}"/>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellTemplate>

          <my:DataGridTemplateColumn.CellEditingTemplate>

            <DataTemplate>

              <CheckBox IsChecked="{Binding Stok, Mode=TwoWay}"></CheckBox>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellEditingTemplate>

        </my:DataGridTemplateColumn>

Yukarıdaki kodu detaylı olarak incelemekte fayda var. Yarattığımız TemplateColumn'un içerisinde bir CellTemplate, bir de CellEditingTemplate var. Bu kolonun normal şartlardaki görüntüsü CellTemplate, düzenleme modundaki görüntüsü ise CellEditingTemplate içerisindeki şablona göre hazırlanacak. CellTemplate içerisinde DataTemplate içinde sadece bir TextBlock koyuyoruz ve söz konusu TextBlock'un da Text özelliğini Stok bilgisini bind ediyoruz. Böylece normalde Stok bilgisi String olarak bu TextBlock içerisinde gösterilecek. Gelelim CellEditingTemplate şablonunda; bu şablon içerisinde de bir CheckBox kullanarak söz konusu CheckBox'un IsChecked özelliğini Stok Property'sine Bind ederken Mode olarak da TwoWay'i seçiyoruz. Böylece bu CheckBox üzerinde yapılan değişiklikler elimizdeki List verimize yansıyacak, yani kaydedilecek.

Uygulamamızın tam XAML kodunu aşağıda inceleyebilirsiniz.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="False"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3">

      <my:DataGrid.Columns>

        <my:DataGridTextBoxColumn Header="Adi"

                                  DisplayMemberBinding="{Binding Adi}" />

        <my:DataGridCheckBoxColumn Header="Stokta Var?"

                                  DisplayMemberBinding="{Binding Stok}" />

        <my:DataGridTemplateColumn Header="Stokta Var?">

          <my:DataGridTemplateColumn.CellTemplate>

            <DataTemplate>

              <TextBlock Text="{Binding Stok}"/>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellTemplate>

          <my:DataGridTemplateColumn.CellEditingTemplate>

            <DataTemplate>

              <CheckBox IsChecked="{Binding Stok, Mode=TwoWay}"></CheckBox>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellEditingTemplate>

        </my:DataGridTemplateColumn>

      </my:DataGrid.Columns>

    </my:DataGrid>

  </Grid>

</UserControl>

IValueConverter ile Binding'lere müdahale edin

Bir önceki örnek biraz saçma gelmiş olabilir. Kolon içerisinde doğrudan True veya False yazıyor olmak pek hoş değil. Stok bilgisinden bahsettiğimize göre True veya Flase yerine "Var" veya "Yok" yazdırsak belki çok daha mantıklı olabilirdi. Kullanıcı satıra tıkladığında ise yine karşısına düzenleme modunda bir CheckBox gelecektir. Bu işlemi yapabilmemiz için bizim CellTemplate içerisindeki TextBlock'un Binding'ine müdahale ederek "Eğer True geliyorsa VAR yazdır, gelmiyorsa YOK yazdır" diyebilmemiz gerekiyor. İşte tam da bu işlemi yapabilmek için Silverlight 2.0 Beta 1 içerisinde ValueConverter yapılarını kullanabiliyoruz.

[VB]

Public Class StokCevirici

    Implements Data.IValueConverter

 

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert

        If value Then

            Return "Var"

        Else

            Return "Yok"

        End If

    End Function

 

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack

        If value = "Var" Then

            Return True

        Else

            Return False

        End If

    End Function

End Class

[C#]

    public class StokCevirici : System.Windows.Data.IValueConverter

    {

 

        object System.Windows.Data.IValueConverter.Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            if (bool.Parse(value.ToString()))

            {

                return "Var";

            }

            else

            {

                return "Yok";

            }

        }

 

        object System.Windows.Data.IValueConverter.ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            if (value.ToString() == "Var")

            {

                return true;

            }

            else

            {

                return false;

            }

        }

    }

İlk olarak yukarıdaki şekilde System.Windows.Data.IValueConverter sınıfını implemente etmemiz gerekiyor. Bu şekilde bir Converter yapısının her zaman bir Convert ve bir de ConvertBack metodlarının bulunması şart. Bu metodlar aslında bizim elimizdeki True veya False olan Boolean değerinin String'e çevireceğimiz ve Binding için DataGrid'e göndereceğimiz veriyi oluşturmamıza olanak tanıyorlar. Kod içerisinde de duruma göre parametre olarak gelen Boolean değeri String'e veya tam tersine işlemler yapıyoruz. Sıra geldi bu Converter yapısını XAML kodumuzda kullanarak Binding işlemine dahil etmeye.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            xmlns:local="clr-namespace:SilverlightApplication25"

            Width="400"

            Height="300">

İlk olarak yukarıdaki şekilde XAML içerisinde kullanacağımız Assembly'mizi tanımlıyoruz. Böylece Converter sınıfımızı rahatlıkla kullanabileceğiz. Fakat işlemler bu kadarla bitmiyor. Tanımladığımız Assembly içerisinde Convertor'ımızı da alarak sayfada Resource olarak yerleştirmemiz şart.

  <UserControl.Resources>

    <local:StokCevirici x:Key="StokCevirici" />

  </UserControl.Resources>

Tüm bu işlemlerde Visual Studio'nun Intellisense yapısı size yardımcı olacaktır. Artık XAML tarafında StokCevirici adını verdiğimiz Converter yapımızı istediğimiz bir Binding için kullanmaya hazırız.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

            xmlns:local="clr-namespace:SilverlightApplication25"

            Width="400"

            Height="300">

  <UserControl.Resources>

    <local:StokCevirici x:Key="StokCevirici" />

  </UserControl.Resources>

  <Grid x:Name="LayoutRoot"

        Background="White">

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="False"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3">

      <my:DataGrid.Columns>

        <my:DataGridTextBoxColumn Header="Adi"

                                  DisplayMemberBinding="{Binding Adi}" />

        <my:DataGridCheckBoxColumn Header="Stokta Var?"

                                  DisplayMemberBinding="{Binding Stok}" />

        <my:DataGridTemplateColumn Header="Stokta Var?">

          <my:DataGridTemplateColumn.CellTemplate>

            <DataTemplate>

              <TextBlock Text="{Binding Stok, Converter={StaticResource StokCevirici}}" />

            </DataTemplate>

          </my:DataGridTemplateColumn.CellTemplate>

          <my:DataGridTemplateColumn.CellEditingTemplate>

            <DataTemplate>

              <CheckBox IsChecked="{Binding Stok, Mode=TwoWay}"></CheckBox>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellEditingTemplate>

        </my:DataGridTemplateColumn>

 

      </my:DataGrid.Columns>

    </my:DataGrid>

  </Grid>

</UserControl>

Uygulamanın son halinin tam kodunu yukarıdaki inceleyebilirsiniz. Özellikle yarattığımız Converter'ın kullanım şekline dikkat etmekte fayda var. Artık TextBlock içerisinde gösterilen veriler söz konusu Converter'dan geçtikten sonra gösterileceği için ekranda "Var" veya "Yok" yazıları yer alacak. Oysa kullanıcı çift tıklayarak değeri değiştirmek istediğinde karşısına bir CheckBox çıkacak ve True veya False olabilecek Boolean değeri değiştiriyor olacak.

Hepinize kolay gelsin.

Thursday, June 05, 2008 8:17:07 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, June 02, 2008

Checkbox ve RadioButton kontrolleri neredeyse her projede en az bir defa kullandığımız kontroller arasında yerlerini alırlar. Bu kontroller gibi farklı kontroller oluşturarak kullanıcıyı bir durumdan haberdar etmek veya kullanıcının bir durumu değiştirmesini sağlamak mümkün olabilir. Örneğin basit bir video oynatıcısı uygulamasında "Play" düğmesi ile "Pause" düğmesini aynı düğme içerisinde kullanabilirsiniz. Söz konusu düğme kendi içinde değişerek her tıklandığında "Play" veya "Pause" şeklinde üzerindeki yazıyı değiştirir ve videonun da durdurulmasını veya oynatılmasını sağlar. Checkbox veya RadioButton düğmeleri gibi bu gibi kontrollere özünde "ToggleButton" denir ve Silverlight 2 Beta 1 içerisinde Checkbox ve RadioButton da zaten hali hazırda adı ToggleButton olan bir kontrol yapısından türetilmiştir. Bu yazımızda ToggleButton kontrolünün detaylarına ve kullanımına değineceğiz.

<UserControl x:Class="SilverlightApplication21.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <ToggleButton Margin="104,109,177,138" Content="ToggleButton" x:Name="ToggleDugme"/>

  </Grid>

</UserControl>

Yukarıdaki şekli ile standart bir ToggleButton kontrolünü ister Blend ister Visual Studio içerisinde uygulamanıza yerleştirebilirsiniz. Sonrasında arkaplanda ToggleButton kontrolünün yakalayabileceğimiz iki kendine özel event'ı var; bunlardan ilki Checked, diğeri ise Unchecked durumları. Yarattığımız ToggleButton'ın görsel özelliklerine değinmeden önce hemen bu event'lar ile neler yapabileceğimize bir göz atalım.

[VB]

Private Sub ToggleDugme_Checked(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ToggleDugme.Checked

    ToggleDugme.Content = "İşaretli"

End Sub

 

Private Sub ToggleDugme_Unchecked(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ToggleDugme.Unchecked

    ToggleDugme.Content = "İşaretsiz"

End Sub

[C#]

private void ToggleDugme_Checked(object sender, System.Windows.RoutedEventArgs e)

{

    ToggleDugme.Content = "İşaretli";

}

 

private void ToggleDugme_Unchecked(object sender, System.Windows.RoutedEventArgs e)

{

    ToggleDugme.Content = "İşaretsiz";

}

Basit bir şekilde ToggleButton kontrolümüzün içerisine yazılı metni değiştirdiğimiz örneğimizi çalıştırdığımızda artık Button görünümündeki ToggleButton kontrolüne her bastığımızda içinde duruma göre "İşaretli" veya "İşaretsiz" yazacak. Ayrıca isterseniz ToggleButton kontrolüne ait IsChecked özelliğini de kullanarak ToggleButton'un o anki durumundan haberdar olabilirsiniz.

Belirsiz durumlara özel...

Bazı durumlarda sadece iki seçenek yetmez ve "belirsizlik" seçimi de yapmak gerekebilir. Bu durumda kullanıcıya sadece Evet veya Hayır şeklinde cevap vermenin yanı sıra isterse "Bilmiyorum" gibi bir seçeneğe de yönelebilir. ToggleButton içerisinde böyle bir yapı da var. Eğer bir ToggleButton'un IsThreeState özelliğini True olarak ayarlarsanız artık iki değil üç seçenekli bir ToggleButton sahibi olmuş oluyorsunuz. Peki bu üçüncü seçeneği kod tarafında nasıl yakalıyoruz?

[VB]

Private Sub ToggleDugme_Checked(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ToggleDugme.Checked

    ToggleDugme.Content = "İşaretli"

End Sub

 

Private Sub ToggleDugme_Indeterminate(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ToggleDugme.Indeterminate

    ToggleDugme.Content = "Belirsiz"

End Sub

 

Private Sub ToggleDugme_Unchecked(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles ToggleDugme.Unchecked

    ToggleDugme.Content = "İşaretsiz"

End Sub

[C#]

private void ToggleDugme_Checked(object sender, System.Windows.RoutedEventArgs e)

{

    ToggleDugme.Content = "İşaretli";

}

 

private void ToggleDugme_Indeterminate(object sender, System.Windows.RoutedEventArgs e)

{

    ToggleDugme.Content = "Belirsiz";

}

 

private void ToggleDugme_Unchecked(object sender, System.Windows.RoutedEventArgs e)

{

    ToggleDugme.Content = "İşaretsiz";

}

Gördüğünüz gibi ToggleButton'un ayrıca bir de Indeterminate adında bir event-handler'ı bulunuyor. Söz konusu durumu yakalayarak belirsizlik halinde de gerekli işlemlerin yapılmasını sağlayabilirsiniz. Böyle bir durumda IsChecked özelliği geriye null / nothing döndürecektir.

Unutmayın ki herhangi bir kontrolün Content özelliği aslında içerisine farklı Silverlight kontrolleri de alabilir hatta kontrollerin görsel yapısının tamamen değiştirebilirsiniz. Silverlight 2 Beta 1 içerisinde Control Templating ile ilgili yazıyı inceleyerek ToggleButton için de aynı teknikleri uygulayabilirsiniz.

Hepinize kolay gelsin.

Monday, June 02, 2008 2:33:53 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, June 01, 2008

Haziran'ın bu ilk gününde yazı karşılarken size yeni bir sürprizim var :)

T-Shirt ve kravatın ardında bir sürü mail aldım. T-Shirt'ü Tish-O'ya paslayarak üretim sorununu halletmiş olduk. Fakat kravat konusunda herhangi bir çözüm maalesef söz konusu değil. Diğer yandan aslında çok daha kolay üretebileceğimiz bir şey var :) Özellikle önümüzde yazın da geldiğini düşünürsek bir Silverlight şapkası süper olur diye düşündüm.

Silverlight Şapka :) ve tatil sevdası!
Silverlight Şapka :) ve tatil sevdası!

Tasarım anlamında çok bir emek yok ortada :) Rahatlıkla sizin de yapabileceğiniz bir uygulama. Silverlight logosunu aşağıdaki linkten indiriyorsunuz ve doğrudan en yakın "dijital baskı merkezi"ne doğru ufak bir yolculuk yapıyorsunuz. Neredeyse hepsi şapka üzerine baskı alabiliyor. Şapkanın yıkanma durumu da t-shirt'e kıyasla daha nadir olduğu için herhangi bir baskının pek sorunu olmayacaktır.

Silverlight Logo - 01062008_2.jpg (99,43 KB)

İlk şapkalıya hediye var :)

Hadi bakalım ilk önce kimi göreceğim etrafta bu şapka ile :) Bu şapkayı takmış olarak gördüğüm ilk arkadaşı buradan sizlere de fotoğrafı ile duyurmanın yanı sıra söz konusu arkadaş benden bir de güzel hediye alacak :) Sürpriz!

İyi şanslar...

Sunday, June 01, 2008 2:10:21 PM (GTB Standard Time, UTC+02:00)  #    Comments [10]   Silverlight | Silverlight 2.0  | 
 Thursday, May 29, 2008

Silverlight 1.0 içerisinde harici sayfalara linkler verecek düğmeler yaratmak için el ile kod yazmak gerekiyordu, eğer bir de gerçekten bir HTML linki gibi gözüken bir HyperLink yaratmak isterseniz epey bir uğraşmanız gerekecektir. Silverlight 2.0 Beta 1 ile bu soruna çok basit bir çözüm geliyor; HyperlinkButton.

<UserControl x:Class="SilverlightApplication19.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <HyperlinkButton Margin="175,101,92,0" Content="Tikla Git" VerticalAlignment="Top" Height="Auto" NavigateUri="http://www.live.com" TargetName="_blank"/>

  </Grid>

</UserControl>

Yukarıda da görebileceğiniz gibi HyperlinkButton kısmen bizim ASP.NET tarafında alıştığımız yapılardan farklı değil. NavigateUri özelliğine verdiğiniz adrese yönlendirme yaparken TargetName ile isterseniz hedef bir pencere veya frame de belirtebiliyorsunuz. Son olarak HyperlinkButton içerisinde gözükmesini istediğiniz içeriği de Content özelliğine aktarabilirsiniz.

Özellikle ASP.NET ile bir karşılaştırma yaparsak ASP.NET içerisinde HyperLink kontrollerinin içine farklı kontroller koyabildiğimizi de hatırlayabiliriz. Örneğin rahatlıkla bir Image kontrolünü HyperLink içerisine koyarak kullanabiliriz. Aynı durum Silverlight için de geçerli.

<UserControl x:Class="SilverlightApplication19.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <HyperlinkButton VerticalAlignment="Center"

                    Height="Auto"

                    NavigateUri="http://www.live.com"

                    TargetName="_blank" HorizontalAlignment="Center">

      <HyperlinkButton.Content>

        <Image Height="54"

              Source="Waterfall.jpg" />

      </HyperlinkButton.Content>

    </HyperlinkButton>

  </Grid>

</UserControl>

Herhangi bir HyperlinkButton'ın Content özelliği aslında sadece metin içeriği almak için düzenlenmiş değil. İsterseniz herhangi bir Silverlight kontrolünü de Content içerisine yerleştirebilirsiniz. Bunun için tek yapmanız gereken Content özelliğini Inline olarak değil de HyperlinkButton içerisinde ek taglar içinde düzenlemeniz. İsterseniz birden çok kontrolü de Content içerisine yerleştirebilirsiniz, tek şart elinizdeki tüm kontrolleri Canvas gibi bir container element içerisine toplamış olmak.

HyperlinkButton için Template Kullanımı

Bir uygulamada birden çok HyperlinkButton kullanılması olası. Bu gibi durumlarda tüm bu linklerin görsel özelliklerinin ortak bir noktada tutuluyor olması gerekiyor. Hali hazırdaki bir HyperlinkButton'un görsel özelliklerinin değiştirilebilmesi için Content özelliğine farklı içerikler aktarmaktansa doğrudan HyperlinkButton'un Template özelliği düzenlenebilir.

    <HyperlinkButton VerticalAlignment="Center"

                    Height="Auto"

                    NavigateUri="http://www.live.com"

                    TargetName="_blank"

                    HorizontalAlignment="Center"

                    Content="TIKLA"

                    Template="{StaticResource LinkTemplate}" />

Yukarıdaki HyperlinkButton'un Template özelliği uygulama içerisindeki kaynaklardan birine bağlanmış. Birazdan LinkTemplate adındaki HyperlinkButton şablonumuzu hazırlayacağız. Böylece aynı görsel şablonu birden çok link kullanabilecek.

Örneğimizde ulaşmak istediğimiz noktayı belirleyelim. HyperlinkButton'un Content özelliğine verilen içeriğin doğrudan görsel şablonun ortasında gözükmesini istiyoruz. Bunun için bir ContentPresenter kullanacağız. Bu ContentPresenter'ın arkasında ise kenarları yuvarlatılmış bir dikdörtgen kullanalım. Böylece HyperlinkButton'umuz normal bir düğme gibi gözüksün.

    <ControlTemplate x:Key="LinkTemplate" TargetType="HyperlinkButton">

      <Grid>

        <Rectangle Stroke="#FF000000"

                  RadiusY="16"

                  RadiusX="16">

          <Rectangle.Fill>

            <RadialGradientBrush>

              <GradientStop Color="#FFFF0000"

                            Offset="1" />

              <GradientStop Color="#FFFFFFFF"

                            Offset="0" />

            </RadialGradientBrush>

          </Rectangle.Fill>

        </Rectangle>

        <ContentPresenter Margin="10,10,10,10" Content="{TemplateBinding Content}"

                          HorizontalAlignment="Center"

                          VerticalAlignment="Center" />

      </Grid>

    </ControlTemplate>

Yukarıdaki kod tüm isteklerimizi yerine getiriyor. Şimdi önemli noktalara tek tek değinelim. İlk olarak ControlTemplate içerisine iki kontrol koyacağımız için bunları bir container element içerisine almamız gerekiyor. Biz örneğimizde Grid kullandık. ContentPresenter kontrolümüzün Content özelliğini şablonun hedefi olacak HyperlinkButton'un Content özelliğine bağladıktan sonra geriye sadece ufak iki ayar kalıyor. Birincisi ContentPresenter ile Rectangle arasında mesafe kalması için ContentPresenter'a elle Margin vermek. Böylece HyperlinkButton içerisine ne konulursan konulsun her zaman arkasında Rectangle'ın kenarlarından 10'a piksel uzak kalacak. İkinci ufak detay ise ControlTemplate'in TargetType özelliğinin kesinlikle ayarlanmış olması gerektiği.

Artık birden çok HyperlinkButton kullanarak aynı görsel özellikleri kullanabilirsiniz.

Hepinize kolay gelsin.

Thursday, May 29, 2008 11:29:20 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, May 28, 2008

Silverlight 2.0 içerisinde .NET programlama dillerini kullanırken istemci tarafında bir tarayıcıda olduğumuzu sürekli hatırlamak gerek. Bu bilgiyi aklımızda tutarsak aslında Silverlight içerisinde yapılamayan bazı şeyleri tarayıcının özelliklerinden faydalanarak yapma şansımız olabiliyor. Bu konuya örneklerden biri Silverlight 2.0 içerisinde farenin roller'ını yakalayarak zoom-in veya zoom-out efekti yaratmak. Maalesef şimdilik Silverlight içerisinde farenin roller'ını yakalayabileceğimiz herhangi bir event-handler yok. Bu durumda biz de tarayıcının özelliklerinden faydalanacağız.

İlk olarak hazırlayacağımız Silverlight 2.0 Beta 1 uygulamasının XAML kodunu inceleyelim. Page.xaml içerisinde basit bir Image nesnesi yer alıyor. Farenin rollerını kullanarak söz konusu Image nesnesini zoom yapabileceğiniz, yani özünde Image nesnesinin boyutlarını büyüterek küçülteleceğiz.

<UserControl x:Class="ScrollWheel.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Image Margin="147,112,156,126" Source="Forest.jpg" RenderTransformOrigin="0.5,0.5" x:Name="Foto">

      <Image.RenderTransform>

        <TransformGroup>

          <ScaleTransform x:Name="ZoomCarpani" ScaleX="1" ScaleY="1"/>

          <SkewTransform/>

          <RotateTransform/>

          <TranslateTransform/>

        </TransformGroup>

      </Image.RenderTransform>

    </Image>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde özellikle dikkat edilmesi gereken bir nokta var. Normal şartlarda Expression Blend içerisinde bir Image nesnesi yerleştirirseniz Image.RenderTransform tagı ve içerisindekiler gelmeyecektir. Eğer söz konusu Image nesnesini sadece bir kere arayüz içerisinde boyutlandırırsanız hemen bu taglar eklenir. Sonrasında RenderTransform içerisindeki ScaleTransform kısmıyla ilgileneceğiz. Image nesnemizin büyüklüğünü değiştirecek olan tag bu. ScaleTransform'un ScaleX ve ScaleY adında X ve Y doğrultusunda boyutlandırma yapabilen çarpanları var. Bu çarpanlara ve ScaleTransform nesnesine programatik olarak ulaşabilmek için hemen ScaleTransform'a ZoomCarpani adını veriyoruz. Böylece artık rahatlıkla kod tarafından bu resmin boyutu ile oynayabiliriz.

Gelelim code-behind sayfamıza; ilk olarak internet tarayıcımızın farenin roller'ını algıladığı event-handlerları yakalayarak kendi .NET event handlerlarımızı bağlamalıyız.

Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

    System.Windows.Browser.HtmlPage.Window.AttachEvent("DOMMouseScroll", AddressOf FareTekerlekDondu)

    System.Windows.Browser.HtmlPage.Window.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

    System.Windows.Browser.HtmlPage.Document.AttachEvent("onmousewheel", AddressOf FareTekerlekDondu)

End Sub

Silverlight uygulamamız sayfaya ilk yüklendiğinde hemen mevcut HtmlPage (HTML sayfa) üzerinden tarayıcı penceresini (Window) yakalayarak DOMMouseScroll ve onmousewheel durumlarına kendi FareTekerlekDondu kodumuzu atıyoruz. Ayrıca sayfada yüklü dokümanın da (Document) onmousewheel event'ını aynı şekilde yakalamamız gerekiyor. Tüm bu farklı event-handlerlar aslında hep bizim tek event-handlarımız olan FareTekerlekDondu'ye yönlendiriliyor. Bunun nedeni farklı tarayıcıların farklı event-handlerlar ile çalışıyor olması. Bizim örneğimiz rahatlıkla Opera, Safari, FireFox ve IE'de çalışacak. Sıra geldi FareTekerlekDondu'yü kodlamaya.

Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs)

    ...

End Sub

Yukarıdaki şekli ile kodumuzu yazarken dikkat etmemiz gereken nokta e parametresinin tipi. HtmlEventArgs bize tarayıcının döndürdüğü değerleri aktaracak.

    Dim DonMiktar As Integer = 0

    Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject

Kodumuzda iki adet değişken tanımlıyoruz. Bunlardan ilki olan DonMiktar tarayıcından gelen farenin roller'ını dönüş miktarını alarak yönünü belirleyecek. Tarayıcılardan dönüş miktarı + veya - değer olarak gelebilir ve maalesef bu durum tarayıcı tipine göre farklı yönlerde dönüşleri tanımlıyor. Tanımladığımız bir diğer değişken ise Gelen adında; bu değişken doğrudan e parametresinden EventObject'i alarak bize dönüş miktarını ulaştıracak.

    'IE ve OPERA

    If Not Gelen.GetProperty("wheelDelta") Is Nothing Then

        'OPERA'da ters!

        If Not Gelen.GetProperty("opera") Is Nothing Then

            DonMiktar = -DonMiktar

        End If

        DonMiktar = Gelen.GetProperty("wheelDelta")

        'Mozilla ve Safari

    ElseIf Not Gelen.GetProperty("detail") Is Nothing Then

        DonMiktar = -Gelen.GetProperty("detail")

    End If

Yukarıdaki kod biraz karışık gözükebilir fakat aslında yapmaya çalıştığımız şey çok basit. Tarayıcıdan farenin roller'ının dönüş miktarını almaya çalışıyoruz. Maalesef farklı tarayıcılarda bu sistemin farklı çalışması gerekiyor. Opera ve IE bu değeri wheelDelta özelliği üzerinden verirken Mozilla ve Safari detail adında bir property kullanıyor. Ayrıca IE dışında tüm tarayıcılarda değerler ters, veya belki de IE'de ters :) Ama duruma göre gelen değeri eksi ile çarpmak zorunda kalıyoruz.

    If DonMiktar > 0 Then

        ZoomCarpani.ScaleX += 0.1

        ZoomCarpani.ScaleY += 0.1

    Else

        ZoomCarpani.ScaleX -= 0.1

        ZoomCarpani.ScaleY -= 0.1

    End If

Artık elimizde DonMiktar değişkeni hazır olarak bulunduğunda göre DonMiktar'ın eksi veya artı değer almasına göre elimizdeki resmi büyütüp küçültebiliriz. Bu noktada büyütme ve küçültme miktarını el ile ayarlamakta fayda var. Aslında DonMiktar içerisinde farenin roller'ının bir defada ne kadar döndürüldüğüne dair bir değer geliyor fakat bunu kullanmak farklı sistemlerde çok ilginç sonuçlar verebiliyor. En iyisi sabit bir yol izlemek.

    If DonMiktar <> 0 Then

        e.PreventDefault()

        Gelen.SetProperty("returnValue", False)

    End If

Son olarak tarayıcıya farenin roller değişimi ile ilgili işlemlerini bizim yaptığımızı belirtmemiz gerek. Böylece tarayıcı içerisinde sayfa scroll etmeyecektir.

Uygulamamızın tam kodu aşağıdaki şekilde sonuçlanıyor....

Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs)

    Dim DonMiktar As Integer = 0

    Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject

    'IE ve OPERA

    If Not Gelen.GetProperty("wheelDelta") Is Nothing Then

        'OPERA'da ters!

        If Not Gelen.GetProperty("opera") Is Nothing Then

            DonMiktar = -DonMiktar

        End If

        DonMiktar = Gelen.GetProperty("wheelDelta")

        'Mozilla ve Safari

    ElseIf Not Gelen.GetProperty("detail") Is Nothing Then

        DonMiktar = -Gelen.GetProperty("detail")

    End If

 

    If DonMiktar > 0 Then

        ZoomCarpani.ScaleX += 0.1

        ZoomCarpani.ScaleY += 0.1

    Else

        ZoomCarpani.ScaleX -= 0.1

        ZoomCarpani.ScaleY -= 0.1

    End If

 

    If DonMiktar <> 0 Then

        e.PreventDefault()

        Gelen.SetProperty("returnValue", False)

    End If

End Sub

Hepinize kolay gelsin...

Wednesday, May 28, 2008 10:37:07 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, May 26, 2008

Super SilverMan T-Shirt tasarımımdan sonra tekstil sektörüne gireceğime dair dedikoduların yanı sıra :) ciddi tavsiyeler bile aldım. T-Shirt gerçekten çok başarılı bir ürün oldu :) diğer yandan maalesef her ortamda T-Shirt ile gezmek mümkün olmuyor. "Gömlek bastıralım?" gibi bir fikrin biraz daha ötesine giderek "kravat" konseptini uygun gördüm. Tasarım çalışmalarını da tamamladıktan sonra uygun bir şekilde kravat üretimine geçtik :) (Dalga geçmiyorum).

Dünyada Tek : Silverlight Kravat
Dünyada Tek : Silverlight Kravat

Kravatı bugüne kadar birkaç aktivitede kullandım ve deneme sürüşleri sonrasında herhangi bir bug'ı olmadığını söyleyebilirim. :) Tasarım yine bana ait ;) Maalesef şimdilik toplu üretim gibi bir şansımız yok, dehşet pahalıya mal oluyor (tamamen dikiş). Diğer yandan tüm dünyada sadece bende böyle bir kravatın bulunuyor olması de ayrı bir duygu :)

Peki ben bu yazıyı neden yazdım? :) "Düşmanlar çatlasın" diye değil tabi ki :P Silverlight heyecanımı blog okuyucularımla paylaşmaktı amacım. Umarım gün gelir Silverlight aktivitelerinde T-Shirt'ler, kravatlar kepçeyle dağıtılır :)

"Daha çok Silverlight'lı günler dileği ile..."

Monday, May 26, 2008 12:26:53 PM (GTB Standard Time, UTC+02:00)  #    Comments [13]   Silverlight | Silverlight 2.0  | 
 Sunday, May 25, 2008

Özellikle beni microbloğum twitter.com üzerinden takip edenlerin farkında olacağı üzere hafta sonunu Ankara'da geçirdim. Cumartesi gece yarısı yola çıkarak sabahına Ankara'ya vardım ve sabah 10.00 gibi EMO (Elektrik Mühendisleri Odası) Ankara şubesinde eğitim serimize başladık. WPF, AJAX, Silverlight ve LINQ konularına değindiğimiz eğitimi Pazar akşamı 18.00'da bitirdik.

EMO Eğitim Serisi başlangıcından bir kare...
EMO Eğitim Serisi başlangıcından bir kare...

Eğitime katılan arkadaşlara özellikle Silverlight örneğindeki kodları blogumdan paylaşacağım konusunda söz vermiştim. Aşağıdan gerekli dosyaları bilgisayarınıza indirebilirsiniz.

Örnek Kodlar - 25052008_2.rar (8,57 KB)

Eğitime katılan ve kocaman bir hafta sonu boyunca yeni teknolojiye olan ilgilerini ve konsantrasyonlarını en yüksek seviyede tutan tüm arkadaşlara çok teşekkür ediyorum (Özellikle ikinci gün sınıfa pasta alan kamera fobili arkadaşımıza ek teşekkürler :))

INETA ve EMO işbirliğinizde düzenlediğimiz bu eğitime katkısından dolayı ODTÜ Bilgisayar Mühendisliği Araştırma Görevlisi Serdar Çiftçi'ye, eğitimlere laboratuar ortamı sağlamakla beraber gösterdikleri sıcak misafirperverlik için de tüm EMO ekibine teşekkürler.

Sunday, May 25, 2008 7:16:24 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   AJAX | Expression Blend | Expression Design | Expression Encoder | LINQ | Silverlight | Silverlight 2.0 | WPF  | 
 Saturday, May 24, 2008

Silverlight 2.0 ile beraber gelen Resource yapısından ve kontrol şablonlarından daha önceki bir yazımda bahsetmiştim. Resource yapılarını herhangi bir Silverlight uygulamasındaki App.XAML dosyası içerisine koyduğunuzda tüm uygulamada global olarak kullanılabiliyor. Kendi şablonlarınızı oluşturarak ilerleyebileceğiniz gibi önceden hazırlanmış şablonlar da kullanabilirsiniz. Bu yazımda sizlerle Corrina Barber tarafından hazırlanmış olan Silverlight Resource şablonlarını paylaşacağım. Böylece hazır şablonları doğrudan uygulamanızda kullanabilir veya ufak değişiklikler yaparak farklı tasarımlara yelken açabilirsiniz. Umarım yakın zamanda daha çok tasarımcı bu şekilde kaynaklar hazırlayarak internette paylaşır, biz yazılımcılara yardımcı olur :)

Tasarım 1 Tasarım 2
Tasarım 1'i İndir Tasarım 2'yi İndir
Tasarım 3 Tasarım 4
Tasarım 3'ü İndir Tasarım 4'ü İndir

Hepinize kolay gelsin ;)

Saturday, May 24, 2008 6:58:35 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Friday, May 23, 2008

Özellikle "developer" tabanlı olanlar için hazırlanan bir uygulamanın görsel arayüzünü süslemek hem bir "çin işkencesi" oluyor hem de ortaya zaten güzel bir ürün de çıkmıyor. Bu gibi durumlarda eğer projelerinizde bir tasarımcı ile çalışma şansınız da yoksa en azından internetteki hazır renk şemalarından faydalanabilir, birbiri ile uyumlu renkler üreten web sitelerinden faydalanabilirsiniz.

Veya daha da pratik bir yol var, bir yerlerde beğendiğiniz renkleri "ödünç" alabilirsiniz :) Peki nerden? Hemen önünüzde Windows Vista duruyor, tasarımı da hiç fena sayılmaz :)

<Canvas

  xmlns="http://schemas.microsoft.com/client/2007"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  Width="640" Height="375.082"

  Background="White"

  x:Name="Page">

  <Rectangle Width="572.131" Height="78.885" Canvas.Left="31.148" Canvas.Top="8" Stroke="#FF000000">

    <Rectangle.Fill>

      <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">

        <LinearGradientBrush.GradientStops>

          <GradientStop Color="#FF000000" Offset="0"/>

          <GradientStop Color="#FF9AC6CF" Offset="0.0494537"/>

          <GradientStop Color="#FF54A1AA" Offset="0.0714264"/>

          <GradientStop Color="#FF146478" Offset="0.5"/>

          <GradientStop Color="#FF408C9A" Offset="0.505493"/>

          <GradientStop Color="#FF87B6C0" Offset="0.928574"/>

          <GradientStop Color="#FFBCCDD7" Offset="0.950546"/>

          <GradientStop Color="#FFAEBFCA" Offset="0.983521"/>

          <GradientStop Color="#FFAEBFCA" Offset="1"/>

        </LinearGradientBrush.GradientStops>

      </LinearGradientBrush>

    </Rectangle.Fill>

  </Rectangle>

  <Rectangle Width="572.131" Height="78.885" Canvas.Left="31.148" Canvas.Top="99.784" Stroke="#FF000000">

    <Rectangle.Fill>

      <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">

        <LinearGradientBrush.GradientStops>

          <GradientStop Color="#FF000104" Offset="0"/>

          <GradientStop Color="#FF02070B" Offset="0.494507"/>

          <GradientStop Color="#FF33373D" Offset="0.494507"/>

          <GradientStop Color="#FF757A7C" Offset="0.917587"/>

          <GradientStop Color="#FFA0A1A3" Offset="0.956039"/>

          <GradientStop Color="#FF48494A" Offset="1"/>

        </LinearGradientBrush.GradientStops>

      </LinearGradientBrush>

    </Rectangle.Fill>

  </Rectangle>

  <Rectangle Width="572.131" Height="78.885" Canvas.Left="31.148" Canvas.Top="189.929" Stroke="#FF000000">

    <Rectangle.Fill>

      <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">

        <LinearGradientBrush.GradientStops>

          <GradientStop Color="#FFD4D4D4" Offset="0"/>

          <GradientStop Color="#FFF0F2F4" Offset="0.0659332"/>

          <GradientStop Color="#FFF6F5F8" Offset="0.598907"/>

          <GradientStop Color="#FFFFFFFF" Offset="0.609894"/>

          <GradientStop Color="#FFFFFFFF" Offset="0.978027"/>

          <GradientStop Color="#FFC7C7C7" Offset="0.994507"/>

          <GradientStop Color="#FFC7C7C7" Offset="1"/>

        </LinearGradientBrush.GradientStops>

      </LinearGradientBrush>

    </Rectangle.Fill>

  </Rectangle>

  <Rectangle Width="572.131" Height="78.885" Canvas.Left="31.148" Canvas.Top="281.713" Stroke="#FF000000">

    <Rectangle.Fill>

      <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">

        <LinearGradientBrush.GradientStops>

          <GradientStop Color="#FFDFE4F4" Offset="0"/>

          <GradientStop Color="#FFB8BCC2" Offset="0.0439606"/>

          <GradientStop Color="#FFE0E6F4" Offset="0.0769196"/>

          <GradientStop Color="#FFD4DBE8" Offset="0.648346"/>

          <GradientStop Color="#FFE8ECF4" Offset="0.714279"/>

          <GradientStop Color="#FFFFFFFF" Offset="1"/>

        </LinearGradientBrush.GradientStops>

      </LinearGradientBrush>

    </Rectangle.Fill>

  </Rectangle>

</Canvas>

İşte size Vista'daki gradientların Silverlight veya WPF ile kullanılabilecek XAML kodları. Yukarıdaki örnek Silverlight 1.0 uygulamasında dört farklı gradientı gösterebilmek için dört adet dikdörtgen kullandım.

Vista Gradientları
Vista Gradientları

Hepinize kolay gelsin.

Friday, May 23, 2008 7:46:47 AM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight | Silverlight 2.0 | WPF  | 
 Wednesday, May 21, 2008

Silverlight 2.0 içerisinde Grid kullanımı HTML içerisinden alışık olduğumuz Table yapısından pek farklı değil. Kolonlar ve satırlar yaratarak görsel öğeleri ekranda konumlandırabilmenizi sağlayan Grid kontrolü ile beraber kullanabileceğimiz kontrollerden biri de GridSplitter kontrolü. GridSplitter kontrolü bir Gridin kolon veya satırlarının kullanıcı tarafından fare ile boyutlandırılabilmesini sağlıyor. Herhangi bir Grid yaratarak satır veya sütunlar oluşturduktan sonra istediğiniz Grid hücresine GridSplitter kontrolü yerleştirebiliyorsunuz.

<UserControl x:Class="GridSplit.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Grid.ColumnDefinitions>

      <ColumnDefinition Width="0.435*"/>

      <ColumnDefinition Width="0.07*"/>

      <ColumnDefinition Width="0.495*"/>

    </Grid.ColumnDefinitions>

    <GridSplitter Height="Auto" VerticalAlignment="Stretch" Grid.Column="1" Background="#FF0092FF" Width="10" HorizontalAlignment="Center"/>

  </Grid>

</UserControl>

Yukarıdaki XAML kodunda yer alan Grid'in toplam üç kolonu var. Bu kolonlardan birinin içerisinde gözükecek şekilde bir de GridSplitter nesnesi yerleştirilmiş. GridSplitter nesnesinin Grid.Column özelliği 1 olduğu için içerisinde bulunduğu Grid'in 1 Index numaralı kolonunda gözükecek.

GridSplitter kontrolü 2 resmi boyutlandırıyor.
GridSplitter kontrolü 2 resmi boyutlandırıyor.

Yukarıdaki gibi bir örnek elde etmek için Grid'in diğer kolonlarına birer Image nesnesi yerleştirdim. GridSplitter kontrolünü fare ile tutup sürüklediğimde her iki resim de içerisinde bulundukları kolonlara sığacak şekilde kendilerini boyutlandırdılar.

<UserControl x:Class="GridSplit.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Grid.ColumnDefinitions>

      <ColumnDefinition Width="0.435*"/>

      <ColumnDefinition Width="Auto"/>

      <ColumnDefinition Width="0.495*"/>

    </Grid.ColumnDefinitions>

    <GridSplitter Height="Auto" VerticalAlignment="Stretch" Grid.Column="1" Background="#FF0092FF" Width="10" HorizontalAlignment="Center"/>

    <Image Source="Creek.jpg"/>

    <Image Grid.Column="2" Source="Dock.jpg"/>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde dikkat etmemiz gereken nokta GridSplitter kontrolünü yerleştirdiğimiz Grid kolonunun Width özelliğinin Auto olması, böylece GridSplitter'ın genişliği ne ise söz konusu kolonun genişliği de o olacaktır.

GridSplitter kontrolünü yukarıdaki taktikleri izleyerek sadece dikey olarak ekranı bölmek için değil yatay olarak Grid'in satırları arasında da kullanabilirsiniz. Ayrıca birden çok Grid kontrolünü iç içe kullanarak farklı ekranlar yaratmak da mümkün.

<UserControl x:Class="GridSplit.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Grid.RowDefinitions>

      <RowDefinition Height="0.72*"/>

      <RowDefinition Height="Auto"/>

      <RowDefinition Height="0.237*"/>

    </Grid.RowDefinitions>

    <Grid>

      <Grid.ColumnDefinitions>

        <ColumnDefinition Width="0.435*"/>

        <ColumnDefinition Width="Auto"/>

        <ColumnDefinition Width="0.538*"/>

      </Grid.ColumnDefinitions>

      <GridSplitter HorizontalAlignment="Center" Width="10" Grid.Column="1" Background="#FF5EFF00"/>

      <Image Source="Creek.jpg" Stretch="Uniform"/>

      <Image Grid.Column="2" Source="Dock.jpg"/>

    </Grid>

    <GridSplitter HorizontalAlignment="Stretch" Width="Auto" Grid.Row="1" VerticalAlignment="Center" Height="10" Background="#FF0092FF"/>

    <Image Grid.Row="2" Source="Garden.jpg"/>

  </Grid>

</UserControl>

Yukarıdaki örnekte toplamda üç satırı bulunan bir Grid kontrolünün ikinci satırında GridSplitter bulunuyor. Aynı Grid'in birinci satırında ise içerisinde üç kolun bulunan ayrı bir Grid var. İçteki bu Grid'in de ikinci kolonunda bir GridSplitter var. Böylece yatay GridSplitter kullanıldığında dikey olan ve iç Grid'de bulunan GridSplitter da otomatik olarak boyutlandırılmış oluyor.

2 Grid ve 2 GridSplitter'ın kardeşliği.
2 Grid ve 2 GridSplitter'ın kardeşliği.

Bu gibi arayüzler neredeyse çoğu yazılımda karşımıza çıkan sistemler içerisinde. Silverlight 2.0 ile beraber iş uygulamaları geliştirirken bu tarz kolaylıkların büyük bir iş yükünü omuzlarımızdan kaldıracağı kesin.

GridSplitter değişiklikleri algılamak?

GridSplitter'ı kullanmak gerçekten çok kolay. Fakat istemci tarafında kullanıcı tüm GridSplitter'ları ayarladıktan sonra Silverlight uygulamasını başka bir zamanda tekrar açtığında tüm ayarları tekrar yapmak zorunda kalması hiç hoş olmaz. O nedenle GridSplitter ile yapılan ayarları bir şekilde saklamamız gerek.

Aslında GridSplitter'ın yaptığı işlem içerisinde bulunduğu Grid'in kolonlarının boyutlarını değiştirmek öte değil. Bu durumda bizim Grid'in kolonlarında değişiklik olup olmadığı yakalamamız ve söz konusu değişiklikleri kaydetmemiz gerekiyor.

Private Sub IcGrid_LayoutUpdated(ByVal sender As Object, ByVal e As System.EventArgs) Handles IcGrid.LayoutUpdated

    Metin.Text = IcGrid.ColumnDefinitions(0).Width.ToString

End Sub

Herhangi bir Grid'in LayoutUpdated metodunu yakaladığınızda aslında Grid'in görselliğindeki tüm boyut değişikliklerini de yakalamış oluyorsunuz. GridSplitter Grid'in kolonlarının boyutunu değiştirdikçe LaoutUpdated metodu çalıştırılacaktır. Bizim yapacağımız da basit bir şekilde IcGrid adını verdiğimiz Grid'in sıfırcı kolonunun genişliğini alarak kaydetmek. Kaydetme işlemini bir web servisi ile sunucu tarafına yapabileceğiniz gibi doğruda Isolated Storage kullanarak istemci tarafında da saklayabilirsiniz. Ben örnek içerisinde söz konusu değeri Metin adındaki bir TextBlock içerisine yazdırdım.

Kaydettiğiniz genişlik ve yükselik değerlerini Silverlight uygulaması tekrar açıldığında görsel arayüze uygulamak ise çok daha kolay.

Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

    IcGrid.ColumnDefinitions(0).Width = New System.Windows.GridLength(100)

End Sub

İstediğimiz herhangi bir Grid'in kolonunu yakalayarak Width özelliğini değiştirebiliyoruz.

Hepinize kolay gelsin ;)

Wednesday, May 21, 2008 12:50:15 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Monday, May 19, 2008

İstemci taraflı programlama sistemleri AJAX ile karşımıza çıkmıştı, Silverlight ile beraber ise artık istemci taraflı programlama neredeyse "hayatımız" oluyor. Bu durumda karşılaştığımız en büyük sorun "Cross-Domain-Request" sınırlaması. Güvenlik nedenleriyle bir alan adından bir başka alan adına bağlanarak veri talebinde bulunamıyoruz. Eğer karşıdaki alan adının ihtiva ettiği siteye admin erişiminiz varsa tabi ki farklı teknikler kullanarak bu sorunu çözebilirsiniz. Bu konuda Silverlight 2.0 ile beraber clientaccesspolicy.xml dosyası geliyor.

Peki ya karşı siteye admin erişimimiz yoksa?

İşte o zaman kendi sitemizde sunucu taraflı bir proxy kullanmamız şart. ASP.NET ile sunucu tarafından istediğimiz siteye bağlanarak istediğimiz dosyası alabiliriz. Bu durumda bir ASPX sayfası yapsak bizim yerimize gidip kendisine hedef gösterdiğimiz adresten gerekli dosyayı alıp istemci tarafına, yani bize iletse hoş olmaz mı?

        Dim Talep As New Net.WebClient

        Dim GelenVeri As Byte() = Talep.DownloadData(Request.QueryString("Dosya"))

        Response.ContentType = Talep.ResponseHeaders("Content-type").ToString

        Response.OutputStream.Write(GelenVeri, 0, GelenVeri.GetLength(0))

        Response.OutputStream.Close()

        Response.End()

Yukarıdaki kod içerisinde doğrudan bir WebClient yaratarak farklı bir adresten veri indirme işlemi yapıyoruz. Kod içerisindeki en önemli nokta indirmek istediğimiz hedef veri ile istemciye göndereceğimiz verinin ContentType değerlerinin aynı olması gerektiği. Bunun için Response.ContentType'ı WebClient üzerinden aldığımız Content-Type header bilgisi ile eşleştiriyoruz. Böylece proxy'miz gerektiğinde video veya resim dosyalarını da rahatlıkla indirerek bize ulaştırabilir.

Performans?

Yukarıdaki örneğimiz çok basit bir yapıya sahip. Dosyayı sunucuya indirerek doğrudan istemciye gönderiyor. Yüksek sayıda istek oluşan projelerde veya büyük dosyalar indirecek olan uygulamalarında farklı performans senaryoları uygulamak gerekecektir. Aslında baktığımızda bu yapının herhangi bir Proxy programlamaktan pek farkı yok. Aklıma ilk aşamada gelen dikkat edilmesi gereken noktalar şöyle oldu;

  • Büyük dosya indirirken istemcinin hala bağlı olup olmadığını Response.IsClientConnected ile kontrol etmek gerekir.
  • Büyük dosya indirme işlemlerinde bufferlamak ve kısım kısım indirerek istemciye göndermek daha mantıklı olabilir. Özellikle video dosyalarında.
  • Kesinlikle bu dosyaya request yollayanın headerını kontrol etmek lazım. Kötü niyetli biri bu proxy'yi sadece sunucunun bant genişliğini harcamak için kullanabilir veya gereksiz yere sunucuyu yorabilir.

Hepinize kolay gelsin.

Monday, May 19, 2008 10:47:08 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   AJAX | Silverlight | Silverlight 2.0  | 
 Sunday, May 18, 2008

Günümüzde çoğu AJAX uygulamasında veri transferi için JSON formatı kullanılıyor. ASP.NET programcılığı tarafında biz farkında olmasak da PageMethod'lar, Web Servisleri veya WCF Servisleri sunucudan JavaScript istemciye asenkron (AJAX) veri taşırken JSON ile çalışıyor. ASP.NET dışındaki dünyaya da baktığımızda tabi ki bu kural geçerliliğini koruyor, örneğin bugün twitter.com kendi uygulamalarından dışarıya asenkron veri aktarırken JSON formatını kullanıyor. Peki Silverlight 2.0 ile salt AJAX mantığından kurtularak artık Web Servislerimizi veya WCF servislerimizi doğrudan asenkron olarak kullanabildiğimize göre karşımıza eski JSON kaynakları gelirse ne yapacağız?

.NET nesnelerinden JSON oluşturmak.

Hikayenin tersinden başlayalım ve ilk olarak istemci tarafında JSON verisi nasıl yaratırız onu inceleyelim. Zaten genelde harici bir web servisinden JSON verisi alacaksanız büyük ihtimal ile elinizdeki hazır bir JSON verisini de web servisine göndermek durumunda kalacaksınız. Bu gibi bir durumda rahatlıkla elimizdeki .NET nesnelerini JSON formatına çevirebiliyor olmalıyız.

Silverlight 2.0 Beta 1 ile beraber gelen sınıflardan system.runtime.serialization.json.datacontractjsonserializer sınıfını kullanacağız. Bu sınıfı normal şartlarda kullanmak isterseniz herhangi bir Silverlight uygulamasında Intellisense ile bulma şansınız olmayacaktır. Söz konusu sınıf harici olarak System.ServiceModel.Web.dll dosyası içerisinde kendisini projemize referans olarak almamızı bekliyor. Gerekli referansı projeye ekledikten sonra rahatlıkla JSON işlemlerini tamamen istemci tarafında yürütebiliyoruz.

Uygulamamızda bir öğrencinin adını ve soyadını taşıyacak bir Ogrenci sınıfı kullanacağız. JSON ile çeviri işlemleri yaparken elimizdeki çevireceğimiz nesnenin tipinin belirli şekilde tanımlanmış olması gerekiyor. O nedenle hemen aşağıdaki kod ile tipimizi tanımlayalım.

Public Class Ogrenci

 

    Private Padi As String

    Public Property Adi() As String

        Get

            Return Padi

        End Get

        Set(ByVal value As String)

            Padi = value

        End Set

    End Property

 

 

    Private PSoyadi As String

    Public Property Soyadi() As String

        Get

            Return PSoyadi

        End Get

        Set(ByVal value As String)

            PSoyadi = value

        End Set

    End Property

 

    Sub New()

 

    End Sub

 

    Sub New(ByVal adi As String, ByVal soyadi As String)

        Me.Adi = adi

        Me.Soyadi = soyadi

    End Sub

End Class

Bu basit işlemi tamamladıktan sonra uygulamamıza üç adet metin kutusu ve iki de düğme yerleştirelim. Bu metin kutularından ikisi öğrencinin adının ve soyadının gözükeceği yer, diğeri ise yarattığımız JSON verisinin yazdırılacağı konum olacak. Düğmelerimizi de işlemleri yapmak için kullanacağız.

<UserControl x:Class="JSON.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

      <TextBox Height="31" HorizontalAlignment="Left" Margin="22,19,0,0" VerticalAlignment="Top" Width="151" Text="Adı" x:Name="Adi1"/>

      <TextBox Height="26" HorizontalAlignment="Left" Margin="22,54,0,0" VerticalAlignment="Top" Width="151" Text="Soyadı" x:Name="Soyadi1"/>

      <TextBox Margin="22,142,23,19" Text="TextBox" x:Name="Sonuc"/>

      <Button Height="29" HorizontalAlignment="Right" Margin="0,99,97,0" x:Name="Dugme2" VerticalAlignment="Top" Width="102" Content="JSON'dan Al"/>

      <Button Height="29" HorizontalAlignment="Left" Margin="45,99,0,0" x:Name="Dugme1" VerticalAlignment="Top" Width="102" Content="JSON Yarat"/>

    </Grid>

</UserControl>

İlk olarak Dugme1 nesnesinin arkasına gerekli kodları yazarak metin kutuları içerisinden öğrencinin adını ve soyadını alıp bir öğrenci nesnesi yaratalım. Sonrasında da bu nesneyi JSON verisine çevirerek Sonuc adındaki metin kutusuna yazdıralım.

Dim Cevirici As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(Ogrenci))

Dim Veri As New IO.MemoryStream

Cevirici.WriteObject(Veri, New Ogrenci(Adi1.Text, Soyadi1.Text))

Sonuc.Text = Text.Encoding.UTF8.GetString(Veri.ToArray, 0, Veri.Length)

Cevirici adını verdiğim nesne bir DataContractJsonSerializer nesnesi. Bu nesnenin WriteObject metodunu kullanarak elimizdeki uygun bir .NET nesnesini JSON formatına çevirebiliyoruz. WriteObject metodu toplamda iki parametre alıyor; bunlardan ilki çeviri işlemi esnasında oluşan JSON verisinin yazdırılacağı Stream nesnesi, diğeri ise çevrilecek olan nesnenin ta kendisi. Ben bu örnekte bir MemoryStream kullandım. Son olarak eldeki Stream'i de bir metne çevirerek Sonuc adındaki metin kutusu içerisine yazdırıyoruz.

Böylece uygulamamızda dinamik olarak JSON yaratma sorununu çözmüş olduk. Tamamen istemci tarafında rahatlıkla yarattığımız .NET nesnelerini JSON formatına çevirebiliyoruz. Şimdi de tam tersi bir senaryoya göz atalım.

JSON verisinden .NET nesneleri yaratmak

Bir önceki bölümde kullandığımız örneği aynen kullanmaya devam edelim. Bu sefer de tam tersi bir işlem yaparak Sonuc adındaki metin kutusu içerisine yazılan JSON verisini okuyarak içerisinde öğrencinin adını ve soyadını alıp diğer metin kutularının içerisine yerleştirelim.

Dim Cevirici As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(Ogrenci))

Dim Veri As New IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Sonuc.Text))

Dim GenelOgrenci = CType(Cevirici.ReadObject(Veri), Ogrenci)

Adi1.Text = GenelOgrenci.Adi

Soyadi1.Text = GenelOgrenci.Soyadi

Her zamanki gibi ilk olarak Cevirici nesnemizi Ogrenci tipinden yaratıyoruz. Bu sefer DataContractJsonSerializer sınıfının ReadObject metodunu kullanacağız. ReadObject metodu okuyacağı veriyi bir Stream olarak istediği için Sonuc adındaki metin kutusu içerisindeki metinden ilk önce bir Byte dizisi sonra da bu diziden bir MemoryStream yaratıyoruz. Aldığımız MemoryStream'i Cevirici nesnemizin ReadObject metoduna verdiğimizde söz konusu metod bize bir Object döndürüyor. Doğal olarak JSON verisi içerisindeki nesnenin hangi .NET nesnesine denk geldiğini bilme şansı yok. O nedenle biz elle casting yaparak aldığımız Object tipindeki değişkeni Ogrenci tipine değiştiriyor ve gerekli verileri alarak diğer metin kutularının içerisine yerleştiriyoruz.

Her iki uygulamayı da bir örnek projede yaptığımızda ilk önce metin kutularına veri girerek JSON verisini yaratabiliyor sonrasında da JSON verisini Sonuc metin kutusunda elle değiştirip tekrar diğer metin kutularına güncel değerlerin aktarılabilmesi için DeSerialize işleminin yapılmasını sağlayabiliyoruz.

Uygulamamızın tam kodu aşağıdaki şekilde sonlanıyor.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Public Class Ogrenci

 

        Private Padi As String

        Public Property Adi() As String

            Get

                Return Padi

            End Get

            Set(ByVal value As String)

                Padi = value

            End Set

        End Property

 

 

        Private PSoyadi As String

        Public Property Soyadi() As String

            Get

                Return PSoyadi

            End Get

            Set(ByVal value As String)

                PSoyadi = value

            End Set

        End Property

 

        Sub New()

 

        End Sub

 

        Sub New(ByVal adi As String, ByVal soyadi As String)

            Me.Adi = adi

            Me.Soyadi = soyadi

        End Sub

    End Class

 

    Private Sub Dugme1_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme1.Click

        Dim Cevirici As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(Ogrenci))

        Dim Veri As New IO.MemoryStream

        Cevirici.WriteObject(Veri, New Ogrenci(Adi1.Text, Soyadi1.Text))

        Sonuc.Text = Text.Encoding.UTF8.GetString(Veri.ToArray, 0, Veri.Length)

    End Sub

 

    Private Sub Dugme2_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme2.Click

        Dim Cevirici As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(Ogrenci))

        Dim Veri As New IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Sonuc.Text))

        Dim GenelOgrenci = CType(Cevirici.ReadObject(Veri), Ogrenci)

        Adi1.Text = GenelOgrenci.Adi

        Soyadi1.Text = GenelOgrenci.Soyadi

    End Sub

End Class

Hepinize kolay gelsin.

Sunday, May 18, 2008 9:57:44 AM (GTB Standard Time, UTC+02:00)  #    Comments [3]   Silverlight 2.0  | 
 Tuesday, May 13, 2008

Bugün Konya, Selçuk Üniversitesin'deydim. Sabah 10.00'da başlayarak 19.00'a kadar WPF, AJAX, Silverlight ve LINQ konularını inceleyen bir seminer ile güzel bir gün geçirdik. Umarım "yol yorgunluğum" aktiviteye çok yansımamıştır. Bir gün öncesinde bildiğiniz üzere Çanakkale 18 Mart Üniversitesin'deydim ve akşam 23.00'da Çanakkale'den mecburen otobüs ile İstanbul'a döndüm. O saatte uçak vs yok. Sabaha karşı 05.00'de İstanbul'daydım ve 07.00 uçağı ile Konya'ya uçtum :) Durum böyle olunca hem uykusuzluk (buna alışkınım aslında) hem de sadece uçakta verilen abuk sandwich nedeniyle açlık (işte buna dayanamam!) nedeniyle performansımdan şüphe etmediğimi söylesem yalan olur.

Konya, Selçuk Üniversitesi
Konya, Selçuk Üniversitesi

Aktivitede katkılarından dolayı sevgili MSP, Okan Öztürkmenoğlu'na çok teşekkür ediyorum. Bereketine hayran kaldığım etli ekmek desteği ile tüm günü ayakta geçirebilmeme büyük katkıları oldu :)

Tekrar görüşmek üzere ;)

Tuesday, May 13, 2008 6:16:49 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   AJAX | LINQ | Seminer | Silverlight | Silverlight 2.0 | WPF  | 
 Monday, May 12, 2008

Bugün Çanakkale 18 Mart Üniversitesi'ndeydim. WPF ve Silverlight konulu toplam 6 saatlik bir seminerin sonunda ilk defa bir üniversitenin öğrencilerinden bu kadar çok iltifat duydum :) Hepiniz çok sağ olun arkadaşlar. Benim için de çok zevkli bir gündü, böyle ilgili bir kitleyle birşeyler paylaşabiliyor olmak gerçekten muhteşem. Özellikle bir arkadaşın "Uzaktan küçük gözüküyorsunuz hocam" yorumunu sanırım hayatım boyunca unutmayacağım :)

Çanakkale 18 Mart Üniversitesi, WPF ve Silverlight Semineri
Çanakkale 18 Mart Üniversitesi, WPF ve Silverlight Semineri

Organizasyonla ilgili özellikle sevgili Erçin Yontar'a çok teşekkür ediyorum. Çanakkale zaten bana yabancı olmayan bir şehir :) yine de sevgili Erçin iskeleden alıp iskeleye kadar yolculadı beni :) Herşey için çok çok teşekkürler arkadaşlar, tekrar görüşmek dileği ile ;)

Monday, May 12, 2008 6:21:07 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Seminer | Silverlight | Silverlight 2.0 | WPF  | 
 Sunday, May 11, 2008

Silverlight 2.0 ile beraber istemci taraflı CLR altyapısı ile aslında hayal bile edemeyeceğimiz bir sürü işlemi bildiğimiz .NET dilleri ile yapabiliyoruz. Birazdan yapacağımız örneği Silverlght 2.0 öncesi herhangi bir teknoloji ile uygulamaya kaltığımızda bir .NET yazılım geliştiricisi için çok daha acı verici bir süreç söz konusu olabilirdi. Oysa doğrudan istemci tarafında .NET kullanımı ile çok daha rahat bir platform sağlanabiliyor.

Silverlight 2.0 Beta 1 içerisinde ister farklı User Control yapıları olsun veya ister farklı görsel stiller kullanın belirli noktalarda dinamik olarak Gradient yapıları kurmanız gerekebiliyor. İşte tam da bu noktada bir rengin geçiş yapabileceği başka uygun bir rengi programatik olarak bulmak ciddi sıkıntı verebilir. Aslında en basit çözüm Expression Design gibi programlarda yapabildiğimiz; bir rengin Hue / Saturation / Lightness değerlerini değiştirmektir. Böylece rengin ana yapısı değişmese de parlaklık ve ışık miktarı değiştirilerek farklı geçişler sağlanabilir ve bu farklı renklerden Gradient'lar dinamik olarak yaratılarak rahatlıkla kullanılabilir. Fakat maalesef Silverlight ile beraber gelen yapıya baktığımızda biz renklerin RGB (Red, Green, Blue) olarak geldiğini görüyoruz. Peki Hue, Lightness ve Saturation nasıl hesaplanıyor? Bu konuda live.com'da ufak bir araştırma HSL ile RGB arasında çeviri işlemlerinin nasıl yapılacağını öğrenmemiz için yeterli. Maalesef internette bu işi hazır yapan bir kod bulamadım. Ben matematik hesaplamaların ve sisteminin mantığının detayına girmeden sizinle yazmış olduğum kodu paylaşacağım.

Namespace HSLveRGB

    Public Structure HslRenk

        Public Alpha As Double

        Public Hue As Double

        Public Saturation As Double

        Public Lightness As Double

 

        Private Function Normal(ByVal gelen As Double) As Double

            If gelen  < 0 Then

                gelen  += 1

            End If

            If gelen  > 1 Then

                gelen  -= 1

            End If

            Return gelen

        End Function

 

        Private Shared Function B2P(ByVal gelen As Byte) As Double

            Dim giden As Double = gelen

            giden  = giden  / 255

            Return giden

        End Function

 

        Private Shared Function P2B(ByVal gelen As Double) As Byte

            gelen *= 255

            gelen += 0.5

            If gelen > 255 Then

                gelen = 255

            End If

            If gelen < 0 Then

                gelen = 0

            End If

            Return CByte(gelen)

        End Function

 

        Public Shared Function FromColor(ByVal BirRenk As Color) As HslRenk

            Return HslRenk.FromArgb(BirRenk.A, BirRenk.R, BirRenk.G, BirRenk.B)

        End Function

 

        Public Function RengiAc(ByVal x As Double) As HslRenk

            Dim BirRenk As New HslRenk()

            BirRenk.Alpha = Me.Alpha

            BirRenk.Hue = Me.Hue

            BirRenk.Saturation = Me.Saturation

            BirRenk.Lightness = Math.Min(Math.Max(Me.Lightness + x, 0), 1)

            Return BirRenk

        End Function

 

        Public Shared Function FromArgb(ByVal Alpha As Byte, ByVal Kirmizi As Byte, ByVal Yesil As Byte, ByVal Mavi As Byte) As HslRenk

            Dim BirRenk As HslRenk = FromRgb(Kirmizi, Yesil, Mavi)

            BirRenk.Alpha = B2P(Alpha)

            Return BirRenk

        End Function

 

        Public Shared Function FromRgb(ByVal Kirmizi As Byte, ByVal Yesil As Byte, ByVal Mavi As Byte) As HslRenk

            Dim BirRenk As New HslRenk()

            BirRenk.Alpha = 1

            Dim red As Double = B2P(Kirmizi)

            Dim green As Double = B2P(Yesil)

            Dim blue As Double = B2P(Mavi)

            Dim max As Double = Math.Max(blue, Math.Max(red , green))

            Dim min As Double = Math.Min(blue, Math.Min(red , green))

            If max = min Then

                BirRenk.Hue = 0

            ElseIf max = red AndAlso green >= blue Then

                BirRenk.Hue = 60 * ((green - blue) / (max - min))

            ElseIf max = red AndAlso green < blue Then

                BirRenk.Hue = 60 * ((green - blue) / (max - min)) + 360

            ElseIf max = green Then

                BirRenk.Hue = 60 * ((blue - red) / (max - min)) + 120

            ElseIf max = blue Then

                BirRenk.Hue = 60 * ((red - green) / (max - min)) + 240

            End If

 

            BirRenk.Lightness = 0.5 * (max + min)

            If max = min Then

                BirRenk.Saturation = 0

            ElseIf BirRenk.Lightness <= 0.5 Then

                BirRenk.Saturation = (max - min) / (2 * BirRenk.Lightness)

            ElseIf BirRenk.Lightness > 0.5 Then

                BirRenk.Saturation = (max - min) / (2 - 2 * BirRenk.Lightness)

            End If

            Return BirRenk

        End Function

 

        Public Function RengiKoyulastir(ByVal x As Double) As HslRenk

            Return RengiAc(-x)

        End Function

 

        Private Function Hesap(ByVal Bir  As Double, ByVal Iki As Double, ByVal Uc As Double) As Double

            If Bir < (1 / 6) Then

                Return Iki  + ((Uc  - Iki ) * 6 * Bir )

            End If

            If Bir < 0.5 Then

                Return Uc

            End If

            If Bir < (2 / 3) Then

                Return Iki  + ((Uc  - Iki ) * 6 * ((2 / 3) - Bir ))

            End If

            Return Iki

        End Function

 

        Public Function ToColor() As Color

            Dim Bir As Double = 0

            If Lightness < 0.5 Then

                Bir  = Lightness * (1 + Saturation)

            Else

                Bir  = Lightness + Saturation - (Lightness * Saturation)

            End If

            Dim Iki As Double = (2 * Lightness) - Bir

            Dim Key As Double = Hue / 360

            Dim red As Double = Hesap(Normal(Key + (1 / 3)), Iki , Bir )

            Dim green As Double = Hesap(Normal(Key), Iki , Bir)

            Dim blue As Double = Hesap(Normal(Key - (1 / 3)), Iki , Bir )

            Return Color.FromArgb(P2B(Alpha), P2B(red ), P2B(green), P2B(blue))

        End Function

    End Structure

End Namespace

Yukarıdaki kodu isterseniz harici bir DLL olarak derleyerek tüm projelerinizde kullanabilirsiniz. Silverlight içerisindeki kullanımına da ufak bir örnek ile göz atalım. Aşağıdaki şekilde Silverlight 2.0 uygulamamıza bir dikdörtgen ve Slider yerleştirerek Slider ile dikdörtgen içerisindeki rengi değiştireceğiz.

<UserControl x:Class="HSL2RGB.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

      <Rectangle HorizontalAlignment="Stretch" Margin="43,23,47,124" VerticalAlignment="Stretch" Fill="#FFD05D5D" Stroke="#FF000000" x:Name="Kutu"/>

      <Slider Height="24" Margin="43,0,47,82" VerticalAlignment="Bottom" x:Name="Slider" Maximum="1" LargeChange="0.1" SmallChange="0.01"/>

    </Grid>

</UserControl>

Özellikle Slider'ın alabildiği maksimum değere dikkat etmekte fayda var. Bu değer üzerinden bizim daha önceki HSL nesnesini kullanarak RengiAc ve RengiKoyulastir metodlarını çalıştıracağız. Geçelim uygulamanın kod kısmına.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim AnaRenk As Color = System.Windows.Media.Color.FromArgb(100, 255, 50, 50)

 

    Private Sub Slider_ValueChanged(ByVal sender As Object, ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of Double)) Handles Slider.ValueChanged

        CType(Kutu.Fill, SolidColorBrush).Color = HSLveRGB.HslRenk.FromColor(AnaRenk).RengiAc(e.NewValue - 0.5).ToColor

    End Sub

End Class

Yukarıdaki kod içerisinde ilk olarak dikkat edilmesi gereken nokta bizim global AnaRenk değişkenimiz. Bu değişken içerisinde sürekli bizim ana rengimiz duruyor ve bu renk üzerinden gerekli işlemleri yaparak yarattığımız yeni rengi Kutu nesnesinin Fill özelliğine atanmış SolidColorBrush'ın Color özelliğine aktarıyoruz. RengiAc metodunu kullanırken de Slider'ın mevcut değerine göre -0.5 ile 0.5 arasında bir değer gelmesini sağlıyoruz. Zaten aynı metod kendisine eksi değer verildiğinde rengi açmak yerine kapatıyordu.

Böylece rahatlıkla renklerin Hue / Saturation ve Lightness özellikleri Silverlight tarafında dinamik olarak değiştirilebiliyor. Bu özellikleri kullanarak sadece tek bir renk üzerinden giderek başka renkler de yaratıp güzel Gradient yapıları kurabilirsiniz.

Hepinize kolay gelsin.

Sunday, May 11, 2008 1:57:27 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, May 10, 2008

Silverlight 2.0 ile beni en çok şaşırtan özelliklerden biri de WPF'in web sürümü diyebileceğimiz ve WPF'e kıyasla bir çok eksiği olan bir torun olarak Silverlight ile beraber artık WPF'de bulunmayan bazı kontrollerin geliyor olması. Tahminen uzun vadede her iki taraf da birbirinden besleniyor olacaktır. Bugün baktığımızda ilk dikkati çeken kontrollerden biri de maalesef WPF tarafında olmayan Calendar ve DateTimePicker kontrolleri. Bu yazımızda bu iki kontrolü ve bu kontrollerle neler yapabileceğimizi inceleyeceğiz.

Calendar kontrolü şekilden şekilde girebiliyor.
Calendar kontrolü şekilden şekilde girebiliyor.

Yukarıdaki şekli ile birer Calender kontrolü yaratmak için tek yapmanız gereken XAML kodunuzu aşağıdaki şekilde düzenlemek.

<UserControl x:Class="Calendar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Calendar Margin="21,20,145,57"/>

  </Grid>

</UserControl>

Tek yaptığımız bir Calendar tagı açarak kenarlardan olan uzaklığını belirtmek. "Çocuk oyuncağı" denen bu olsa gerek. Peki daha neler yapabiliriz? Aslında bu aşamadan sonra bahsedeceğimiz tüm özellikler Calendar ve DatePicker kontrolleri için birebir aynı. O nedenle gelin öncesinde bir de DatePicker kontrolünün XAML koduna bakalım.

<DatePicker Height="20" Margin="42,0,156,23" VerticalAlignment="Bottom"/>

DatePicker kontrolünü de sahneye yerleştirmek en az Calendar kontrolü kadar basit. Bu durumda hızlıca programatik işlevselliklere göz atabiliriz. Aşağıdaki gibi bir Silverlight uygulaması hazırlayarak kodlamaya başlayalım.

<UserControl x:Class="Calendar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Calendar Margin="21,20,145,57" x:Name="Takvim"/>

    <DatePicker Height="20" Margin="42,0,156,23" VerticalAlignment="Bottom" x:Name="TarihSecici"/>

  </Grid>

</UserControl>

Uygulamamızda Takvim adında bir Calendar kontrolü ve TarihSecici adında bir DateTimePicker bulunuyor. Bu kontroller Silverlight uygulaması ile beraber ilk gösterildiklerinde içlerinde herhangi bir tarih seçili gelmiyor. Oysa aşağıdaki şekilde güncel tarihi seçili hale getirebilirsiniz.

        Takvim.SelectedDate = Date.Now

        TarihSecici.SelectedDate = Date.Now

Makalemizin en üstündeki görsele baktığınızda Calendar kontrolünün iki farklı görsel durumunun bulunduğunu görebilirsiniz. Normal şartlarda Calendar kontrolü günleri gösterecek şekilde açılıyor, sonrasında eğer üstteki ay ismine tıklarsanız ayların seçilebileceği arayüz geliyor. Oysa isterseniz Calendar kontrolü sayfada ilk açıldığında da ayların seçilebileceği arayüzün otomatik gelmesini sağlayabilirsiniz.

        Takvim.DisplayMode = CalendarMode.Year

Eğer Calender nesnesinin DisplayMode özelliği Month olursa tam bir ayı gösteriyor, Year şeklinde düzenlendiğinde ise tüm yılı yani ayları gösteriyor. Bunun haricinde isterseniz her iki kontrolün de hangi tarih aralıklarını gösterebileceğini ek olarak düzenleyebilirsiniz.

        TarihSecici.SelectableDateStart = Date.Today.Subtract(New TimeSpan(5, 0, 0, 0))

        TarihSecici.SelectableDateEnd = Date.Today.AddDays(5)

Yukarıdaki kod içerisinde DatePicker kontrolümüzün SelectableDateStart ve SelectableDateEnd özelliklerine DatePicker içerisinde seçilebilecek başlangıç ve bitiş tarihlerini aktarıyoruz. Bunu yaparken söz konusu tarihlerin hesaplamalarını da tabi ki dinamik olarak yapabilirsiniz. Böylece bu örneğimizde kontrol sürekli olarak mevcut tarihden 5 gün öncesinin ve 5 gün sonrasının seçilebilmesine olanak tanıyacaktır.

        TarihSecici.DisplayDateStart = Date.Today.Subtract(New TimeSpan(5, 0, 0, 0))

        TarihSecici.DisplayDateEnd = Date.Today.AddDays(5)

Seçili tarihleri belirlemenin yanı sıra isterseniz belirli tarihleri seçilemez yapmanın yanı sıra tamamen o tarihlerin gösterilmemesini de sağlayabilirsiniz. Bunun için DisplayDateStart ve DisplayDateEnd özelliklerinden faydalanabilirsiniz.

SelectableDateve DisplayDate arasında fark.
SelectableDateve DisplayDate arasında fark.

Hepinize kolay gelsin.

Saturday, May 10, 2008 1:46:36 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Friday, May 09, 2008

Socket programlama Silverlight çıktığından beri biz yazılım geliştiricilerin en büyük hayali ve bu hayal gerçek oluyor. Silverlight 2.0 Beta 1 ile beraber Socket Programlama karşımızda. Yani artık istemci ile sunucu arasında TCP/IP ile haberleşmek mümkün. Tabi belirli kurallar var; bu kurallardan ilki sunucudaki uygulamanın istemci uygulamanın yüklendiği web sitesi ile aynı konumda olması. Yani sunucu uygulamanızın web siteniz ahmet.com ise ahmet.com'un reverse DNS Look-Up ile bakıldığında çıkan IP adresine sahip sunucuda bulunması gerekiyor. Bu durumun Silverlight'ın Beta 1 sonrası sürümlerinde policyfile gibi sistemlerde daha esnek hale getirileceği söylentiler arasında fakat baktığımızda şu anki hali ile bile süper bir potansiyel söz konusu.

Peki nedir bunun avantajı?

Diyorum ya, hayalimizdi diye, peken neden? Web sitelerinde güncel bilgi göstermek her zamanki en büyük derttir. Bunu yapabilmek için çok eskilere döndüğümüzde bazı meta tagları ile belirli aralıkla sayfanın refresh atmasını sağladığımız günler bile olurdu. IFRAME vs nin gelmesi ile en azından bunu sayfada kısmi bölümlerde uygulayabilir hale geldik. Sonrasında AJAX geldi ve çok daha sinsi bir şekilde kullanıcı farkında olmadan belirli aralıklarla sunucudan yeni veri talebinde bulunarak sayfa değişmeden yeni içeriği gösterebildik. Oysa hep bizi rahatsız eden bir nokta vardı, o da şu; sürekli istemciden sunucuya bağlanarak bir veri değişikliğinin olup olmadığını kontrol etmek durumunda kalıyorduk. Sunucuya "Yeni birşey var mı?" diye dakikada bir soruyor ve çoğunda da hüsran ile geri dönüyordu. Keşke sunucu bize bir "Alo" diyebilse ve değişiklik olduğunda istemciyi haberdar edebilse? Teknik olarak bu güvenlik sebepleri nedeniyle zaten mümkün değil çünkü bir istemci bilgisayara dışarıdan içeriye bağlantı kuramazsınız (kuramamanız gerekir). Peki nasıl oluyor da Socket Programming bunu aşıyor? Aslında aşmıyor, yine istemci sunucuya bağlanıyor fakat söz konusu bağlantı TCP bazında olduğu herhangi bir trafiğe neden olmadan sürekli açık tutulabiliyor. Durum böyle olunca sunucu kendisine bağlı istemciye istediğinde söz konusu bağlantı üzerinden rahatlıkla ulaşabiliyor.

Sunucu tarafından işe başlayalım.

İlk olarak sunucudaki programımızı hazırlayalım. Söz konusu program kendisine gelen tüm istekleri karşılayarak gerektiğinde istemcilere veri gönderecek. Bizim programımız içerisinde bir TextBox bulunacak ve kutu içerisine metin yazıldıkça kendisine bağlı tüm istemcilere bu metin sürekli gönderilecek.

    Dim Baglilar As New System.Collections.Generic.List(Of System.IO.StreamWriter)

    Dim yeniTR As System.Threading.Thread

    Dim TCPBaglantilari As New System.Threading.ManualResetEvent(True)

    Dim Dinleyici As New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 4530)

İlk olarak global değişkenlerimizi tanımlıyoruz. Bunlardan ilki olan Baglilar değişkeni sunucuya bağlı olan istemcilere veri gönderecek olan StreamWriter nesnelerini bir listesini taşıyacak. Böylece istediğimizde bu liste içerisinde gezerek tüm bağlı olan istemcilere veri gönderebileceğiz. yeniTR adındaki değişkenimizi yeni bir Threat yaratmak ve her yerden kendisine ulaşabilmek için kullanacağız. TCPBaglantilari değişkenimiz var olan Threat'ın blocklanması ve tüm event-larının sıfırlanması için kullanılacak. Dinleyici adındaki değişkenimizi ise tüm istemcileri dinleyecek olan ve gelen bağlantıları algılayacak olan TCPListener nesnemizin ta kendisi. Gördüğünüz gibi bu nesneyi tanımlarken iki parametre aktarmışız. Bunlardan ilki herhangi bir IP adresi üzerinden bu uygulamaya bağlanılabileceği anlamına gelirken diğer ise sadece 4530 portu üzerinden bağlantı yapılabileceği anlamına geliyor. Silverlight 2.0 Beta 1 şu anda 4502-4532 aralığındaki portları kullanabiliyor.

    Private Sub btn_Basla_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Basla.Click

        yeniTR = New System.Threading.Thread(AddressOf Bekle)

        yeniTR.Start()

    End Sub

Uygulamamızdaki düğmeye basıldığında dinleme işlemini başlatmak üzere yeni bir Thread yaratıyoruz. Söz konusu Thread Bekle Sub'ına bağlı. Yarattığımız thread'i hemen başlatıp yolumuza devam edelim.

    Sub Bekle()

        Dinleyici.Start()

        While True

            TCPBaglantilari.Reset()

            Dinleyici.BeginAcceptTcpClient(New System.AsyncCallback(AddressOf BaglantiGeliyor), Nothing)

            TCPBaglantilari.WaitOne()

        End While

    End Sub

Yeni Thread içerisinde hemen Dinleyici nesnemizi başlatıyoruz ve kısır bir döngüye giriyoruz. Sürekli olarak elimizdeki Threadi sıfırlayarak Dinleyici'nin BeginAcceptTcpClient metodu ile istemciden bir bağlantı geleceğini belirterek WaitOne metodu ile de bekliyoruz. Eğer burada bir bağlantı gelir ve başarılı veya başarısız şekilde sonuçlanırsa bu döngü başa gelerek tekrar yeni bir bağlantı bekleyecek. BeginAcceptTcpClient içerisinde parametre olarak verdiğimiz BaglantiGeliyor event-handları herhangi bir bağlantı geldiğinde çalıştırılacak.

    Private Sub BaglantiGeliyor(ByVal ar As System.IAsyncResult)

        TCPBaglantilari.Set()

        Dim Musteri As System.Net.Sockets.TcpClient = Dinleyici.EndAcceptTcpClient(ar)

        If Musteri.Connected Then

            Dim yazici As New System.IO.StreamWriter(Musteri.GetStream)

            yazici.AutoFlush = True

            Baglilar.Add(yazici)

            yazici.Write("Bağlandınız.")

        End If

    End Sub

Baglanti geldiği anda bekleyen Threat'leri devam ettirmek adına TCPBaglantilari.Set() metodunu çağırıyoruz. Unutmayalım ki programımız aynı anda sadece tek istemcinin bağlantısını authenticate edebilir, yani diğerleri bir önceki istemci bağlanıp bağlantısını oluşturana kadar bekleyecektir. Bu noktada artık istemci bağlantı kurma işlemini tamamladığı için diğerlerine yol veriyoruz. Musteri adında bir TCPClient yarattıktan sonra Dinleyici'nin EndAcceptTcpClient metodu ile args parametresi üzerinden gelen Request'i alıyoruz. Eğer Musteri bağlı ise, yani Connected ise artık sıra geldi ona veri göndermeye. Musteri'nin yani TCPClient'ın Stream'ini alarak bundan bir StreamWriter oluşturuyoruz. Bu Stream üzerinden artık istemciye istediğimiz veriyi gönderebiliriz.

Unutmayın ki uygulamamızda bir TextBox vardı ve içerisine birşey yazıldığında tüm bağlı kullanıcılara gönderecektik. Bunun için sonra kullanabilmek adına elimizdeki canlı Stream'leri saklamak sorundayız. Global olarak tanımladığımız Baglilar adında Generic.List'e elimizdeki Stream'i aktarıyoruz. Bu arada kullanıcıya "Bağlandınız" diye de bir metin gönderiyoruz.

    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

        For Each x As System.IO.StreamWriter In Baglilar

            x.Write(TextBox1.Text)

        Next

    End Sub

Artık TextBox içerisinde değişiklik olunca bunu istemcilere göndermek çok kolay. Basit bir şekilde Generic.List içerisinde gezin ve her Stream'e elinizdeki veriyi gönderin.

İstemci tarafında neler olacak?

Silverlight tarafında çok basit görsellikte bir uygulamamız olacak. Sadece bir TextBlock! Uygulama tarayıcı içerisinde ilk açıldığında sunucuya bağlanacak ve gelen veriyi sürekli olarak söz konusu TextBlock içerisinde gösterecek.

<UserControl x:Class="SocketsClient.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <TextBlock Margin="42,46,37,125" Text="TextBlock" TextWrapping="Wrap" x:Name="Metin"/>

  </Grid>

</UserControl>

XAML kodumuzu yukarıdaki şekilde düzenledikten sonra hemen code-behind dosyasına geçerek bağlantı kodlarımızı yazmaya başlayalım.

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Hat As New System.Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)

        Dim Args As New System.Net.Sockets.SocketAsyncEventArgs

 

        Args.UserToken = Hat

        Args.RemoteEndPoint = New System.Net.DnsEndPoint("localhost", 4530)

        AddHandler Args.Completed, AddressOf Baglandi

        Hat.ConnectAsync(Args)

    End Sub

Silverlight uygulaması ilk yüklendiğinde hemen bir Socket bağlantısı yaratmak için System.Net.Sockets.Socket üzerinden ilerliyoruz. Hat adındaki değişkenimizi yaratırken verdiğimiz parametrelerden ilki olan InterNetwork bizim bağlantı için IPv4 kullanacağımızı ve ikinci parametre de TCP kullanacağımızı belirtiyor. Asenkron bir çalışma yapısı için bir de SocketAsyncEventArgs nesnesi yaratarak söz konusu nesneyi Hat adındaki Socket'imize bağlıyoruz. Args'ın RemoteEndPoint özelliği istemcinin bağlanacağı sunucunun adresini ve port bilgisini içeriyor. Bağlanti oluşturulduğunda elimizdeki SocketAsyncEventArgs nesnesi olan Args'ın Completed event-handları çalışacağı için ona da dinamik bir event-handler olarak Baglandi metodunu atıyoruz. Son olarak ConnectAsync diyerek Socket değişkenimizin eldeki SocketAsyncEventArgs ile sunucuya bağlanmasını sağlıyoruz.

    Private Sub Baglandi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen(1024) As Byte

        e.SetBuffer(Gelen, 0, Gelen.Length)

        RemoveHandler e.Completed, AddressOf Baglandi

        AddHandler e.Completed, AddressOf Geldi

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

Artık istemci sunucuya bağlandığında göre sıra geldi karşı taraftan yeri geldiğinde veriyi almaya. Hatta ilk bağlantı esnasında hatırlarsanız bizim sunucumuzun "Bağlandınız" diye bir metin gönderiyordu. Gelen veriyi alabilmek için ve sürekli gelen veriyi dinlemek için eldeki Socket'i alarak sürekli dinleme durumunda olmamız şart. Kodumuzdaki event-handler içerisinde e parametresi aslında bizim bir önceki adımda tanımladığımız Args adaınki SocketAsyncEventArgs'ın ta kendisi. SetBuffer ile veriyi önbelleklemek için kullanacağımız ayarları da bir Byte değişkeni üzerinden aktardıktan sonra ilginç bir şekilde elimizdeki event-handlerları değiştiyoruz. Bundan sonra Args'ın Compeleted durumu yeni bir bağlantı oluştuğunu değil yeni veri geldiğini bildireceği için farklı bir event-handlerı bağlamamız gerekiyor. Baglandi adındaki metodumuzla Args'ın ilişkisi keserek Geldi adında farklı bir metoda bağlıyoruz. Son olarak Page.Load'a atadığımız ve e.UserToken üzerinden alabileceğimiz ana Socket değişkenimizi de yakalayarak ReceiveAsync metodu ile veri alımını başlatıyoruz.

Geldi ve Baglandi metodları aslında Silverlight içerisinde ayrı bir Thread içerisinde çalışıyor. Bu nedenle tüm bu işlemler yapılırken kullanıcının uygulama ile olan interaktivitesi kesinlikle kesilmiyor. Tabi ayrı bir Thread gibi davranıyor olmasını dezavantajı ise birazdan karşımıza çıkacak. Kısır döngü içerisinde süreki ReceiveAsync ile sunucuyu dinlerken istemci tarafında görsel arayüzde değişiklik yapamayacağız. Bu da bizim sunucudan veri alabilmemizi fakat ekranda göstermememize neden olacak. Tabi demokrasilerde çare tükenmez...

    Delegate Sub MyDelegate(ByVal myArg2 As String)

 

    Sub GelGel(ByVal x As String)

        Metin.Text = x

    End Sub

İlk olarak bir Delegate tanımlayacağız, söz konusu delegemiz sadece bir parametre alacak. Ayrıca bir de Sub yaratıyoruz. Aynı şekilde Sub'da bir metin parametresi alıyor ve bizim uygulamamızda adı Metin olan TextBlock içerisine yerleştiriyoruz. İşte bu yapı ile biraz önce bahsettiğimiz sorundan kurtuluyor olacağız.

    Private Sub Geldi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen As String = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred)

        Me.Dispatcher.BeginInvoke(New MyDelegate(AddressOf GelGel), New String() {Gelen})

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

Aslında sunucudan gelen veriyi almak çok kolay. Kodumuz içerisindeki ilk satır bu işi hallediyoruz. Esas mesele veriyi aldıktan sonra sahnede göstermek. Dispatcher nesnesi belki de Silverlight içerisinde en ilginç yapılardan biri; Dispatcher ile mevcut Thread'i yakalayarak BeginInvoke ile başka bir metod çalıştırıyoruz. Çalıştıracağımız metodu sunucudan gelen veriyi parametre olarak vereceğiz ve söz konusu metod (GelGel) bu veriyi alarak sahnedeki Metin adındaki TextBlock içerisine yerleştirecek. BeginInvoke ile ilgili işimizi de tamamladıktan sonra artık tekrar sunucunun dinlenmeye başlanması için elimizdeki Socket'i yakalayarak ReciveAsync metodunu çalıştırıyoruz. Bu sistem böyle sonsuza tek dönecek ve sunucudan gelen veri sürekli olarak tüm istemcilerde anında gösterilecek.

Son olarak hem istemci hem de sunucu uygulamanın tam kodunu sizlerle paylaşmak istiyorum.

[İstemci: Silverlight uygulaması]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Dim Hat As New System.Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)

        Dim Args As New System.Net.Sockets.SocketAsyncEventArgs

 

        Args.UserToken = Hat

        Args.RemoteEndPoint = New System.Net.DnsEndPoint("localhost", 4530)

        AddHandler Args.Completed, AddressOf Baglandi

        Hat.ConnectAsync(Args)

    End Sub

 

    Private Sub Baglandi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen(1024) As Byte

        e.SetBuffer(Gelen, 0, Gelen.Length)

        RemoveHandler e.Completed, AddressOf Baglandi

        AddHandler e.Completed, AddressOf Geldi

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

 

    Private Sub Geldi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen As String = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred)

        Me.Dispatcher.BeginInvoke(New MyDelegate(AddressOf GelGel), New String() {Gelen})

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

 

    Delegate Sub MyDelegate(ByVal myArg2 As String)

 

    Sub GelGel(ByVal x As String)

        Metin.Text = x

    End Sub

 

End Class

[Sunucu: Winforms Uygulaması]

Public Class Form1

 

    Dim Baglilar As New System.Collections.Generic.List(Of System.IO.StreamWriter)

    Dim yeniTR As System.Threading.Thread

    Dim TCPBaglantilari As New System.Threading.ManualResetEvent(True)

    Dim Dinleyici As New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 4530)

 

    Private Sub btn_Basla_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Basla.Click

        'İzin Verilen Port Aralığı 4502-4532

        yeniTR = New System.Threading.Thread(AddressOf Bekle)

        yeniTR.Start()

    End Sub

 

    Sub Bekle()

        Dinleyici.Start()

        While True

            TCPBaglantilari.Reset()

            Dinleyici.BeginAcceptTcpClient(New System.AsyncCallback(AddressOf BaglantiGeliyor), Nothing)

            TCPBaglantilari.WaitOne()

        End While

    End Sub

 

    Private Sub BaglantiGeliyor(ByVal ar As System.IAsyncResult)

        TCPBaglantilari.Set()

        Dim Musteri As System.Net.Sockets.TcpClient = Dinleyici.EndAcceptTcpClient(ar)

        If Musteri.Connected Then

            Dim yazici As New System.IO.StreamWriter(Musteri.GetStream)

            yazici.AutoFlush = True

            Baglilar.Add(yazici)

            yazici.Write("Bağlandınız.")

        End If

 

    End Sub

 

    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

        For Each x As System.IO.StreamWriter In Baglilar

            x.Write(TextBox1.Text)

        Next

    End Sub

End Class

Hepinize kolay gelsin.

Friday, May 09, 2008 12:47:14 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Thursday, May 08, 2008

Herhangi bir içeriği Silverlight 2.0 arayüzlerinde göstermek istediğinizde özellikle veri bağlanabilir çoğu kontrolün kendi içerisinde "ScrollBar" (Kaydırma Çubukları) içerdiğini görebilirsiniz. Fakat bazı durumlarda bu hazır kontrolleri kullanmadığınızda veya scrollbar özelliği bulunmayan bazı yapı taşı niteliğinde kontrolleri beraber kullanmak istediğiniz ayrıca bir ScrollBar'a ihtiyacınız olabilir. Bu gibi durumlarda bize scrollbar özellikleri ekleme konusunda ScrollViewer kontrolü yardımcı oluyor.

Yapacağımız ilk örnekte 1024*768 piksel büyüklüğünde bir resmi uygulamamıza ekleyeceğiz. Fakat biz bu resim nesnesini tam ekran göstermek istemiyoruz. Uygulamamız içerisinde ufak bir karede göstererek insanların istiyorlarsa ScrollBar'lar aracılığı ile resmi gezmesini istiyoruz. Bu durumda aslında yapmamız gereken çok basit. Aşağıdaki XAML kodunu yaratacak şekilde Image nesnemizi bir ScrollViewer içerisine yerleştirmemiz yeterli.

<UserControl x:Class="ScrollBar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">

    <Grid x:Name="LayoutRoot" Background="White">

      <ScrollViewer Margin="0,0,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">

        <Image Height="768" Width="1024" Source="Forest.jpg"/>

      </ScrollViewer>

    </Grid>

</UserControl>

Gördüğünüz gibi ScrollViewer nesnemizin içerisinde kocaman bir resim var. ScrollViewer içerisine programatik olarak farklı nesnelerin de yerleştirilebiliyor olabilirdi. O nedenle biz ScrollViewer'a ait HorizontalScrollBarVisibility ve VerticalScrollBarVisibility özelliklerini de Auto yaparak ScrollBar'ların sadece gerektiğinde gözükmesini sağladık. Zaten varsayılan ayarları ile maalesef yatay ScrollBar gösterilmiyor o nedenle her halükarda bu ayarları değiştirmek şart.

ScrollViewer kontrolü iş başında.
ScrollViewer kontrolü iş başında.

Kullanımın ne kadar basit olduğunu sanırım daha da anlatmaya gerek yok. Gelin biraz daha karışık bir örneğe doğru yola çıkalım. Varsayalım ki ScrollViewer ile beraber gelen kaydırma çubukları yerine kendi oluşturduğunuz bazı düğmeleri kullanarak kaydırma işlemi yaptırmak istiyorsunuz, bu durumda ne yapabilirdik?

İlk olarak örneğimizin görsel kısmını hazırlayarak uygulamamıza iki düğme ekleyelim. Bu düğmeler rahatlıkla farklı görsellikler atanarak daha anlamlı hale getirilebilir. Ben odak noktamızı kaybetmeme adına düğmelerin görsel özellikleri ile ilgilenmeyeceğim.

<UserControl x:Class="ScrollBar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">

  <Grid x:Name="LayoutRoot" Background="White">

    <ScrollViewer Margin="0,0,63,0" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" x:Name="Scroll">

      <Image Height="768" Width="1024" Source="Forest.jpg"/>

    </ScrollViewer>

    <Button Height="57" HorizontalAlignment="Right" Margin="0,8,8,0" VerticalAlignment="Top" Width="51" Content="Yukarı" x:Name="Yukari"/>

    <Button Height="46" HorizontalAlignment="Right" Margin="0,0,8,8" VerticalAlignment="Bottom" Width="51" Content="Aşağı" x:Name="Asagi"/>

  </Grid>

</UserControl>

Kodumuz içerisinde önemli birkaç nokta var. Bunlardan ilki ScrollViewer kontrolümüzün VerticalScrollBarVisibility ve HorizontalScrollBarVisibility özelliklerinin Hidden olarak ayarlanmış olması gerektiği. Eğer bu özellikleri Disable olarak ayarlarsanız maalesef birazdan yapacağımız şekilde ScrollViewer'ın kaydırma özelliklerinden faydalanamayız. Oysa biz işimizi olabildiğince basite indirgemek ve kolaylaştırmak istiyoruz. O nedenle bu özellikler Hidden olması ve ScrollViewer'dan faydalanmamız şart. Bu haldeyken zaten ScrollBar'lar hiçbir şekilde gözükmeyecektir.

Sahnemizde ayrıca iki adet de düğme var. Bu düğmelere her basıldığında bir miktar scroll yaptırmak istiyoruz. Aslında bizim örneğimizde hem yatay hem de dikey kaydırma çubukları gerektiği için toplam dört düğme gerekirdi. Fakat ben şimdilik sadece dikey kaydırma çubuğunu simüle edeceğim, aynı sistemi yatay için kullanmak size kalıyor.

Private Sub Asagi_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Asagi.Click

    If Scroll.ScrollableHeight > 0 Then

        Scroll.ScrollToVerticalOffset(Scroll.VerticalOffset + 10)

    End If

End Sub

 

Private Sub Yukari_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Yukari.Click

    If Scroll.ScrollableHeight > 0 Then

        Scroll.ScrollToVerticalOffset(Scroll.VerticalOffset - 10)

    End If

End Sub

Hem Yukari hem de Asagi adindaki düğmelerimize yukarıdaki şekilde kodlarımızı yazdığımızda düğmelere her basıldığında ScrollViewer içerisindeki resim 10 piksel yukarı veya aşağıya doğru kayıyor. Kodumuzu incelediğimizde basit bir IF kontrolü ile ScrollViewer'ın yükseklik olarak kaydırılabilip kaydırılamayacağını öğreniyoruz eğer ScrollableHeight sıfırdan büyük ise demek ki kaydırma işlemi yapabiliriz. Kaydırma işlemini yapabilmek için mevcut VerticalOffset üzerinden konumu alarak üzerine 10 piksel ekleyip veya çıkartıp bu konuma scroll edilebilmesi için de ScrollToVerticalOffset metodunu kullanıyoruz. Bu metod almış olduğu Offset değerine scroll ediyor.

Daha kaygan bir Scroll olmaz mı?

Yukarıdaki örneğimizi denediğinizde düğmeye her bastığımızda 10 piksellik bir kayma göreceksiniz. Bu durum sizi de benim gibi rahatsız ettiyse daha hoş bir çözüme doğru ilerleyebiliriz. Rahatsızlık yaratan aslında iki konu var, birincisi kullanıcı kaydırma işlemine devam etmek için milyonlarca kez düğmeye tıklamak zorunda. Bu hiç de hoş bir durum değil. Oysa biz düğmeye tıklandığı anı yakalayıp kullanıcı düğmeyi bırakana kadar kaydırmaya devam etsek süper olurdu. Düğmeye fare ile tıklandığı ve bırakıldığı anları yakalamak için rahatlıkla MouseLeftButtonDown ve MouseLeftButtonUp eventlarını kullanabiliriz. Tek yapmamız gereken bu arada sürekli kaydırma işlemi yapmak. Hatta bu kaydırma işlemini de 20 milisaniyede 1 piksel şeklinde yaparsak aslında çok daha hoş bir kaydırma efekti yaratmış oluruz.

Peki tüm bunları nasıl yapacağız. Silverlight 2.0 Beta 1 ile beraber gelen DispatchTimer nesnesini kullanacağız. Bu aslında bizim bildiğimiz Winforms'daki Timer'dan pek farklı değil. Esasen tek farkı istemci tarafında farklı bir Threat içerisinde çalışıyormuş gibi davranması.

Dim Timer As Windows.Threading.DispatcherTimer

İlk olarak yukarıdaki şekilde Timer değişkenimizi global olarak tanımladık. Global tanımlamamızın nedeni hem MouseLeftButtonDown hem de MouseLeftButtonUp durumlarında bu Timer'a başvuracak olmamız. Aslında yapacağımız esas işlemi Timer'ı MouseLeftButtonDown durumunda yani kullanıcı düğmeye basında başlatmak ve MouseLeftButtonUp durumunda ise yani kullanıcı düğmeyi bıraktığında ise durdurmak.

    If Scroll.ScrollableHeight > 0 Then

        Timer = New Windows.Threading.DispatcherTimer

        Timer.Interval = New TimeSpan(0, 0, 0, 0, 20)

        AddHandler Timer.Tick, AddressOf TimerTick

        Timer.Start()

    End If

Yukarıdaki kodumuzu düğmemizin MouseLeftButtonDown durumuna yazıyoruz. Kullanıcı düğmeye tıkladığı anda global değişkenimize yeni bir DispatchTimer nesnesi aktararak Interval değerini 20 milisaniye olarak düzenliyoruz. Böyleceher 20 milisaniyede bir bir sonraki adımda DispatchTimer nesnesine bağladığımız Tick event-handları çalıştırılıyor olacak. Tüm ayarlarımızı tamamladıktan sonra DispatchTimer'ın Start metodu ile işlemi başlatıyoruz.

Sub TimerTick(ByVal sender As Object, ByVal e As EventArgs)

    Scroll.ScrollToVerticalOffset(Scroll.VerticalOffset + 1)

End Sub

Timer'ın her Tick durumunda daha önce kullandığımız kodu kullanarak kaydırma işlemi yapıyoruz. Bu sefer Tick durumları 20 milisaniyede bir olacağı için sadece 1 piksellik bir kayma yaratacağız.

Private Sub Asagi_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Asagi.MouseLeftButtonUp

    Timer.Stop()

End Sub

Son olarak düğmenin MouseLeftButtonUp durumunda ise Timer'ımızı durdurarak kayma işlemini sonlandırıyoruz. Uygulamamızı hem Asagi hem de Yukari düğmeleri için tamamladığımızda kodumuz aşağıdaki şekilde sonuçlanıyor.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim Timer As Windows.Threading.DispatcherTimer

 

    Private Sub Asagi_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Asagi.MouseLeftButtonDown, Yukari.MouseLeftButtonDown

        If Scroll.ScrollableHeight > 0 Then

            Timer = New Windows.Threading.DispatcherTimer

            Timer.Interval = New TimeSpan(0, 0, 0, 0, 20)

            AddHandler Timer.Tick, AddressOf TimerTick

            Timer.Start()

        End If

    End Sub

 

    Sub TimerTick(ByVal sender As Object, ByVal e As EventArgs)

        If Yukari.IsFocused Then

            Scroll.ScrollToVerticalOffset(Scroll.VerticalOffset - 1)

        Else

            Scroll.ScrollToVerticalOffset(Scroll.VerticalOffset + 1)

        End If

    End Sub

 

    Private Sub Asagi_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Asagi.MouseLeftButtonUp, Yukari.MouseLeftButtonUp

        Timer.Stop()

    End Sub

End Class

Yukarıdaki kod içerisinde MouseLeftButtonDown ve MouseLeftButtonUp event-handlerlarının sadece birer kere bulunduğu dikkatinizi çekecektir. Söz konusu event-handlerları her iki düğmeye de bağlamış durumdayız. Aslında her iki düğmenin de sadece uygun zamanlarda Timer nesnesini başlatması ve sonlandırma yeterli. Önemli olan Timer'ın Tick durumunda içeriğini yukarı veya aşağıya kaydırılacağına karar verebiliyor olmak. Bunun için de ben örneğimde Yukari düğmesinin IsFocused özelliğinden faydalandım. Eğer bir düğmeye basılmış ise doğal olarak söz konusu düğme Focus almış demektir. Böylece o an için hangi düğmeye basılmakta olduğunu yakalayıp one göre işlem yapılabilir.

Hepinize kolay gelsin.

Thursday, May 08, 2008 11:42:49 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, May 06, 2008
 Monday, May 05, 2008

Silverlight 2.0 Beta 1 ile beraber gelen görsel özellikler içerisinde özellikle tasarımcıların en çok beğenecekleri ve bildiğimiz teknolojiler arasında CSS'e benzetebileceğimiz "Resource" yapısı çok önemli bir yere sahip. WPF'de hali hazırda var olan ve Silverlight tarafına da (ciddi farklılıklar ile) taşınan bu özellikler sayesinde Silverlight uygulamaları içerisinde kontrollerin programatik işlevselliklerinden bağımsız olarak görsel özellikleri ayarlanabildiği gibi merkezi bir yönetim de sağlanabiliyor. Gelin hızlı bir örnek ile konumuza giriş yapalım.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

      <Button HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch" Content="Button"/>

    </Grid>

</UserControl>

İlk olarak yukarıdaki gibi yaratacağımız yeni bir Silverlight 2.0 uygulamasına basit bir Button yerleştirelim ve Button içerisinde yazının (Content) yerine farklı birşeyler koymayı deneyelim. Yukarıdaki kod içerisinde Content değeri doğrudan bit metne eşitlenmiş durumda. Oysa bu değerin içerisine başka bir Silverlight kontrolü yerleştirebiliriz.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Button HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch">

      <Button.Content>

        <Image Height="84" HorizontalAlignment="Center"  VerticalAlignment="Center" Width="139" Source="Dock.jpg"/>

      </Button.Content>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde Button nesnesinin Content özelliğini belirlemek için Button tagları arasında ayrıca bir Button.Content tagları açtık.

Button.Content özelliğini değiştirilen Button nesnesi sağda.
Button.Content özelliğini değiştirilen Button nesnesi sağda.

Bu noktada Button.Content içerisinde istediğiniz Silverlight kontrolünü yerleştirebilirsiniz fakat dikkat etmeniz gereken bir nokta var; maalesef bu taglar arasında sadece bir Silverlight kontrolü yerleştirilebilir. Aslında cümle olarak yanlış bir cümle oldu, daha doğru tabiri ile Button.Content içerisinde XAML kodunun her zaman tek bir RootElement'inin olması gerekiyor. Yani eğer bu bölgeye iki kontrol yerleştirmek istiyorsanız kontrollerinizi bir Container Element içerisinde gruplayarak yerleştirmek zorundasınız. Aşağıdaki örneğimizde Container Element olarak bir StackPanel kullanacağız.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Button HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch">

      <Button.Content>

        <StackPanel Orientation="Horizontal">

          <Image Height="84" HorizontalAlignment="Center"  VerticalAlignment="Center" Width="139" Source="Dock.jpg"/>

          <Image Height="84" HorizontalAlignment="Center"  VerticalAlignment="Center" Width="139" Source="Dock.jpg"/>

        </StackPanel>

      </Button.Content>

    </Button>

  </Grid>

</UserControl>

Gördüğünüz gibi Root Element olarak Button.Content içerisinde bir StackPanel kullandıktan sonra artık StackPanel içerisine istediğimiz kadar kontrol yerleştirebiliyoruz.

Button.Content içerisinde birden çok Silverlight kontrolü.
Button.Content içerisinde birden çok Silverlight kontrolü.

Bu yapı ile farklı kontrollerinin farklı görsel özelliklerini tanımlamak mümkün.

Bir kontrolün tüm görsel yapısını nasıl değiştiririz?

Bu noktaya kadar elimizdeki bir düğmenin içerisinde farklı Silverlight kontrolleri yerleştirdik. Oysa söz konusu düğmenin tüm görsel yapısını değiştirmek de isteyebilirdiniz. Örneğin bir Resim nesneninin bir Button olarak tanımlanması mümkün müdür?

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Button HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch">

      <Button.Template>

        <ControlTemplate>

          <Image Height="84" HorizontalAlignment="Center"  VerticalAlignment="Center" Width="139" Source="Dock.jpg"/>

        </ControlTemplate>

      </Button.Template>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kodumuz içerisinde bir Button nesnesinin Template özelliğini başka bir ControlTemplate atayarak değiştiyoruz. Tanımladığımız ControlTemplate içerisinde sadece bir adet Image nesnesi var. Böylece artık düğmemiz sadece bir Image nesnesinden oluşacak oysa programcımız için bu nesne hala bir Button.

Bir Button nesnesine benzemiyor değil mi? Ama öyle.
Bir Button nesnesine benzemiyor değil mi? Ama öyle.

Peki tüm bunların anlamı nedir?

Yukarıdaki iki yapıyı Button.Content ve Button.Template beraber kullanmanız halinde istediğimiz gibi düğmeler oluşturabilirsiniz. Gelin şimdi güzel bir dikdörtgen çizelim ve bunu yeni yarattığımız bir Button nesnesinin Template özelliğine aktaralım.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Button HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch">

      <Button.Template>

        <ControlTemplate>

          <Rectangle Stroke="#FF000000" RadiusY="16" RadiusX="16" Margin="{TemplateBinding Margin}">

            <Rectangle.Fill>

              <RadialGradientBrush>

                <GradientStop Color="#FFFF0000" Offset="1"/>

                <GradientStop Color="#FFFFFFFF" Offset="0"/>

              </RadialGradientBrush>

            </Rectangle.Fill>

          </Rectangle>

        </ControlTemplate>

      </Button.Template>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde en önemli nokta Button'umuzun ControlTemplate'i içerisindeki Rectangle nesnesinin Margin özelliklerinin TemplateBinding ile içerisinde olduğu kontrolün Margin özelliğine bağlanmış olması. Böylece Button nesnesi büyüdükçe otomatik olarak ControlTemplate içerisinde tanımlanmış Rectangle da büyüyecek. Her zaman olduğu gibi eğer ControlTemplate içerisinden birden çok Silverlight kontrolü kullanarak görsel özellikler tanımlamak isterseniz bir Container Element kullanmanız gerekecektir. Bizim örneğimizde tek nesne bulunduğu için gerek olmadı.

Yeni Silverlight Button nesnemiz karşınızda!
Yeni Silverlight Button nesnemiz karşınızda!

Gördüğünüz gibi düğmemizin görsel özellikleri tamamlandı. Peki ya bu düğmenin içerisine yazılacak olan yazı nerede? Şu anda kontrolün bu hali ile Button.Content özelliğine farklı değerler verdiğiniz görsel anlamda herhangi bir değişiklik görmeyeceksiniz. Çünkü kontrolün ControlTemplate tanımı içerisinde herhangi bir şekilde Content içeriğinin konacağı bir yer ayarlanmış değil. Yani Button.Content içerisine konacak nesnelerin veya yazının ControlTemplate içerisinde nereye konacağını tanımlamamız gerekiyor.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <Button HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch">

      <Button.Content>

        <TextBlock VerticalAlignment="Center" Text="TextBlock" TextWrapping="Wrap"/>

      </Button.Content>

      <Button.Template>

        <ControlTemplate TargetType="Button">

          <Grid>

            <Rectangle Stroke="#FF000000" RadiusY="16" RadiusX="16" Margin="{TemplateBinding Margin}">

              <Rectangle.Fill>

                <RadialGradientBrush>

                  <GradientStop Color="#FFFF0000" Offset="1"/>

                  <GradientStop Color="#FFFFFFFF" Offset="0"/>

                </RadialGradientBrush>

              </Rectangle.Fill>

            </Rectangle>

            <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>

          </Grid>

        </ControlTemplate>

      </Button.Template>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde tanımladığımız Button'ın ControlTemplate'i içerisinde bir ContentPresenter nesnesi bulunuyor. Bu ContentPresenter'ın Content özelliği ise TemplateBinding ile ana Button nesnesinin Content'ına bağlanmış durumda. Böylece Button'un Button.Content'ı içerisindeki tüm Silverlight kontrolleri otomatik olarak ControlTemplate içerisindeki ContentPresenter içerisine yerleştirilmiş olacaktır. Bu noktada dikkat etmemiz gereken önemli bir ayar var, ControlTemplate'ın TargetType'ının özel olarak ayarlanmış olması gerekiyor, aksi halde söz konusu ControlTemplate bir Button içerisinde bulunmasına rağmen doğru olarak çalışmıyor. Umarım Beta sürümü sonrasında sürümlerde bu yapı düzeltilir, şu anki çalışma yapısı pek mantıklı değil.

Button'umuzun son hali.
Button'umuzun son hali.

Peki neden doğrudan herşeyi ControlTemplate içerisine koymuyoruz?

Çok mantıklı bir soru. Çünkü bu noktaya kadar yaptığımız tüm görsel ayarların üzerinden bir merkezi yönetim sistemi kurmak istiyoruz. Bir önceki adımda Button nesnemizin Template özelliğini ayarlamıştık. Şimdi sıra geldi söz konusu Template'ı birden çok kontrol tarafından kullanılabilir hale getirmeye.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <UserControl.Resources>

    <Style x:Key="Dugme" TargetType="Button">

      <Setter Property="Template">

        <Setter.Value>

          <ControlTemplate TargetType="Button">

            <Grid>

              <Rectangle Stroke="#FF000000" RadiusY="16" RadiusX="16" Margin="{TemplateBinding Margin}">

                <Rectangle.Fill>

                  <RadialGradientBrush>

                    <GradientStop Color="#FFFF0000" Offset="1"/>

                    <GradientStop Color="#FFFFFFFF" Offset="0"/>

                  </RadialGradientBrush>

                </Rectangle.Fill>

              </Rectangle>

              <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/>

            </Grid>

          </ControlTemplate>

        </Setter.Value>

      </Setter>

    </Style>

  </UserControl.Resources>

  <Grid x:Name="LayoutRoot" Background="White">

    <Button Style="{StaticResource Dugme}" HorizontalAlignment="Stretch" Margin="44,54,55,45" VerticalAlignment="Stretch">

      <Button.Content>

        <TextBlock VerticalAlignment="Center" Text="TextBlock" TextWrapping="Wrap"/>

      </Button.Content>

    </Button>

  </Grid>

</UserControl>

Template tanımımızı Button'un içerisinden keserek doğrudan UserControl.Resources altına alıyoruz. Böylece artık tüm Silverlight XAML sayfası içerisinde kullanabileceğiz. Tabi bunu yaparken bir Style tanımlıyoruz ve TargetType özelliğini de Button olarak düzenliyoruz. Style içerisinde bir Setter yerleştirerek hedef kontrolün Template özelliğini değiştirmek istediğimizi de belirttikten sonra Setter.Value içerisine daha önce hazırladığımız Template yapısını yerleştiriyoruz.

Son olarak adını Dugme koyduğumuz bu Style'ı kullanmak istediğimiz tüm Button kontrollerinin Style özelliğini StaticResource olarak stilimize bağlayarak kullanabiliyoruz. Böylece tüm düğmelerimiz aynı ControlTemplate'i kullanacaklar ve hepsi de kendi içerisindeki Content'ı hedef Style içerisindeki ContentPresenter'a yerleştirerek gösterecekler. Herhangi bir görsel değişiklik gerektiğinde ise merkezi olarak Style'ımızı değiştirerek ilerleyebileceğiz.

İsterseniz bu Stlye'ınızı Silverlight uygulamasının App.xaml dosyası içerisine koyarak Silverlight uygulamanızdaki tüm XAML dosyaları içerisinde kullanılabilir hale de getirebilirsiniz.

Hepinize kolay gelsin.

Monday, May 05, 2008 5:49:08 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, May 04, 2008

Bugün INETA ve BilgeAdam işbirliğinde "Silverlight" eğitiminin ikinci gününü zevkli bir şekilde sonlandırdık. Eğitim yanlışlıkla ".NET altyapılı" diye duyurulunca tüm katılımcıların "Silverlight 2.0" bekleyerek geldiklerin için eğitimin bu ikinci gününde Silverlight ile Veri İşlemleri kısmını Silverlight 2.0 ile yaptık. Sanırım bundan sonra yine katılımcıların istekleri çerçevesinde sürekli Silverlight 2.0 ile beraber devam ediyor olacağız. Bu kapsamda aslında Türkiye'deki ilk Silverlight 2.0 eğitimini yapıyoruz :)

INETA ve BilgeAdam işbirliğinde Silverlight 2.0 Eğitimi
INETA ve BilgeAdam işbirliğinde Silverlight 2.0 Eğitimi

Tabi konu Silverlight 2.0 olunca ve arkada .NET olunca her zamanki gibi "biz (VB) ve siz (C#)"li sohbetler yapar olduk. Özellikle Silverlight 2.0 ile istemci tarafında XML ile uğraşırken VB'nin XLINQ ile inline XML kolaylıklarının yadsınamayacak olduğunu sanırım kanıtladım :)

Gün boyunca yaptığımız örneklere ait kaynak kodlarını aşağıdaki adresten indirebilirsiniz. Sonuncusu çalışmıyor :) zamanımız yetmedi bitirmeye.

Eğitim Uygulamaları Proje Kodları - 04052008_2.rar (2,6 MB)

Katılan herkese çok teşekkürler.

Sunday, May 04, 2008 7:45:25 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Eğitimler | Silverlight | Silverlight 2.0  | 
 Saturday, May 03, 2008

Silverlight 2.0 ile beraber .NET programlama geldiğinde göre hemen aklımıza gelen konulardan biri de "Oyun Programlama" oluyor. Silverlight içerisinde var olan StoryBoard yapısını kullanarak oyun programlamaya çalıştığınız noktada ise "Bu iş böyle olmaz" diyerek bırakacağınız kesin. Maalesef StoryBoard yapısı çoğu işi kolaylaştırsa da ve oyun programlama içerisinde belirli bir yeri olsa da işin tamamını halletmek için yeterli değil.

Oyun programlamada çoğu zaman kare kare çizim yapabilmemiz ve nesnelerin koordinatları ile tek tek ilgilenebilmemiz gerekir. Daha net bir tanımla aslında ekranda çizimi bizim kod ile yaptırmamız gerekir. Bu noktada Silverlight 2.0 Beta 1 ile beraber gelen DispatcherTimer nesnesini kullanarak bu makalemizde ufak bir örnek yapacağız.

Hedefimiz uygulamamızda bir kare içerisine bir top yerleştirerek bu topun kare içerisinde duvarlara çarparak sürekli gezmesini sağlamak. "Bu ne biçim oyun?" diyebilirsiniz. Tabi ki makale sonunda elimizde hazır bir oyun olmayacak, amacımız oyun programlamada kullanılan yapının bir modelini yaratmak.

İlk olarak gelin uygulamamızın görsel kısmını tamamlayalım. Yarattığımız yeni Silverlight 2.0 uygulamasına bir Ellipse yerleştirerek en üst sol köşeye konumlandıralım. Ellipse'in adı Top olsun. İşlemleri tamamladığımızda elde edeceğimiz XAML aşağıdaki gibi olacak.

<UserControl x:Class="SilverlightApplication15.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="#FFF4E80C">

    <Ellipse Height="30" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="30" Fill="#FFFF0000" Stroke="#FF000000" x:Name="Top"/>

  </Grid>

</UserControl>

XAML kodumuz hazır olduğuna göre artık arkaplana geçip programlamaya başlayabiliriz. Uygulamamızda kullanılmak üzere toplam dört adet global değişken tanımlayacağız.

    Dim Konum As New System.Windows.Media.TranslateTransform()

    Dim Timer As New System.Windows.Threading.DispatcherTimer

    Dim XDegisim = 5

    Dim YDegisim = 5

Bu değişkenlerden ilki olan Konum bizim için sürekli olarak topun ekranın sol üst köşesinden ne kadar sağda ve aşağıda olacağını saklayacak. Konum değişkeninin tipi TranslateTransform şeklinde. Bu değişken tipi herhangi bir nesnesinin RenderTransform grubuna aktardığımızda nesnenin X ve Y koordinatlarında yer değiştirmesini sağlıyor. Eğer Expression Blend 2.5 içerisinde bir nesne yaratır ve herhangi bir animasyon ile konumunu değiştirirseniz nesnenizin XAML kodunun aşağıdaki hale geldiğini görebilirsiniz.

<Rectangle Height="80" HorizontalAlignment="Left" Margin="136,93,0,0" VerticalAlignment="Top" Width="155" Fill="#FFFFFFFF" Stroke="#FF000000" x:Name="rectangle" RenderTransformOrigin="0.5,0.5">

  <Rectangle.RenderTransform>

    <TransformGroup>

      <ScaleTransform/>

      <SkewTransform/>

      <RotateTransform/>

      <TranslateTransform X="10" Y="10" />

    </TransformGroup>

  </Rectangle.RenderTransform>

</Rectangle>

Expression Blend'in bizim için yarattığı Rectangle koduna da baktığımızda aslında yapıyı anlayabiliyoruz.Rectangle içerisine yerleştirilen bir RenderTransform yapısındaki TransformGroup içerisinde TranslateTransform nesnesi yer alıyor. Bu nesnenin X ve Y özellikleri de Rectangle'ın ne kadar yer değiştireceğine karar veriyor. Biz bu aynı yapıyı kendi Top nesnemiz için programatik olarak kullanacağız.

Şimdi tanımladığımız global değişkenlere geri dönelim.

    Dim Konum As New System.Windows.Media.TranslateTransform()

    Dim Timer As New System.Windows.Threading.DispatcherTimer

    Dim XDegisim = 5

    Dim YDegisim = 5

İkinci değişkenimiz bir DispatcherTimer tipinde bir Timer nesnesi. Bu nesne aslında Windows programlamadan bildiğimiz Timer'dan farklı değil. Bu Timer'ın da bir Tick durumu ve Interval'i var. Biz örneğimizde Interval'i çok düşük vererek ekranda çizim yapmak için bu nesneyi kullanacağız.

Diğer iki global değişkenimizin aslında Top'umuzun bir defada ne kadar yer değiştireceğine karar veriyor. Bu değerleri büyüterek topun hızını arttırabilir veya tam tersine azaltarak topunu hızını da yavaşlatabilirsiniz.

        Timer.Interval = New TimeSpan(0, 0, 0, 0, 15)

        AddHandler Timer.Tick, AddressOf Timer_Tick

        Timer.Start()

Silverlight uygulamamız sayfada ilk açıldığında hemen Timer nesnemizin Interval'ini 15 milisaniye olarak ayarlıyoruz. Her 15 milisaniyede bir ekrandaki Top'un yeni konumunu belirleyeceğiz böylece animasyon oluşturmuş olacağız. Doğal olarak Timer nesnemizin Tick durumunu da yakalamamız lazım. Onun için bir de event-handler tanımıyoruz. Event-Handler kodumuza birazdan bakacağız. Son olarak Timer'ın Start metodu ile sayacı başlatıyoruz.

Sıra geldi Timer'ın her bir Tick durumunda topun yeni pozisyonunu ayarlamaya. Aslında kullanacağımız kod çok basit.

        Konum.X += XDegisim

        Konum.Y += YDegisim

        Top.RenderTransform = Konum

Global değişkenimiz olan Konum değişkeninin X ve Y değerlerine değişim miktarlarını ekleyerek Top'un RenderTransform'una eşitleyerek Top'un yeni konumunu almasını sağlıyoruz. Fakat ortada bir sorun var; Top'un duvarlardan sekmesi lazım. Kabaca baktığımızda aslında yapmamız gereken dört kontrol var. Eğer top alt kenara çarptıysa artık XDegisim miktarı 5 değil de -5 olmalı. Böylece top tekrar yukarıya doğru gitmeye başlamalı. Aynı şekilde her kenar için bu kontrolün yapılması lazım. Eğer top sağ kenara çarptıysa artık YDegisim miktarı 5 değil de -5 olmalı. Tüm bu kontrolleri yaptığımızda aşağıdaki gibi bir kod elde ediyoruz.

        If Konum.X = Me.LayoutRoot.ActualWidth - Top.Width Then

            XDegisim = -XDegisim

        End If

        If Konum.Y = Me.LayoutRoot.ActualHeight - Top.Height Then

            YDegisim = -YDegisim

        End If

        If Konum.X = 0 Then

            XDegisim = Math.Abs(XDegisim)

        End If

        If Konum.Y = 0 Then

            YDegisim = Math.Abs(YDegisim)

        End If

        Konum.X += XDegisim

        Konum.Y += YDegisim

        Top.RenderTransform = Konum

IF kontrollerimizi sırasıyla incelersek; ilkinde eğer topun konumu sahnemizdeki ana Canvas'ımız olan LayoutRoot'un genişliğinden Top'un genişliğini de çıkararak aldığımız koordinata ulaşmış ise hemen XDegisim miktarını - hale getiriyoruz. Böylece Top geri gitmeye başlayacak. Aynı şekilde ikinci IF kontrolünde de Y yönünde aynı kontrolü yapıyoruz. Tabi bir de işin diğer tarafı var, yani değişim miktarı eksi iken top ekranın üstüne veya soluna doğru gidecek. Bu durumda da üçüncü ve dördüncü IF kontrolümüz ile Top bu pozisyonlara gelmiş ise değişim miktarlarının mutlak değerini alarak pozitif hale çeviriyoruz.

Bu hali ile uygulamamızı çalıştırdığımızda topumuzun duvarlardan sekerek sonsuza dek gezecektir. Kodumuzun son hali aşağıdaki şekilde;

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim Konum As New System.Windows.Media.TranslateTransform()

    Dim Timer As New System.Windows.Threading.DispatcherTimer

    Dim XDegisim = 5

    Dim YDegisim = 5

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Timer.Interval = New TimeSpan(0, 0, 0, 0, 15)

        AddHandler Timer.Tick, AddressOf Timer_Tick

        Timer.Start()

    End Sub

 

    Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs)

        If Konum.X = Me.LayoutRoot.ActualWidth - Top.Width Then

            XDegisim = -XDegisim

        End If

        If Konum.Y = Me.LayoutRoot.ActualHeight - Top.Height Then

            YDegisim = -YDegisim

        End If

        If Konum.X = 0 Then

            XDegisim = Math.Abs(XDegisim)

        End If

        If Konum.Y = 0 Then

            YDegisim = Math.Abs(YDegisim)

        End If

        Konum.X += XDegisim

        Konum.Y += YDegisim

        Top.RenderTransform = Konum

    End Sub

 

    Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

        If Timer.IsEnabled Then

            Timer.Stop()

        Else

            Timer.Start()

        End If

    End Sub

End Class

Ek olarak bir de sayfanın genelinde MouseLeftButtonDown durumunu yakalayarak Silverlight uygulamasına tıklandığında Timer'ın durdurulabilerek tekrar başlatılabilmesi için gerekli kodu da yazarsak örneğimiz artık tamamlanmış demektir. Artık farklı animasyon yapmak, farklı koordinat kontrolleri yapmak hatta matematiksel koordinat hesaplamalarını ortaokula dönüp biraz da trigonometri ekleyerek lise bilgisi ile de vektörel hesaplamalara çevirmek tamamen size kalmış.

Hepinize kolay gelsin.

Saturday, May 03, 2008 2:28:40 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Wednesday, April 30, 2008

Web uygulamalarında Cookie kullanımı alışık olduğumuz bir yapıdır. Bu yapının bir benzeri Silverlight 2.0 Beta 1 ile beraber de karşımıza geliyor. "Isolated Storage" olarak adlandırılan alan sadece Silverlight uygulamanıza özel olarak varsayılan ayarları ile 100KB'lık bir alanı istemci tarafında programcının kullanımına sunuyor. İlk olarak gelin bu alana veri yazma ve okuma işlemlerinin nasıl yapıldığına bir göz atalım.

Örneğimizde uygulamamız içerisinde bir TextBox ve iki Button yer alacak. Buttonlardan birine basıldığında TextBox içerisindeki veri Isolated Storage içerisine kaydedilecek diğeri ise veriyi silecek. Isolated Storage içerisinde doğrudan dosyalar ve klasörler saklayabiliyoruz. O nedenle biz de örneğimizde saklamak istediğimiz metni bir TXT dosyası şeklinde diske kaydedeceğiz. Gelin ilk olarak uygulamamızın arayüzünü aşağıdaki şekilde hazırlayalım.

<UserControl x:Class="SilverlightApplication12.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <TextBox Margin="38,18,51,105" Text="TextBox" x:Name="txtMetin"/>

    <Button Height="41" HorizontalAlignment="Right" Margin="0,0,51,35" VerticalAlignment="Bottom" Width="127" Content="KAYDET" x:Name="DgmKaydet"/>

    <Button Height="41" HorizontalAlignment="Left" Margin="104,0,0,35" VerticalAlignment="Bottom" Width="91" Content="KAYDI SİL" x:Name="DgmSil"/>

  </Grid>

</UserControl>

Uygulamamız ilk açıldığında Isolated Storage içerisinde daha önce kaydedilmiş "deneme.txt" adında bir dosyanın olup olmadığını kontrol edeceğiz. Eğer böyle bir dosya varsa içeriğini okuyarak doğrudan TextBox içerisinde göstereceğiz.

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            If DEPO.FileExists("deneme.txt") Then

Dim Dosya As IO.IsolatedStorage.IsolatedStorageFileStream = DEPO.OpenFile("deneme.txt", IO.FileMode.Open, IO.FileAccess.Read)

Dim Okuyucu As IO.StreamReader = New IO.StreamReader(Dosya)

                txtMetin.Text = Okuyucu.ReadToEnd

                Okuyucu.Close()

            Else

                txtMetin.Text = "Dosya yok"

            End If

        End Using

Isolated Storage ile ilgili yapacağımız tüm işlemleri IsolatedStorageFile.GetUserStoreForApplication() ile mevcut kullanıcının alanını ele alarak yapacağız. O an için istemci işlem yapan kullanıcının bizim uygulamamız için ayrılmış olan alanına ulaştıktan sonra hemen hedef konumda deneme.txt adında bir dosya olup olmadığını FileExists metodu ile kontrol edebiliyoruz. Eğer söz konusu dosya varsa OpenFile metodu ile dosyamızı açarak bir StreamReader'a kaynak olarak veriyoruz. Bundan sonrası aslında alışık olduğumuz dosya okumat metodları. Eğer böyle bir dosya yok ise TextBox içerisinde doğrudan "Dosya Yok" yazdırıyoruz. Eğer dosyamız herhangi bir klasör içerisinde olsaydı gerekli metodlara sadece dosya ismini değil klasör ismi ile beraber bir yol adresini vermek durumunda kalacaktık. Unutmayın tüm bu klasörler ve dosyalar bizim uygulamamıza ait Isolated Storage alanına saklanıyor olacak. Klasör yaratma konusunda özellikle bir uyarıda bulunmam gerek. Normal şartlarda Windows'ta herhangi bir klasör boş ise diskte yer kaplamaz. Isolated Storage içerisinde her klasör 1KB alan kaplıyor. Bunun aslında mantıklı bir açıklaması var; kötü niyetli Silverlight programcıların istemci tarafında milyonlarca klasör yaratmasını engellemek :)

Şimdi geçelim bir sonraki adıma ve elimizdeki metin kutusuna yazılan herhangi bir değeri TXT dosyası olarak Isolated Storage içerisine nasıl kaydedeceğimizi inceleyelim.

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            Using Dosya As IO.IsolatedStorage.IsolatedStorageFileStream = DEPO.CreateFile("deneme.txt")

Dim Yazici As IO.StreamWriter = New IO.StreamWriter(Dosya)

                Yazici.Write(txtMetin.Text)

                Yazici.Close()

                Istatistik()

            End Using

        End Using

Yukarıdaki kod içerisinde yine GetUserStoreForApplication diyerek mevcut kullanıcının Isolated Storage alanını alıyoruz ve sonrasında CreateFile metodu ile yeni bir dosya yaratıyoruz. Yarattığımız dosyanın içerisine ise bir StreamWriter ile elimizdeki metni yazdırıyoruz. Kodun en sonunda Istatistik denen bir kodu çalıştırdığımı göreceksiniz. Söz konusu kodu ileriki adımlarda yazacağız. Amacımız Isolated Storage içerisinde kullanılan ve kalan alanı kullanıcıya göstermek olacak.

Artık dosyamızı da kaydettiğimize göre sıra geldi ikinci düğmeye basıldığında söz konusu dosyayı Isolated Storage alanından silmeye.

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            If DEPO.FileExists("deneme.txt") Then DEPO.DeleteFile("deneme.txt")

        End Using

Kodumuz gerçekten çok basit. Yine mevcut Isolated Storage alanından yola çekerek FileExists ile dosyanın varlığını kontrol ettikten sonra DeleteFile ile söz konusu dosyayı istemciden siliyoruz. Uygulamamızın tam kodunu incelemeden önce bir de Istatistik adındaki kodumuzu yazalım.

Sub Istatistik()

    Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

        DgmKaydet.Content = "Kaydet " & vbCrLf & "(Kalan Alan:" & Math.Round(DEPO.AvailableFreeSpace / 1024) & "/" & Math.Round(DEPO.Quota / 1024) & ")"

    End Using

End Sub

Kullanıcının Isolated Storage alanını bir değişkene aktardıktan sonra doğrudan Quota ile mevcut kotayı, AvailableFreeSpace ile de boş alanınn byte olarak alabiliyoruz. Örneğimizde bu sayıları 1024'e bölerek kullanıcıya KB biriminde bir istatistik gösteriyoruz. Şimdi uygulamamızın son halini inceleyebiliriz.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            If DEPO.FileExists("deneme.txt") Then

                Dim Dosya As IO.IsolatedStorage.IsolatedStorageFileStream = DEPO.OpenFile("deneme.txt", IO.FileMode.Open, IO.FileAccess.Read)

                Dim Okuyucu As IO.StreamReader = New IO.StreamReader(Dosya)

                txtMetin.Text = Okuyucu.ReadToEnd

                Okuyucu.Close()

            Else

                txtMetin.Text = "Dosya yok"

            End If

        End Using

    End Sub

 

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles DgmKaydet.Click

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            Using Dosya As IO.IsolatedStorage.IsolatedStorageFileStream = DEPO.CreateFile("deneme.txt")

                Dim Yazici As IO.StreamWriter = New IO.StreamWriter(Dosya)

                Yazici.Write(txtMetin.Text)

                Yazici.Close()

                Istatistik()

            End Using

        End Using

    End Sub

 

    Sub Istatistik()

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            DgmKaydet.Content = "Kaydet " & vbCrLf & "(Kalan Alan:" & Math.Round(DEPO.AvailableFreeSpace / 1024) & "/" & Math.Round(DEPO.Quota / 1024) & ")"

        End Using

    End Sub

 

    Private Sub DgmSil_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles DgmSil.Click

        Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            If DEPO.FileExists("deneme.txt") Then DEPO.DeleteFile("deneme.txt")

        End Using

        Istatistik()

        Page_Loaded(sender, e)

    End Sub

End Class

Örneğimizdeki gibi farklı dosyalar yaratarak Isolatetd Storage alanı içerisinde saklayabilirsiniz. Ayrıca isterseniz CreateDirectory, DeleteDirectory metodlarını kullanarak istemci tarafında farklı klasörler yaratabilir, gerektiğinde GetDirectoryNames ve GetFileNames ile daha önce kaydedilmiş dosya ve klasörlerin isimlerini de birer liste olarak alabilirsiniz.

Peki ya 100KB bize yetmezse?

Eğer 100KB size yetmiyorsa hedef istemcideki kullanıcının iznini alarak söz konusu alanı arttırabilirsiniz. Bunun için aşağıdaki gibi bir kod yeterli olacaktır.

       Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()

            DEPO.TryIncreaseQuotaTo(1000000)

        End Using

TryIncreaseQuotaTo metoduna parametre olarak istediğiniz alanın byte miktarını aktarmanız gerekiyor. Böylece kullanıcıya uygulamanın daha fazla alan istediğine dair bir uyarı gösterilecek onayı isteniyor. Eğer kullanıdı onay verirse TryIncreaseQuotaTo metodu geriye True döndürüyor, aksi halde ise False Boolean değeri geliyor.

Daha kolay kullanımı birşey yok mu?

Isolated Storage gerçekten bize istemci tarafında mini bir sabit disk verirmişcesine olanaklar sağlıyor. Oysa bazı durumlarda sadece ufacık bir değeri, uygulamayla ilgili bir ayarı istemci tarafında saklamak gerekebilir. Bunun için tek tek gidip dosyalar yaratmak ve verileri dosyalara kaydetmek uğraştırıcı gelebilir. İşte böyle bir durumda özel olarak hazırlanmış olan System.IO.IsolatedStorage.ApplicationSettings sınıfından faydalanabiliyoruz.

'Mevcut AppSettings nesnesini alalım.

Dim Ayarlar As System.IO.IsolatedStorage.ApplicationSettings = System.IO.IsolatedStorage.ApplicationSettings.Default

'Yeni bir ayar ekleyelim

        Ayarlar.Add("RenkSecimi", "Kirmizi")

'Var olan ayarı değiştirelim

        Ayarlar("RenkSecimi") = txtMetin.Text

'Var olan bir ayarın değerini alalım

        txtMetin.Text = CType(Ayarlar("RenkSecimi"), String)

'Var olan bir ayarı silelim

        Ayarlar.Remove("RenkSecimi")

System.IO.IsolatedStorage.ApplicationSettings sınıfı üzerinden varsayılan ayarları bir değişkene aktardıktan sonra yukarıdaki örnek kod içerisindeki metodları kullanarak rahatlıkla farklı ayarları Isolated Storage içerisine kaydedebiliyor, değiştirebiliyor ve silebiliyoruz.

Hepinize kolay gelsin.

Wednesday, April 30, 2008 4:49:26 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, April 29, 2008

Silverlight çılgınlığı aldı başını gidiyor :) Spike Xavier ve Dan Wahlin tarafından hazırlanmış Silverlight şarkısını aşağıdaki adresten bilgisayarınıza indirebilirsiniz.

http://www.xmlforasp.net/CodeBank/Download/Blog/Music/Silverlight.mp3

Şarkının sözleri şu şekilde;

feed this need for quality
vector based delivery
we write it in xaml, we roll like a caml
we love it like baml
3D dioramma

lightweight subset of the CLR
down the wire with fluidity
you won't believe it, if you can conceive it
your users retrieve it
and their minds receive it.

it's Silverlight
it's strong and tight
they got it right
try it tonight

take the web to a brand new height

:) Bizde de var mı böyle yetenekli gençler? ;)

Tuesday, April 29, 2008 11:48:38 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight | Silverlight 2.0  | 
 Monday, April 28, 2008

Silverlight 2.0 uygulamalarını web sayfalarımıza OBJECT tagları ile koyacağımızı biliyoruz. Artık Silverlight 1.0'daki gibi JavaScript ile uğraşmak durumunda kalmayacağız. Durum böyle olunca tabi ki bu uygulamalara dışarıdan belirli durumlarda parametreler de göndermek gerekecek.

Örneğin bir Video Player hazırladınız ve aynı sayfada birden çok Video göstermek için kullanacaksınız fakat bu videolar da sunucu tarafındaki veriye bağlı olacak. Yani özetle Video Player Silverlight uygulamamız bir ASP.NET Repeater içerisindeyse video dosyasının adını nasıl Silverlight uygulamamıza aktarırız?

Dışarıdan Parametre Gönderimi

İlk olarak sayfamız içerisinde Object tagları arasında bir yerlerde parametrelerimizi belirtmemiz lazım. Bunun için aşağıdaki gibi bir yapı kullanabiliriz.

<object type="application/x-silverlight"

        width="100%" height="100%">

  <param name="source"

        value="ClientBin/deneme.xap"/>

  <param name="initParams"

        value="metin=osman" />

</object>

İsterseniz parametre sayısını arttırmak için yukarıdaki param tagının value özelliğine birden çok parametre ve değer çifti verebilirsiniz. Tek yapmanız gereken metin=osman,deger=xx şeklinde çiftleri birbirinden birer virgül ile ayırmak. Eğer ASP.NET ile beraber gelecek Silverlight sunucu kontrolünü kullanarak uygulamanızı sayfanıza ekliyorsanız bu durumda aşağıdaki gibi bir yapı kullanabilirsiniz.

<asp:Silverlight ID="Xaml1" runat="server"

                Source="~/ClientBin/deneme.xap"

                InitParameters="metin=osman"

                Version="2.0"

                Width="100%"

                Height="100%" />

Peki uygulama içerisinde nasıl kullanacağız?

Bir önceki bölümde verdiğimiz parametrelere Silverlight uygulamaları içerisinde Application nesnesinin Startup durumunda erişebiliyoruz. Söz konusu durumu uygulamanızın App.xaml dosyası içerisinde kodlayabiliyorsunuz.

Private Sub Application_Startup(ByVal o As Object, ByVal e As StartupEventArgs) Handles Me.Startup

    e.InitParams("metin")

End Sub

Yukarıdaki şekli ile Application nesnesinin Startup durumuna parametre olarak gelen StartupEventArgs üzerinden InitParams dizisinde parametrelerimizi bulabiliyoruz. Fakat aslında bizim esas istediğimiz bu parametrelere doğrudan uygulamamızın ana XAML dosyalarında ulaşabiliyor olmak. Bunun için biraz daha uğraşmamız gerekecek. İlk olarak gelin içerisinde bir TextBlock olan XAML kodumuza bakalım. Metin parametresi ile Silverlight uygulamasına aktarılan metni bu TextBlock içerisinde göstereceğiz.

<UserControl x:Class="SilverlightApplication10.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <TextBlock Margin="29,26,41,48" Text="TextBlock" TextWrapping="Wrap" x:Name="Metin"/>

  </Grid>

</UserControl>

Görüldüğü üzere ortada çok karışık bir durum yok. Sadece bir TextBlock var. Peki nasıl olacak da parametrelerimizi sayfamıza aktaracağız. Aslında sayfa dediğimiz XAML dosyaları birer Class.

Partial Public Class Page

    Inherits UserControl

.........................

End Class

Yukarıdaki kod bizim herhangi bir XAML kodumuzun arkasında .NET kodunu gösteriyor. Page adında bir sınıf tanımlanmış ve bu sınıf aslında aşağıdaki şekilde XAML kodumuza da bağlanmış durumda.

<UserControl x:Class="SilverlightApplication10.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

Yani her XAML dosyası aslında birer sınıf olarak tanımlanıyor. Peki başlangıçta hangi XAML dosyasının açılacağı nasıl ayarlanıyor? Gelin App.XAML içerisindeki orijinal StartUp eventının koduna bir göz atalım.

Private Sub Application_Startup(ByVal o As Object, ByVal e As StartupEventArgs) Handles Me.Startup

    Me.RootVisual = New Page()

End Sub

İşte tam bu noktada uygulama açıldığında bizim Page sınıfından bir adet yaratılarak uygulamanın ana görseli haline getirilmiş. Yani bir XAML dosyasını yüklemek için aslında söz konusu XAML koduna bağlı .NET sınıfı kullanılmış. Bu durumda biz Page sınıfımızı bir Property eklesek ve bu Property'ye Application Startup'daki parametreleri aktarsak Page sınıfı içerisinden de tüm parametrelere ulaşmaz mıyız?

Kesinlikle ulaşırız. Hatta üzerine bir de yeni alternatif bir Constructer yazdık mı aslında işimiz daha da kolaylaşır. Gelin tek tek bunları yapalım.

Private PInitParams As System.Collections.Generic.IDictionary(Of String, String)

Public Property InitParams() As System.Collections.Generic.IDictionary(Of String, String)

    Get

        Return PInitParams

    End Get

    Set(ByVal value As System.Collections.Generic.IDictionary(Of String, String))

        PInitParams = value

    End Set

End Property

Yukarıdaki gördüğünüz Property'yi Page sınıfı içerisinde kullanacağız. Bu Property aslında Application Startup'taki tüm InitParams'ları taşıyabilecek. Zaten söz konusu InitParams'ın tipine de baktığımızda System.Collections.Generic.IDictionary(Of String, String)) ile karşılaşıyoruz. Sıra geldi bir de yeni Constructor yazmaya.

Public Sub New(ByVal IncInitParams As System.Collections.Generic.IDictionary(Of String, String))

    Me.InitParams = IncInitParams

    InitializeComponent()

End Sub

Yukarıdaki kodu da ekledikten sonra artık istersek yeni bir Page sınıfı yaratırken atanacak olan Parametre listesini de verebiliriz. Page sınıfımızın tam kodu aşağıdaki şekilde sonlanıyor.

Partial Public Class Page

    Inherits UserControl

 

    Private PInitParams As System.Collections.Generic.IDictionary(Of String, String)

    Public Property InitParams() As System.Collections.Generic.IDictionary(Of String, String)

        Get

            Return PInitParams

        End Get

        Set(ByVal value As System.Collections.Generic.IDictionary(Of String, String))

            PInitParams = value

        End Set

    End Property

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Public Sub New(ByVal IncInitParams As System.Collections.Generic.IDictionary(Of String, String))

        Me.InitParams = IncInitParams

        InitializeComponent()

    End Sub

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Metin.Text = InitParams("metin")

    End Sub

End Class

Page.Loaded durumunda da Page sınıfımızın kendi Property'si olan InitParams üzerinden Metin parametresini alarak TextBlock içerisine yazdırıyoruz. Peki App.xaml'ın arkasına ne yazdık?

Partial Public Class App

    Inherits Application

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Application_Startup(ByVal o As Object, ByVal e As StartupEventArgs) Handles Me.Startup

        Me.RootVisual = New Page(e.InitParams)

    End Sub

 

End Class

Gördüğünüz gibi Page sınıfını yaratırken doğrudan uygulamaya gelen tüm parametrelerin listesini de sınıfımıza aktarıyoruz. Böylece artık Page sınıfında da söz konusu tüm parametrelere ulaşılabilecek.

Hepinize kolay gelsin.

Monday, April 28, 2008 12:15:21 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Sunday, April 27, 2008

Silverlight 2.0 uygulamalarında tüm uygulamaya ait VB veya C# kodu ile beraber XAML dosyalarının da birer DLL olarak düzenlendiğini ve sonrasında XAP adında, özünde ZIP dosyaları şeklinde paketlenerek istemciye gönderildiğini biliyoruz. Durum böyle olunca bir Silverlight uygulaması ile beraber sunucudan istemciye farklı kaynaklar göndermeyle ilgili değişik yollar söz konusu oluyor.

Bunlardan en basiti tabi ki sunucuda yer alan hali hazırdaki bir dosyayı asenkron bir istek ile istemciye taşımak. Fakat bu durumda eğer istenecek olan veri çok ufaksa aslında ilk Silverlight uygulamasının yüklenmesinde kullanılan veri transferinde bu ufak dosyalar da ana XAP dosyası ile beraber gönderilebilirdi. Böylece hem toplamda sunucuya gönderilen istek sayısı azalırdı hem de XAP dosyalarının yapısı gereği sıkıştırma özelliğinden faydalanılmış olurdu.

Build Action : Resource

Visual Studio içerisinde Silverlight projelerinde herhangi bir dosyayı seçtikten sonra "Properties" paneline göz attığımızda "Build Action" adında bir ayar görebilirsiniz. Bu ayar ile söz konusu dosyanın ne şekilde sunucudan istemciye gönderileceğini ayarlamış oluyoruz.

Varsayılan ayarları ile projenize bir resim dosyası eklediğinizde Build Action ayarı Resource olarak düzenlenmiş olacaktır. Bu dosyalar doğrudan Silverlight uygulaması için yaratılacak DLL dosyası içerisine Resource olarak yerleştirilecektir. DLL dosyasının yüklenme süresini uzatmamak adına olabildiğince ufak ve önemli dosyaları bu şekilde projelere eklemekte fayda var.

<Image Source="Foto.jpg"/>

Bu şekilde projelere eklenmiş dosyaları XAML içerisinde doğrudan yukarıdaki gibi kullanabilirsiniz.

Build Action : Content

Eğer dosyanızın orijinal DLL'i şişirmesini istemiyorsanız fakat yine de aynı XAP dosyası içerisinde istemciye gitmesini istiyorsanız. Kullanmanız gereken seçenek "Content" seçeneği. Bu şekilde işaretlenmiş dosyalar XAP dosyası içerisine konarak istemciye gönderilir. Eğer istemci tarafında Plug-In hedef dosyayı XAP dosyası içinde bulamazsa bu sefer XAP dosyası ile aynı klasörde sunucu üzerinden dosyayı almaya çalışıyor.

<Image Source="/Foto.jpg"/>

Normalinden farklı olarak bu sefer tüm verilen adreslerin başında bir / yerleştirilmesi ve relative konum verilmesi gerekiyor. Her ihtimale karşı yine de çok büyük dosyaları da bu şekilde kullanmamakta fayda var. Çünkü unutmayın XAP dosyası istemciye tamamen gitmeden uygulamanız çalışmayacaktır.

Hepinize kolay gelsin.

Sunday, April 27, 2008 1:31:50 AM (GTB Standard Time, UTC+02:00)  #    Comments [1]   Silverlight 2.0  | 
 Saturday, April 26, 2008

ASP.NET kullanırken en sevdiğim kontrol Repeater kontrolüdür. Bana herşeyi istediğim gibi esnek bir şekilde düzenleme şansı tanır. Aynı mantıkla Silverlight 2.0 Beta 1 tarafına geçtiğimizde karşımızda ItemsControl çıkıyor. ItemsControl'e bağladığınız herhangi bir veri içerisindeki her Item'ın nasıl gözükeceği aynı Repeater içerisinde olduğu gibi bir ItemTemplate aracılığı ile karar verebiliyorsunuz. Ayrıca tüm bu Item'ların nasıl bir kontrol içerisinde ekrana yerleştirileceğini de belirleme şansınız var. Özünde ItemsControl tek başına herhangi bir görsellik barındırmıyor, herşeyi sizin tek tek ayarlamış olmanız şart.

Örneğimizde elimizde bulunan bir ürün listesini ItemsControl'e bağlayarak ürünlerin isimleri ile satış grafiklerini göstereceğiz. Bunu yaparken de Silverlight 2.0 ile beraber gelen DataBinding sistemini kullanacağız. İlk olarak gelin code-behind tarafından başlayalım ve ürün listemizi yaratacağımız ürün tipini tanımlayalım.

Public Class Urun

 

    Private PAdi As String

    Public Property Adi() As String

        Get

            Return PAdi

        End Get

        Set(ByVal value As String)

            PAdi = value

        End Set

    End Property

 

    Private PSatis As Integer

    Public Property Satis() As Integer

        Get

            Return PSatis

        End Get

        Set(ByVal value As Integer)

            PSatis = value

        End Set

    End Property

 

    Sub New()

 

    End Sub

 

    Sub New(ByVal adi As String, ByVal satis As Integer)

        Me.Adi = adi

        Me.Satis = satis

    End Sub

 

End Class

Gördüğünüz gibi aslında klasik bir .NET sınıfından farklı değil. Her zamanki gibi Urun sınıfımızı / tipini yarattık ve bu sınıf üzerinde bir liste üreterek ItemsControl'e bağlayacağız. Normal şartlarda olsa belki bir Generic.List kullanırdık oysa Silverlight 2.0 ile beraber bir ObservableCollection kullanacağız. Bunun tabi ki mantıklı bir nedeni var. ObservableCollection yapıları Silverlight 2.0 tarafında DataBind işlemleri için kullanıldıklarında Public bir ObservableCollection listesi bir defa herhangi bir kontrole bağlandıktan sonra sürekli organik bir bağ içerisinde kalıyor. Böylece eldeki liste üzerinde herhangi bir değişiklik kod tarafında yapıldığında otomatik olarak sonuç görsel öğelere de yansıyor. Biz de bu nedenle örneğimizde ObservableCollection listesi kullanacağız, böylece kod tarafında listede bir değişiklik yaptığımızda sonuç doğrudan görsel olarak ItemsControl'e yansıyacak.

Public Liste As New System.Collections.ObjectModel.ObservableCollection(Of Urun)

 

Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

    For x As Integer = 0 To 9

        Liste.Add(New Urun("Urun Adi " & x, Rnd() * 150))

    Next

    UrunlerControl.ItemsSource = Liste

End Sub

Gördüğünüz gibi aslında ObservableCollection'ların normal Generic.List'lerden kullanım açısından pek bir farkı yok. Biz örneğimizde rastgele ürünler ve satış rakamları yaratarak ürettiğimiz listeyi, adını UrunlerControl olarak koyduğumuz ItemsControl nesnesine ItemsSource özelliği üzerinden bağlıyoruz.

Gelelim XAML kodumuza...

<ItemsControl Margin="27,8,44,8" x:Name="UrunlerControl">

    <ItemsControl.ItemTemplate>

        <DataTemplate>

          Her bir yaratılan öğenin görsel tanımı buraya gelir.

        </DataTemplate>

    </ItemsControl.ItemTemplate>

    <ItemsControl.ItemsPanel>

        <ItemsPanelTemplate>

            Tüm yaratılan öğelerin içerisine yerleştirileceği ortamı tanımlar.

        </ItemsPanelTemplate>

    </ItemsControl.ItemsPanel>

</ItemsControl>

Yukarıdaki ItemsControl içerisinde toplamda iki farklı Template bulunuyor. Bunlardan ilki ItemTemplate içerisinde DataTemplate. ItemsControl'e bağladığımız verideki her biri Urun için bir adet DataTemplate oluşturulacaktır. Bu sistemi ASP.NET'teki Repeater içerisinde ItemTemplate yapısına benzetebiliriz. Tüm bu yaratılan DataTemplate'lar ise ItemsPanel içerisinde ItemsPanelTemplate'ta tanımlanmış görsel yapının içerisine oturtulacaktır. ItemsControl'un kendine ait bir görsel yapısı olmadığı için aslında ItemsPanelTemplate bu yapıyı oluşturuyor olacak.

Biz örneğimizde ana yapı olarak bir StackPanel kullanacağız ve ItemsPanelTemplate içerisinde içindeki nesneleri dikey hizalamaya ayarlanmış bir StackPanel bulunacak.

    <ItemsControl.ItemsPanel>

        <ItemsPanelTemplate>

            <StackPanel Orientation="Vertical"></StackPanel>

        </ItemsPanelTemplate>

    </ItemsControl.ItemsPanel>

Diğer yandan üretilecek olan her biri Urun'un görselliği için de DataTemplate içerisinde bir TextBlock bir de Rectangle kullanacağız. DataTemplate içerisine sadece bir element yerleştirebildiğimiz için bir ContainerElement olarak yine StackPanel kullanacağız. Bu sefer her bir Urun için oluşturulacak olan StackPanel'ler kendi içlerindeki nesneleri yatay olarak hizalayacaklar. Böylece StackPanel'ler içerisindeki TextBlock ve Rectangle'lar yan yana duracaklar.

    <ItemsControl.ItemTemplate>

        <DataTemplate>

          <StackPanel Orientation="Horizontal">

                <TextBlock/>

                <Rectangle Height="30" Fill="#FFFF0000"/>

            </StackPanel>

        </DataTemplate>

    </ItemsControl.ItemTemplate>

Amacımız TextBlock içerisinde ürünün adını gösterirken ürün satış rakamına göre Rectangle'ın da genişliğini ayarlayarak genişliğine göre ürünlerin yanında bir satış grafiği göstermek. Bu durumda hemen Silverlight 2.0'a özel DataBind sistemini kullanarak TextBlock'un Text özelliğini ItemsControl'a aktarılan verilerin Adi özelliğine, Rectangle'ın Width özelliğini de Satis değerine bağlamamız gerekiyor.

          <StackPanel Orientation="Horizontal">

                <TextBlock Text="{Binding Adi}"/>

                <Rectangle Height="30" Width="{Binding Satis}" Fill="#FFFF0000"/>

            </StackPanel>

İşimiz tamamlandı. Artık uygulamamızı çalıştıracak sonucu görebiliriz. Fakat onun öncesinde gelin sürekli ürünlerin listesini değiştiren bir de Düğme ekleyelim uygulamamıza ve elimizdeki ObservableCollection yapısındaki ürün listesini sürekli değiştirsin. Düğmemizin arkaplandaki koduna aşağıdaki satırları yazmamız yeterli olacaktır.

Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

    Liste.Clear()

    For x As Integer = 0 To 9

        Liste.Add(New Urun("Urun Adi " & x, Rnd() * 150))

    Next

End Sub

Yukarıdaki kod içerisinde ObservableCollection listemizi temizliyor ve tekrar ürünler ekliyoruz. Herhangi bir şekilde tekrar DataBind işlemi yapmasak da söz konusu işlemlerin sonucu ItemsControl'ün görsel arayüzüne yansıyor.

Uygulamamızın tam XAML kodunu aşağıda inceleyebilirsiniz.

<UserControl x:Class="SilverlightApplication8.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <ItemsControl Margin="27,8,44,8" x:Name="UrunlerControl">

      <ItemsControl.ItemTemplate>

        <DataTemplate>

          <StackPanel Orientation="Horizontal">

            <TextBlock Text="{Binding Adi}"/>

            <Rectangle Height="30" Width="{Binding Satis}" Fill="#FFFF0000"/>

          </StackPanel>

        </DataTemplate>

      </ItemsControl.ItemTemplate>

      <ItemsControl.ItemsPanel>

        <ItemsPanelTemplate>

          <StackPanel Orientation="Vertical"></StackPanel>

        </ItemsPanelTemplate>

      </ItemsControl.ItemsPanel>

    </ItemsControl>

    <Button Height="30" HorizontalAlignment="Right" Margin="0,0,17,8" VerticalAlignment="Bottom" Width="70" Content="Yenile" x:Name="Dugme"/>

  </Grid>

</UserControl>

Code-Behind kısmındaki VB kodumuz da bu şekilde;

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Public Class Urun

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

 

        Private PSatis As Integer

        Public Property Satis() As Integer

            Get

                Return PSatis

            End Get

            Set(ByVal value As Integer)

                PSatis = value

            End Set

        End Property

 

        Sub New()

 

        End Sub

 

        Sub New(ByVal adi As String, ByVal satis As Integer)

            Me.Adi = adi

            Me.Satis = satis

        End Sub

 

    End Class

 

    Public Liste As New System.Collections.ObjectModel.ObservableCollection(Of Urun)

 

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        For x As Integer = 0 To 9

            Liste.Add(New Urun("Urun Adi " & x, Rnd() * 150))

        Next

        UrunlerControl.ItemsSource = Liste

    End Sub

 

 

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Liste.Clear()

        For x As Integer = 0 To 9

            Liste.Add(New Urun("Urun Adi " & x, Rnd() * 150))

        Next

    End Sub

End Class

Silverlight 2.0 Beta 1 ile beraber gelen bu DataBind özellikleri aslında WPF tarafından tanıdık olsa da Cross-Platform olarak istemci tarafında bu işlemleri yapabiliyor olmak gerçekten heyecan verici.

Hepinize kolay gelsin.

Saturday, April 26, 2008 8:00:23 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Friday, April 25, 2008

Silverlight 2.0 ile beraber istemci tarafında .NET dillerini kullanabildiğimizi ilk duyduğumda aklıma gelen ilk şey WebClient sınıfını artık istemci tarafında da kullanıp kullanamayacağım olmuştu. Kesinlikle kullanabiliyoruz, hatta bununla kalmayıp istersek daha detaylı bir kullanım için HttpWebRequest'i de tercih edebiliriz. Tüm bu sınıflar bize REST kullanımında yardımcı oluyorlar. Normal şartlarda uygulamalar arasında veri transferi için WSDL tanımlarına sahip servislerin kullanımı tavsiye edilse de hala maalesef herhangi bir kural tanımı olmayan veri kaynaklarını da kullanmak durumunda kalabiliyoruz. İşte tam bu noktada WebClient basit işlemler için imdatımıza yetişiyor. Eğer farklı HTTP Verb'lerini (GET, PUT, POST, DELETE) kullanacaksanız daha detaylı işlemler için HttpWebRequest'i tercih etmeniz gerekecektir. WebClient işin sadece GET kısmında yer alıyor.

Örneğimizdeki Silverlight 2.0 Beta 1 uygulamasında System.Net.WebClient sınıfını kullanarak sunucudaki bir xml dosyasını okuyacağız. İlk olarak okuduğumuz veriyi göstermek üzere uygulamamıza bir TextBlock ve veriyi çekme işlemini başlatmak üzere bir de Button ekleyerek aşağıdaki XAML kodunu yaratalım.

<UserControl x:Class="SilverlightApplication7.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <TextBlock Height="47" Margin="57,45,151,0" VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap" x:Name="Metin"/>

    <Button HorizontalAlignment="Stretch" Margin="94,136,151,121" VerticalAlignment="Stretch" Content="Button" x:Name="Dugme"/>

  </Grid>

</UserControl>

Sayfamız hazır olduğuna göre artık WebClient nesnemizi yaratacak olun kodu düğmemizin arkasına yazabiliriz.

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Dim Istek As New System.Net.WebClient

        AddHandler Istek.DownloadStringCompleted, AddressOf istek_DownloadStringCompleted

        Istek.DownloadStringAsync(New Uri("http://www.alanadi.com/veri.xml"))

    End Sub

Yukarıdaki kodumuz içerisinde ilk olarak WebClient nesnemizi yaratıyoruz. Bir sonraki adımda elimizdeki WebClient nesnesinin DownloadStringCompleted durumunu harici bir event-handler'a bağlıyoruz. Bunu yapmamızın nedeni WebClient sınıfının kendisine verilen bir adresten alacağı veriyi tamamen asenkron olacak alıyor olması. Yani sunucudan veri tam olarak geldiğinde bizi haberdar edecek olan event-handları tanımlamamız gerekiyor. Son adımda ise DownloadStringAsync komutuna hedef adresi de bir Uri değişkeni olarak aktararak veri talebimizi sunucuya göndermiş oluyoruz. Sıra geldi veri geldiğinde çalıştırılacak olan event-handler kodunu yazarak veriyi TextBlock içerisine yazdırmaya. Fakat onun öncesinde ilk olarak hedef aldığımız XML dosyasının yapısına bir göz atalım.

<?xml version="1.0" encoding="utf-8" ?>

<Root>

  <Kayitlar>

    <Kayit>

      <Adi>Ahmet</Adi>

    </Kayit>

    <Kayit>

      <Adi>Daron</Adi>

    </Kayit>

    <Kayit>

      <Adi>Mehmet</Adi>

    </Kayit>

  </Kayitlar>

</Root>

Örnek XML dosyamızı sunucudan istemciya aldıktan sonra biz sadece adının içerisinde "Dar" geçen ilk kaydı bularak onun Adi'ni göstermek istiyoruz. Bu XML dosyası çok daha farklı olabilirdi, içerisinde ID ve Adi bilgileri olan bir ürün listesi olabilir ve istemci tarafına aldıktan sonra farklı şekillerde filtrelemek isteyebilirdiniz. Tüm bunları rahatlıkla yapabilmek için Silverlight 2.0 Beta 1 ile istemci tarafında XLINQ kullanacağız. Silverlight 2.0 içerisinde XLINQ kullanabilmek için Silverlight projenizde "Solution Explorer" içerisinde sağ tıklayarak gelen menüden "Add Reference" komutu vermeniz ve "System.Xml.Linq" sınıfını eklemeniz gerekiyor. Sonrasında artık normalde olduğu gibi XDocument ve tüm XLINQ özelliklerinden faydalanabiliriz.

    Private Sub istek_DownloadStringCompleted(ByVal sender As Object, ByVal e As System.Net.DownloadStringCompletedEventArgs)

        Dim YeniDoc As Xml.Linq.XDocument = Xml.Linq.XDocument.Parse(e.Result)

        Metin.Text = (From Gelenler In YeniDoc.<Root>.<Kayitlar>.<Kayit> _

                      Where Gelenler.<Adi>.Value.Contains("Dar") _

                      Select Gelenler.<Adi>.Value).SingleOrDefault

    End Sub

Bir önceki adımda düğmeye tıklandığında yarattığımız WebClient nesnesine aktardığımız event-handları burada tanımlıyoruz. Böylece sunucudan veri geldiğinde bu metod çalıştırılıyor olacak. Sunucudan gelen ham veriye e.Result ile ulaşabiliyoruz. Gelen veri özünde XML olacağı için hemen bir XDocument yaratarak XDocument sınıfının Parse özelliği ile verimizi işlenebilir hale getiriyoruz. Son adımda ise klasik bir XLINQ sorgusu yazarak adında "Dar" geçen kaydı bularak değeri Metin adındaki TextBlock nesnemize aktarıyoruz.

Böylece sunucudan farklı bir XML dosyasını alarak XLINQ ile rahatlıkla istemci tarafında işleyebildiğimizi gördük.

Peki ya başkan bir alan adından veri çekmek istersek?

Aslında bu bölümde bahsedeceğimiz sorun Silverlight'dan bağımsız olup tüm AJAX uygulamalarında geçerli bir sorun. Maalesef tarayıcılardaki uygulamalar güvenlik sebepleri ile kendi çalıştıkları alan adı haricindeki konumlardan veri alamaz veya gönderemezler. Bu nedenle maalesef Silverlight tarafından da yola çıkarak başka bir alan adından veri almak mümkün değil gibi gözükebilir. Oysa bir yol var.

İster harici klasik ASMX Web Servisleri, ister WCF servisleri veya ister doğrudan REST kullanmak isteyin, harici bir alan adına ulaşmak istiyorsanız aslında söz konusu alan adındaki veri kaynağının size ulaşım izni vermiş olması gerekiyor. Silverlight 2.0 karşı hedef alan adında clientaccesspolicy.xml adında bir dosya arar. Eğer bu dosyayı bulabiliyorsa içerisinde yazılı kurallar çerçevesinde sizin söz konusu alan adındaki içeriğe ulaşmanıza izin verir.

<?xml version="1.0" encoding="utf-8"?>

<access-policy>

  <cross-domain-access>

    <policy>

      <allow-from>

        <domain uri="*"/>

      </allow-from>

      <grant-to>

        <resource path="/" include-subpaths="true"/>

      </grant-to>

    </policy>

  </cross-domain-access>

</access-policy>

Yukarıdaki gibi bir clientaccesspolicy.xml dosyası herhangi bir alan adından hedef alan adındaki her konuma ulaşılabileceği anlamına gelir. İsterseniz bu dosyayı değiştirerek farklı kurallar koyabilir, sadece belirli alan adlarında çalışan uygulamaların hedef konuma ulaşabilmesini sağlayabilirsiniz.

<?xml version="1.0" encoding="utf-8"?>

<access-policy>

  <cross-domain-access>

    <policy>

      <allow-from>

        <domain uri="http://daron.yondem.com"/>

      </allow-from>

      <grant-to>

        <resource path="/servisler/" include-subpaths="true"/>

      </grant-to>

    </policy>

  </cross-domain-access>

</access-policy>

Örneğin yukarıdaki gibi bir policy dosyasında sadece daron.yondem.com adresinden xml dosyasının bulunduğu alan adında servisler klasörü içerisinde kaynaklara ulaşılabileceği tanımlanmış. Policy dosyaları ile ilgili detaylara buradan ulaşabilirsiniz.

Hepinize kolay gelsin.

Friday, April 25, 2008 2:56:25 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, April 24, 2008

.NET Framework 3.0 ile beraber karşımıza çıkan WCF servisleri aslında çoktan klasik web servislerinin yerini de almış durumda. Tabi ki doğrudan bir karşılaştırma yapmak çok yanlış olacaktır, WCF çok daha geniş kapsamlı bir çerçevede değerlendirilmeli. Silverlight 2.0 tarafına baktığımızda ise istemci ile sunucu arasındaki veri trafiğini klasik ASMX web servislerine bağlayabileceğimiz gibi istersek doğrudan WCF servislerini de kullanabiliyoruz. Bu yazıda Silverlight 2.0 Beta 1 ile WCF servislerininin kullanımına değineceğiz.

WCF servisimizi hazırlayalım.

Visual Studio 2008 içerisinde yarattığımız yeni Silverlight projemize eşlik eden Web Project içerisinde yeni bir WCF servisi yaratıyoruz. Örneğimizde Silverlight tarafından gönderilen iki sayıfa WCF servisi tarafından alınarak sunucu tarafından toplanacak ve geri döndürülecek. Bu çerçevede uygun bir WCF servisini hazırlarken aşağıdaki kodları yazmamız gerekiyor.

[IService.vb]

Imports System.ServiceModel

 

<ServiceContract()> _

Public Interface IService

 

    <OperationContract()> _

    Function Toplama(ByVal x As Integer, ByVal y As Integer) As Integer

 

End Interface

[Service.vb]

Public Class Service

    Implements IService

 

    Public Function Toplama(ByVal x As Integer, ByVal y As Integer) As Integer Implements IService.Toplama

        Return x + y

    End Function

 

End Class

WCF servisimiz hazır olduğuna göre Silverlight tarafına geçiş yapabiliriz diye düşünüyorsunuz kesinlikle aldanıyorsunuz. Varsayılan ayarları ile Visual Studio içerisinde herhangi bir WCF servisi yarattılığında wsHttpBinding kullanılır oysa bizim Silverlight tarafında basicHttpBinding'e ihtiyacımız var. O nedenle hemen projemizin Web.Config dosyasına ufak bir yolculuk yaparak aşağıdaki şekilde ayarlarda değişiklik yapmamız gerekiyor.

<services>

  <service behaviorConfiguration="ServiceBehavior" name="Service">

    <endpoint address="" binding="basicHttpBinding" contract="IService">

      <identity>

        <dns value="localhost" />

      </identity>

    </endpoint>

    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

  </service>

</services>

Artık tüm ayarlarımız tamamladı. Silverlight 2.0 tarafına rahatlıkla geçebiliriz.

Silverlight 2.0 ve WCF bağlantısı

WCF servisimiz ile Silverlight uygulamamızın aynı domain içerisinde olması şart. Güvenlik kuralları nedeniyle "cross-domain" yani alan adları arası veri trafiği oluşturma şansımız yok. Visual Studio içerisinde Silverlight projenize sağ tıklayarak gelen menüden "Add Service Reference" düğmesine basarak proje içerisinde WCF servisini Silverlight uygulamasına referans olarak ekleyebilirsiniz.

İlk olarak gelin uygulamamızın XAML koduna bir göz atalım.

<UserControl x:Class="SilverlightApplication3.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

  <Grid x:Name="LayoutRoot" Background="White">

    <TextBox Height="29" Margin="72,37,134,0" VerticalAlignment="Top" Text="TextBox" x:Name="Sayi1"/>

    <TextBox Height="39" Margin="72,81,134,0" VerticalAlignment="Top" Text="TextBox" x:Name="Sayi2"/>

    <Button HorizontalAlignment="Stretch" Margin="114,144,188,122" VerticalAlignment="Stretch" Content="Button" x:Name="Topla"/>

    <TextBlock Height="43" Margin="86,0,147,47" VerticalAlignment="Bottom" Text="TextBlock" TextWrapping="Wrap" x:Name="Sonuc"/>

  </Grid>

</UserControl>

Şimdi kod tarafına geçerek bir önceki adımda referans olarak projemize eklediğimiz WCF servisini kullanmaya başlayalım.

WithEvents Servis As New WCFServisim.ServiceClient

Yukarıdaki şekli ile servisimizi uygulama içerisinde global olarak tanımlıyoruz. WCF servisimi bu şekilde tanımlamamın aslında önemli bir nedeni var. Birazdan WCF servisi ile istemci tarafından suncuya bir veri talebi gönderdiğimizde, yani toplanacak olan sayıları gönderip toplamı istediğimizde aslında asenkron bir talepte bulunmuş olacağız. Klasik Windows uygulamalarından alıştığımız yapıdan farklı olarak Silverlight 2.0 içerisinde WCF servislerinin kullanımı tamamen asenkron olarak gerçekleşiyor. Durum böyle olunca asenkron bir istek sonrasında sunucudan cevap (veri) geldiğinde bizim kodumuzun da durumdan haberdar edilmesi gerekecek. Söz konusu haber yine WCF servisimize özel olan bir başka event-handler'ın çalıştırılması ise bize ulaştırılacak. Aslında dinamik olarak servisimizi yaratırken event-handler da bağlayabilirdik. Ama Visual Basic ile yukarıdaki gibi bir kullanım çok daha rahat oluyor. C# programcıları dinamik event-handler bağlamayı kullanabilirler.

Global değişkenimizde WCF servisimiz hazır olduğuna göre artık düğmemize bazıldığında söz konusu servisi rahatlıkla kullanabiliriz.

    Private Sub Topla_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Topla.Click

        Servis.ToplamaAsync(Integer.Parse(Sayi1.Text), Integer.Parse(Sayi2.Text))

    End Sub

Gördüğünüz gibi Servis değişkenim üzerinden ToplamaAsync metodunu çağırıyorum. Metodu çalıştırdıktan sonra sunucudan veri geldiğinde bu metoda özel olan ToplamaCompleted event'ı çalıştırılacak.

    Private Sub Servis_ToplamaCompleted(ByVal sender As Object, ByVal e As WCFServisim.ToplamaCompletedEventArgs) Handles Servis.ToplamaCompleted

        Sonuc.Text = e.Result.ToString

    End Sub

ToplamaCompleted event'ına gelen parametrelerden ikincisinin tipine baktığımızda ToplamaCompletedEventArgs ile karşılaşıyoruz. Bu tamamen bizim metodumuza özel bir değişken tipi. Buradan yola çıkarak e.Result dediğimizde ise doğrudan bizim WCF metodumuzun döndürdüğü nesneyi yakalayabiliyoruz. Örneğimizde gelen sonucu uygulama içerisinde bir TextBlock içine yazdırıyoruz.

Kodumuzun tamamına baktığımızda aşağıdaki manzara ile karşılaşıyoruz.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    WithEvents Servis As New WCFServisim.ServiceClient

 

    Private Sub Topla_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Topla.Click

        Servis.ToplamaAsync(Integer.Parse(Sayi1.Text), Integer.Parse(Sayi2.Text))

    End Sub

 

    Private Sub Servis_ToplamaCompleted(ByVal sender As Object, ByVal e As WCFServisim.ToplamaCompletedEventArgs) Handles Servis.ToplamaCompleted

        Sonuc.Text = e.Result.ToString

    End Sub

End Class

Peki ya C# olsaydı?

Visual Basic'e özel yapılar kullandığım için aynı kodun C# muadilini de sizlerle paylaşmak istiyorum. Böylece C# programcıları için anlaşılması çok daha kolay olacaktır.

namespace SilverlightApplication4

{

    public partial class Page : UserControl

    {

        public Page()

        {

            InitializeComponent();

            Topla.Click += new RoutedEventHandler(Topla_Click);

        }

 

        void Topla_Click(object sender, RoutedEventArgs e)

        {

            WCFServisim.ServiceClient Servis = new WCFServisim.ServiceClient();

            Servis.ToplamaCompleted += new EventHandler<WCFServisim.ToplamaCompletedEventArgs>(Servis_ToplamaCompleted);

            Servis.ToplamaAsync(int.Parse(Sayi1.Text), int.Parse(Sayi2.Text));

        }

 

        void Servis_ToplamaCompleted(object sender, SilverlightApplication4.WCFServisim.ToplamaCompletedEventArgs e)

        {

            Sonuc.Text = e.Result.ToString();

        }

    }

}

Hepinize kolay gelsin.

Thursday, April 24, 2008 3:56:39 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0 | WCF  | 
 Wednesday, April 23, 2008

Silverlight 2.0 ile beraber .NET dillerini kullanabilirker aslında sunucu tarafındaki veriye ulaşma yapısı biraz değişiyor. Normal şartlarda istemci tarafından sunucuya bağlanabilmek için AJAX isteklerini kullanırken artık istemci tarafında elimizde .NET varken ne yapacağız?

İşte bu soruya bir cevap olarak klasik ASMX web servislerinin Silverlight 2.0 Beta 1 ile kullanımına göz atarak hali hazırda elimizde web servisleri ile bulunan projelere nasıl Silverlight 2.0 Beta 1 uygulamalarını bağlayabileceğimizi göreceğiz.

Klasik ASMX servisimiz hazır

Örneğimizde kullanılmak üzere kendisine verilen iki sayıyı toplayarak geri döndüren bir method'u harici bir web servisi olarak hazırlayarak Silverlight uygulamamıza bağlayacağız. Bunun için Silverlight uygulamamızı host edecek olan ASP.NET 3.5 sitesine bir web servisi ekleyerek içerisine aşağıdaki kodu yazıyoruz.

Imports System.Web

Imports System.Web.Services

Imports System.Web.Services.Protocols

 

<WebService(Namespace:="http://tempuri.org/")> _

<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _

Public Class servisim

    Inherits System.Web.Services.WebService

 

    <WebMethod()> _

    Public Function Toplama(ByVal x As Integer, ByVal y As Integer) As Integer

        Return x + y

    End Function

 

End Class

Bir sonraki adımda Silverlight projemize Visual Studio 2008 içerisinde sağ tıklayarak gelen menüden "Add Service Reference" komutunu vererek servisimizi Silverlight projesine referans olarak ekliyoruz.

Uygulamamızı tasarlıyoruz

Silverlight uygulamamız içerisinde iki adet TextBox, bir Button ve bir de TextBlock yer alacak. Bu TextBox'lardan alınan değerler web servisine gönderilecek. Değerlerin toplam web servisinden geri döndüğünde ise sonuç TextBlock içerisine yazılacak. Hazırlayacağımız örnek bir Silverlight uygulamamısının XAML kodu aşağıdaki şekilde sonuçlanıyor.

<UserControl x:Class="SilverlightApplication2.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

    <Grid x:Name="LayoutRoot" Background="White">

        <TextBox Height="31" HorizontalAlignment="Left" Margin="48,46,0,0" VerticalAlignment="Top" Width="115" Text="" x:Name="Sayi1"/>

        <TextBox Height="31" HorizontalAlignment="Right" Margin="0,46,79,0" VerticalAlignment="Top" Width="116" Text="" x:Name="Sayi2"/>

        <Button Height="33" HorizontalAlignment="Stretch" Margin="133,112,155,0" VerticalAlignment="Top" Content="TOPLA" x:Name="Topla"/>

        <TextBlock Height="42" Margin="87,0,103,72" VerticalAlignment="Bottom" Text="TextBlock" TextWrapping="Wrap" x:Name="Sonuc"/>

    </Grid>

</UserControl>

Servisimizi kullanalım...

Sıra geldi artık işin arkaplanın geçerek kodumuzu yazmaya. Projemize eklediğimiz servis referansına verdiğimiz isim üzerinden servisimizin bir kopyasını yaratarak içerisindeki Toplama metodunu kullanmak istiyoruz.

        Dim BirServis As New KlasikServisim.servisimSoapClient

        BirServis.ToplamaAsync(Sayi1.Text, Sayi2.Text)

Yukarıdaki kod aslında alışık olduğumuz web servisi kullanımından pek farklı değil. Fakat arada ufak bir değişiklik var. Bizim adını "Toplama" olarak koyduğumuz metodun sonuna Async eklenmiş. Aslında bunun anlamı çok basit; Silverlight tarafında çağırdığınız bir web servisi tamamen asenkron olarak çalıştırılıyor. Yani bizim AJAX tarafında alışık olduğumuz istemciden sunucuya bağlanarak veri çekme mantığı bire bir web servisleri için de uygulanmış. Oysa eskiden Windows programlarında web servisleri kullanırken içerisinde bulunduğumuz Threat kesinlikle verinin gelmesini beklerdi.

Peki veri asenkron geliyorsa bizim verinin geldiğinden haberdar olmamız gerekmez mi? Çünkü bu şartlar altında verinin ne zaman sunucudan geleceğini bilemiyoruz. İşte tam bu noktada kodumuz içerisinde dinamik olarak bir event-handler tanımlamamız gerekiyor.

       Dim BirServis As New KlasikServisim.servisimSoapClient

        AddHandler BirServis.ToplamaCompleted, AddressOf Bitti

        BirServis.ToplamaAsync(Sayi1.Text, Sayi2.Text)

        Sonuc.Text = "Hesaplanıyor..."

Yukarıdaki kodumuzda Bitti adındaki bir event-handler'ı servisimizin ToplamaCompleted metoduna bağlıyoruz. Böylece Toplama işlemi tamamlandığında söz konusu event-handler çalıştırılacak. Şimdi bir de veri geldiğinde nasıl TextBlock içerisine yazdıracağımıza göz atalım.

    Public Sub Bitti(ByVal sender As Object, ByVal e As KlasikServisim.ToplamaCompletedEventArgs)

        Sonuc.Text = e.Result

    End Sub

Gördüğünüz gibi bir önceki adımda tanımladığımız Bitti event'ının aldığı ikinci parametre olan ToplamaCompletedEventArgs tipinde e değişkeni üzerinden Result yani sonuca ulaşabiliyoruz. Söz konusu parametre doğrudan Toplama metoduna özel olduğu için içerisinde Result özelliğinin tipi de zaten web servisimizdeki metodun dönüş tipi olan Integer.

Uygulamamızın tam kodu aşağıdaki şekilde sonlanıyor.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Topla_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Topla.Click

        Dim BirServis As New KlasikServisim.servisimSoapClient

        AddHandler BirServis.ToplamaCompleted, AddressOf Bitti

        BirServis.ToplamaAsync(Sayi1.Text, Sayi2.Text)

        Sonuc.Text = "Hesaplanıyor..."

    End Sub

 

    Public Sub Bitti(ByVal sender As Object, ByVal e As KlasikServisim.ToplamaCompletedEventArgs)

        Sonuc.Text = e.Result

    End Sub

End Class

Hepinize kolay gelsin.

Wednesday, April 23, 2008 12:39:11 AM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight 2.0  | 
 Sunday, April 20, 2008

Silverlight 2.0 Beta 1 ile gelen yeni Silverlight kontrollerinden biri olan PopUp kontrolü ile beraber Silverlight uygulamaları içerisinde dahili PopUp sistemleri oluşturabiliyoruz. Özellikle farklı Silverlight kullanıcı kontrollerinin bulunduğu projelerde farklı arayüzler arası geçişleri sağlamak için PopUp kontrolleri büyük kolaylık sağlıyor.

Hemen bir PopUp kontrolü örneği yapmak için yeni bir Silverlight 2.0 Beta 1 projesi yaratarak uygulamamızın ana XAML'ı olan Page.XAML içerisine bir düğme yerleştiriyoruz. Söz konusu düğmeye basıldığında PopUp kontrolü açılacak.

[Page.xaml]

<UserControl x:Class="SilverlightApplication1.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="800" Height="600">

    <Grid x:Name="LayoutRoot" Background="#FFFF0000">

        <Button Height="36" HorizontalAlignment="Left" Margin="26,40,0,0" VerticalAlignment="Top" Width="65" Content="POPUP&#xd;&#xa;AÇ" TextAlignment="Center" x:Name="Dugme"/>

    </Grid>

</UserControl>

Uygulamamızın ana sayfasını yukarıdaki şekilde tasarladıktan sonra sıra geldi PopUp kontrolü içerisinde kullanacağımız özel kullanıcı kontrolünü (User Control) hazırlamaya. Söz konusu User Control içerisinde de PopUp'ı kapatacak olan bir düğme ve bir de TextBlock yer alacak.

[UserControl1.xaml]

<UserControl

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expssion/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

    x:Class="SilverlightApplication1.UserControl1"

    d:DesignWidth="640" d:DesignHeight="480">

 

    <StackPanel x:Name="LayoutRoot">

        <Canvas Height="323" Width="478" Background="#FF2DFF00">

            <TextBlock TextWrapping="Wrap" FontSize="72" FontWeight="Bold" Text="Popup Test" Height="232" Width="478" Canvas.Left="31" Canvas.Top="29"/>

            <Button Height="112" Content="POPUP Kapat" x:Name="Dugme" Width="171" Canvas.Left="132" Canvas.Top="159"/>

        </Canvas>

    </StackPanel>

</UserControl>

Üstteki şekli ile UserControl'ümüzü de tamamladıktan sonra artık XAML dosyalarımızı ve tasarımlarını bitirdiğimize göre Visual Studio ile kod yazma kısmına geçebiliriz. İlk olarak ana XAML dosyamızdaki Dugme'mizin arkasına PopUp kontrolünü yaratarak ekrana getirecek olan kodu yazalım.

Dim PopupKontrol As New System.Windows.Controls.Primitives.Popup

PopupKontrol.Child = New UserControl1

PopupKontrol.IsOpen = True

Kodumuzun ilk satırında System.Windows.Controls.Primitives NameSpace'i altında yer alan PopUp sınıfını kullanarak yeni bir PopUp kontrolü yaratıyoruz. Bir sonraki satırda ise UserControl olarak hazırladığımız ve adı UserControl1 olan kontrolümüzden bir kopya yaratarak PopUp kontrolünün Child özelliğine eşitliyoruz. İşlemleri tamamladıktan sonra artık PopUp kontrolümüzü ekrana getirebileceğimize göre IsOpen özelliğine True değerini vererek ilerleyebiliriz.

PopUp kontrolümüz ekranda gösterildiğine göre sıra geldi PopUp kontrolündeki UserControl1 içerisindeki düğmeye basıldığında söz konusu PopUp'ı ekrandan kaldırmaya.

Me.Visibility = Windows.Visibility.Collapsed

Yukarıdaki kod ile basit bir şekilde UserControl içerisindeki Düğme'nin Click durumunda UserControl'ümüzü görünmez hali getirerek sahneden kaldırıyoruz. Silverlight uygulamamızında code-behind dosyalarının son hali aşağıdaki şekilde;

[Page.xaml.vb]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Dim PopupKontrol As New System.Windows.Controls.Primitives.Popup

        PopupKontrol.Child = New UserControl1

        PopupKontrol.IsOpen = True

    End Sub

End Class

[Usercontrol1.xaml.vb]

Imports System

Imports System.Windows

Imports System.Windows.Controls

Imports System.Windows.Media

Imports System.Windows.Media.Animation

Imports System.Windows.Shapes

 

Partial Public Class UserControl1

    Inherits UserControl

 

    Public Sub New()

        ' Required to initialize variables

        InitializeComponent()

    End Sub

 

    Private Sub Dugme_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Dugme.Click

        Me.Visibility = Windows.Visibility.Collapsed

    End Sub

End Class

Hepinize kolay gelsin.

Sunday, April 20, 2008 10:36:26 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, April 17, 2008

Bir yazgelistir.com Silverlight Editörü olarak yeni Silverlight ve WPF yazılarım sitede yerini aldı. Blogumu takip edenler için maalesef yeni bir yazı yok ama en azından kaçırdıklarınıza bir göz atma hatta belki hepsine birer oy verme şansınız olabilir :)

Silverlight 2.0 ve JavaScript Kardeşliği
SharePoint Server üzerinde Silverlight kullanımı.
Silverlight 2.0 içerisinde ZIP arşivleri kullanmak.
Silverlight 2.0 içerisinde farklı XAML dosyaları kullanımı
WPF uygulamalarında Winforms kontrollerinin kullanımı
Winforms uygulamalarında WPF animasyonlarından faydalanmanın yolu.

Thursday, April 17, 2008 9:09:07 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0 | WPF  | 
 Monday, April 14, 2008

Silverlight 2.0 ile beraber istemci tarafında VB.NET veya C# kullanabileceğimizi artık biliyoruz. Durum böyle olunca söz konusu .NET dilleri ile Silverlight uygulamasının dışına çıkarak HTML sayfasındaki klasik HTML elementlerine ulaşmak da büyük kolaylıklar sağlayabilir. Böylece aslında kısmen şu an için istemci tarafındaki JavaScript'in hakimiyetini kırmak da mümkün. Tabi bunun tam tersi senaryolarda da JavaScript tarafından yola çıkarak Silverlight içerisinde .NET metodlarına ulaşmak isteyebiliriz.

HTML elementlerine ulaşalım

İlk olarak Silverlight tarafında yazdığımız kod ile sayfadaki HTML elementlerine nasıl ulaşabileceğimize bir göz atalım. Bunun için ilk olarak Silverlight 2.0 Beta 1 uygulaması içerisinden dışarı çıkarak Browser içerisinde HTMLPage'in Document nesnesini yakalamamız gerekiyor.

Private Sub Dugme_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Dugme.MouseLeftButtonDown

    Dim MevcutBelge As System.Windows.Browser.HtmlDocument = System.Windows.Browser.HtmlPage.Document

    MevcutBelge.GetElementById("icerik").SetAttribute("innerHTML", "DENEME METNİ")

End Sub

MevcutBelge değişkenimize sayfadaki mevcut HTMLDocument nesnesini aktardıktan sonra artık klasik JavaScript metodu gibi GetElementById metodunu kullanabiliyoruz. Silverlight 2.0 animasyonunun bulunduğu sayfadaki "icerik" adındaki HTML elementini yakaladıktan sonra basit bir şekilde innerHTML özelliğine farklı bir metin aktarıyoruz. Bu şekilde VB veya C# kodu ile sayfalardaki HTML elementlerine ulaşılarak farklı işlemler rahatlık istemci tarafında yapılabilir.

Peki ya bir JavaScript kodu çalıştırmak istersek?

İstemcideki .NET kodunuz ile sayfalarınızda hali hazırda yer alana JavaScript kodlarını birbiri ile konuşturabiliyor olmak tabi ki çok önemli. HTML sayfası içerisinde tanımlanmış olan herhangi bir JavaScript metodunu doğrudan çalıştırmak için aşağıdaki kodu kullanabilirsiniz.

System.Windows.Browser.HtmlPage.Window.CreateInstance("Uyari")

Yukarıdaki kod içerisinde "Uyari" adındaki JavaScript fonksiyonu çalıştırılıyor. Eğer bu fonksiyon aşağıdaki gibi tanımlanarak bir parametre alsaydı daha farklı bir şekilde çalıştırmamız gerekecekti.

function Uyari(mesaj)

{

    alert(mesaj);

}

Yukarıdaki JavaScript fonksiyonunu Silverlight tarafından VB veya C# ile çalıştırırken göndereceğimiz parametreyi de ek olarak belirtmemiz gerekecek.

System.Windows.Browser.HtmlPage.Window.CreateInstance("Uyari", New String("23"))

CreateInstance metoduna verdiğimiz ilk parametre çalıştırmak istediğimiz JavaScript metodunun adı şeklinde düzenlenirken verdiğimiz diğer parametre ise aslında JavaScript fonksiyonumuza aktarmak istediğimiz diğer olası tüm parametrelerin bir dizisi.

JavaScript tarafından .NET'e yolculuk...

.NET tarafında hazırladığımız ve Silverlight ile istemci tarafında çalışan bir metodu JavaScript ile kullanabilmemiz için ilk aşamada yapmamız gereken bazı ayarlar var. Bunlardan ilki uygulamamız ilk yüklendiğinde elimizdeki Silverlight sayfasını HTML sayfasına bir "ScriptableObject" olarak tanımlamamız gerektiği. Bunu yapmak için uygulamamızın App.xaml dosyasının arkasındaki kodlardan faydalanacağız.

Private Sub OnStartup(ByVal o As Object, ByVal e As EventArgs) Handles Me.Startup

    Dim Sayfam As New Page()

    System.Windows.Browser.HtmlPage.RegisterScriptableObject("Page", Sayfam)

    Me.RootVisual = Sayfam

End Sub

Gördüğünüz gibi ilk satırda Silverlight uygulamamızda gösterilecek sayfayı yaratıyoruz ve bir sonraki satırda hemen söz konusu sayfayı mevcut HTML sayfamıza bir ScriptableObject olarak kaydediyoruz. Sayfayı Silverlight uygulamamızın ana görsel öğesi haline getirerek kullanıcıya gösterilmesini de sağmalayı unutmayalım.

Bu ayarı tamamladıktan sonra sıra geldi JavaScript tarafı ile paylaşacağımız fonksiyonumuzu yazmaya.

<System.Windows.Browser.ScriptableMember()> _

Public Function Kare(ByVal X As Integer) As Integer

    Return X ^ 2

End Function

Yukarıdaki örnekte basit fonksiyon kendisine parametre olarak verilen sayının karesini alarak geri döndürüyor. Bu fonksiyonun JavaScript tarafı ile paylaşılabilmesi için kesinlikle yukarıdaki şekilde ScriptableMember olarak işaretlenmiş olması gerekiyor. Son olarak sıra geldi bu metodu kullanabilecek olan JavaScript kodunu yazmaya fakat onun öncesinde dikkat etmemiz gereken bir nokta. Sayfamızdaki herhangi bir Silverlight uygulaması içerisindeki bir metodu dışarıdan kullanabilmek için ilk olarak söz konusu Silverlight uygulamasını bulmamız gerekiyor. Yani Silverlight uygulamamızın bir isminin olması şart.

<object id="SL" data="data:application/x-silverlight," type="application/x-silverlight-2-b1" width="100%" height="100%">

  <param name="source" value="SilverlightApplication8.xap"/>

  <param name="onerror" value="onSilverlightError" />

  <param name="background" value="white" />

 

  <a href="http://go.microsoft.com/fwlink/?LinkID=108182" style="text-decoration: none;">

    <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

  </a>

</object>

Yukarıdaki şekliyle sayfaya yerleştirilen bir Silverlight uygulamasına isim vermek için uygulamaya ait object taglarına bir ID bilgisi atamak yeterli olacaktır. Artık ID bilgisi üzerinden Silverlight uygulamamız ulaşarak aşağıdaki gibi JavaScript içerisinden .NET metodumuzu çalıştırabiliriz.

SL.Content.Page.Kare(2)

Hepinize kolay gelsin.

Monday, April 14, 2008 1:30:40 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, April 12, 2008

SharePoint Server artık sadece bir şirket içi iletişim ve paylaşım alanı olmanın ötesinde internete açık web sitelerinin altyapısında da rahatlıkla kullanılıyor. Her iki ihtimalde de SharePoint üzerinde Silverlight kullanımı farklı olanaklar tanıyabilir. Örneğin şirket için canlı video yayını dağıtımlarınızı SharePoint ve Media Services ile Silverlight aracılığı ile kullanıcılara yansıtabilir veya şirket içi eğitim videolarınızı Silverlight ile SharePoint üzerine yerleştirebilirsiniz. Tabi ki SharePoint'in web servislerine bağalanarak AJAX aracılığı SharePoint'in dahili verisine bağlanarak çok daha farklı senaryolar da gerçeleştirilebilir.

Peki SharePoint içerisinde Silverlight'ı nasıl kullanacağız?

SharePoint içerisinde Silverlight kullanımı ile ilgili yayınlanmış olan bir paket var. Bu paketi sunucuya yüklemenizle beraber artık SharePoint üzerinde size özel bir WebPart'ınız oluyor. Bu WebPart'ı herhangi bir WebPartZone'a ekleyerek istediğiniz Silverlight uygulamasının söz konusu alanda çalışmasını sağlayabiliyorsunuz. Özetle, aslında WebPart'ımız Silverlight uygulamalarımız için bir HostElement görevi görüyor.

Software & Services BluePrints çerçevesinde yayınlanan paketin adı Silverlight BluePrint for SharePoint şeklinde. Aşağıdaki adresten söz konusu paketleri ve örnekleri indirerek sunucunuza kurabilirsiniz.

http://www.ssblueprints.net/sharepoint/

Maalesef bu adresteki çoğu örnek Silverlight 2.0 ile hazırlanmış durumda. "Maalesef" dememin nedeni daha Silverlight 2.0'ın Beta 1 sürecinde olması ve kesinlikle kullanımdaki sunucularınıza SL 2.0 ile ilgili yüklemeleri yapmamanız gerektiği. Bu durumda hızlı bir şekilde yukarıdaki adresteki ilk örnek olan "Hello Silverlight Web Part"ını yükleyerek işe başlayabiliriz. Bu yükleme paketi içerisinde SilverlightPart'ın yüklemesi de bulunuyor. SharePoint'e Silverlight uygulaması yüklemek için kullanacağımız esas WebPart da zaten bu. WebPart şu anda SL 2.0 da desteklediği için bazı durumlarda SL2.0 yüklemeleri de yapmamız şart.

"Setup_SilverlightPart.zip" adındaki dosyanın içerisinde yüklemeyi tamamlamanız yeterli olacaktır. Diğer yüklemeler sadece örnek uygulamalar içeriyor. İşimiz bitti zannediyorsanız aldanıyorsunuz. Daha yapmamız gereken birçok iş var. Gelin sunucuda yapılması gerekenleri bir liste haline getirelim.

  • Silverlight BluePrint sitesinden ilk örneği indir ve içerisindeki Setup_SilverlightPart.zip dosyasında yüklemeleri yap.
  • Silverlight Plug-In'i sunucuya yüklemeniz gerekiyor. (Sorun yaşarsanız SL 2.0 Plug-In'i de yüklemek durumunda kalabilirsiniz)
  • Silverlight 2 Beta 1 SDK'nın sistemde yüklü olması gerekiyor.
  • "C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Server" adresinden System.Web.Silverlight.dll dosyasını "C:\windows\assembly" adresine kopyalayın.
  • SharePoint web sitenizin altındaki /ClientBin/ klasöründe doğru Silvelight.js dosyasının bulunduğundan emin olun. Eğer yoksa "C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Tools" adresinden söz konusu dosyayı kopyalayın.
  • IIS üzerinde XAML ve kullanacaksanız SL 2.0 için XAP Mime Type ayarlarını yapmanız gerekecek. Ayarlar şu şekilde olmalı.
    Extension: .xaml / MIME Type: application/xaml+xml
    Extension: .xap / MIME Type: application/x-silverlight-2-b1 (Sadece SL 2.0 Beta 1 için özeldir)
  • Son olarak IIS'e ufak bir reset ile işlemi tamamlayabiliriz.

SilverlightPart'ın kullanımı üzerine...

SharePoint sunucumuza yüklediğimiz SilverlightPart özelliğini aktif hale getirmek için ilk olarak "Site Actions / Site Settings / Modify All Settings" menüsünden yola çıkarak "Site Collection Features" kısmına gitmemiz gerekiyor. Burada yüklemiş olduğunuz SilverlightPart'ı göreceksiniz, hemen yanında "Activate" düğmesi ile özelliği aktif hale getirebilirsiniz.

SilverlightPart özelliğini aktif hale getirdik.
SilverlightPart özelliğini aktif hale getirdik.

Artık herhangi bir sayfada WebPart olarak SilverlightPart'ımızı ekleyebiliriz. Sayfalarımızda "Add a WebPart" dedikten sonra karşımıza gelen listeden SilverlightPart'ımızı seçebiliyoruz. Ekleme işlemini tamamladıktan sonra sıre geliyor ayarlara. WebPart'a ait "Tool Pane"'i açtığınızda karşınıza bazı seçenekler gelecek. Bu seçeneklerden ilki SharePoint sitenize koyacağınız Silvleright uygulamasının hangi sürüm için hazırlanmış olduğu. Eğer 2.0 için hazırlanmış ise sizden bir XAP dosyası seçmeniz istenecek. Eğer SL 1.0 için hazırlanmış bir uygulamayı sitenize yerleştireceksiniz bu sefer de XAML dosyasını seçmeniz gerekecektir. SL 1.0 uygulamanızın arkaplanında bir programlama yapıldıysa ayrıca "Include JavaScript" işaretini de işaretleyerek uygun JavaScript dosyasını seçmeniz şart. Bahsettiğimiz bu JavaScript dosyası Expression Blend 2 ile yaratılmış bir projedeki Page.xaml.js dosyasına denk geliyor. Yani hiçbir şekilde Silverlight.js veya default.html.js içerisinde yapılan işlemlerin yapılmasına veya söz konusu dosyalardaki kodların bu tarafa taşınmasına gerek yok çünkü SL uygulamasının yaratılması ve sayfaya yerleştirilmesi işini SilverlightPart yapacak, yani gerekli JavaScript kodlarını kendisi yaratacak.

SilverlightPart ayarları.
SilverlightPart ayarları.

Tüm ayarlarımızı tamamladığımıza göre artık "OK" düğmesine basarak sayfamızda Silverlight uygulamamızı rahatlıkla çalıştırabiliriz. Peki bu seçtiğimiz XAML, XAP ve JavaScript dosyaları nerede? SharePoint web sitenizin içerisindeki ClientBin klasörü içerisinde koyduğunuz tüm dosyalar SilverlightPart içerisinde seçilebilir hale gelecektir.

Hepinize kolay gelsin.

Saturday, April 12, 2008 12:57:51 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight | Silverlight 2.0 | SharePoint  | 
 Friday, April 11, 2008

Bugün Swiss Hotel'de düzenlenen Microsoft SharePoint Konferans serisinin İstanbul ayağında Silverlight BluePrint ile SharePoint entegrasyonu konusunu işledik. 50 dakika gibi kısa bir sürede hem Silverlight'ın sektördeki yerine hem SharePoint ile beraber kullanılmasına değindim.

Microsoft SharePoint Konferansı, İstanbul
Microsoft SharePoint Konferansı, İstanbul

Normalde SharePoint ile ilgili yazılar yazmıyorum ama özellikle dünki aktiviteye katılan arkadaşlara not olması amacıyla SharePoint ile Silverlight entegrasyonundan bahsettiğim bir makaleyi yarın bloguma ekleyeceğim. Yarın da sizi bloguma beklerim ;)

Friday, April 11, 2008 5:17:48 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight | Silverlight 2.0  | 
 Monday, March 31, 2008

Silverlight 2.0 yazılarıma başladığım günlerde aklıma olmasına rağmen atladığım bir yazıyı bugün sizlerle paylaşıyorum. Seminer ve eğitimlerde karşılaştığım kadarıyla hem Silverlight'ın sürümleri arasında hem de Silverlight ile geliştirme yapılacak araçların sürümleri arasında ciddi bir kafa karışıklığı söz konusu. Gelin elde neler var, ve ne yapmak için ne kullanmamız gerekiyor bir göz atalım.

Expression Blend : Blend'in ilk sürümünde WPF uygulamaları geliştirebilirsiniz fakat Silverlight uygulaması geliştiremezsiniz. Bunun nedeni aslında çok basit. Blend ilk çıktığında ortada Silverlight diye birşey yoktu. O nedenle ürün içerisinde de böyle bir destek yok. Özetle Expression Blend'in ilk sürümünün SL dünyasında yeri yok.

Expression Blend 2 : Blend'in bir sonraki sürümü olan Blend 2'nin Nisan ayı içerisinde satışa sunulması yani "release" olması bekleniyor. Bu sürüm içerisinde tabi ki Silverlight 1.0 desteği var. Şu an Blend 2'nin Beta'sını indirerek bilgisayarınızda çalıştırabilir ve SL 1.0 uygulamaları geliştirebilirsiniz. Adı sonradan SL 2.0 olarak değiştirilen SL 1.1 uygulamaları da yine Blend 2 içerisinde geliştirilebiliyordu fakat bu sistem değişti. Artık SL 1.1 kalmadığına göre zaten bu kullanımın da doğru olduğunu söyleyemez. Daha önceleri SL 1.1 kullananlara tavsiyem sistemlerindeki SL 1.1 ile ilgili herşeyi kaldırmaları.

Expression Blend 2.5 : Silverlight 2.0 uygulamaları geliştirmek istiyorsanız Expression Blend 2.5 ile yola çıkmanız gerekiyor. Unutmayalım ki SL 2.0 daha Beta 1 aşamasında bu nedenle Blend 2.5 de Preview sürümü ile karşımıza çıkıyor.

Microsoft Silverlight 1.0 Software Development Kit : Silverlight 1.0 ile ilgili uygulama geliştiriyorsanız sisteminize bu paketi yükleyerek hem yardım dosyalarından hem de Visual Studio'ya entegre olan SL Proje şablonundan faydalanabilirsiniz.

Microsoft Silverlight Tools Beta 1 for Visual Studio 2008 : Adından pek anlaşılmasa da aslında bu paket SL 2.0 için hazırlanmış durumda. VS içerisinde SL 2.0 proje şablonlarını ve gerekli Intellisense desteğini yüklüyor. Paket içerisinde aslında ayrıca da indirilebilen SL 2.0 BETA SDK da bulunuyor.

Benim her zamanki tavsiyem SL 2.0 ile ilgili yüklemeleri SL 1.0 uygulaması geliştirdiğiniz makinelere yapmamanız yönünde. Mümkünse bir sanal makine kullanarak SL 2.0 uygulama çalışmalarınızı söz konusu makine üzerinde devam ettirin.

Hepinize kolay gelsin.

Monday, March 31, 2008 11:29:28 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Expression Blend | Silverlight | Silverlight 2.0 | Visual Studio 2008  | 
 Saturday, March 29, 2008

Silverlight 1.0 içerisinde sunucu tarafından ZIP dosyaları alarak bunların içerisindeki dosyaları istemci tarafında çıkartarak kullanabiliyor olmak büyük avantaj sağlıyordu. Özellikle böyle bir işlevsellik sağlamak için de neredeyse hiçbir ek kod yazmıyor olmamız şaşırtıcı bir kolaylıktı. Bu şaşkınlığımızı almak adına Silverlight 2.0 Beta 1 içerisinde işler biraz daha zorlaştırılmış durumda. Gelin bir örnek ile ilerleyelim. Sayfamızda iki adet resim göstermek istiyoruz. Bu resimler bir ZIP dosyası içerisinde sunucuda yer alacak.

<UserControl

  xmlns="http://schemas.microsoft.com/client/2007"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  x:Class="SilverlightApplication6.Page"

  Width="640" Height="480">

 

  <Grid x:Name="LayoutRoot" Background="White" >

    <Image HorizontalAlignment="Left" Margin="42,64,0,235" Width="221" x:Name="Resim1" />

    <Image Margin="303,64,118,235" x:Name="Resim2"/>

    <Button Height="53" HorizontalAlignment="Stretch" Margin="200,0,301,138" VerticalAlignment="Bottom" Content="Button" x:Name="Dugme"/>

  </Grid>

</UserControl>

Yukarıdaki örnek Silverlight 2.0 Beta 1 projemize ait Page.xaml dosyasının kodunu inceleyebilirsiniz. Hedefimiz düğmeye tıklandığında sunucudaki fotolar.zip dosyasını istemciye indirerek içerisindeki iki farklı resmi ekrandaki iki boş Image tagının içerisine yerleştirmek. İlk olark sunucudan asenkron bir istek ile veri alabilmek için bir WebClient nesnesi yaratmamız gerekiyor.

Private Sub Dugme_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Dugme.MouseLeftButtonDown

    Dim Talep As New System.Net.WebClient

    AddHandler Talep.OpenReadCompleted, AddressOf VeriGeldi

    Talep.OpenReadAsync(New Uri("fotolar.zip", UriKind.Relative))

End Sub

Yukarıdaki kodumuz Silverlight uygulamamızda düğmeye basıldığında çalışacak olan kodun ta kendisi. İlk olarak Talep adında bir WebClient nesnesi yaratıyoruz. Sonrasında bu WebClient'ın OpenReadCompleted durumunda çalışacak olan VeriGeldi fonksiyonuna ait atamayı tamamlıyoruz. Böylece sunucudan istediğimiz veri istemciye ulaştığında birazdan yazacağımız VeriGeldi fonksiyonu / event handler'ı çalışacak.

Son satırda OpenReadAsync metodu ile sunucudan fotolar.zip dosyasını istiyoruz. Söz konusu isteği gerçekleştirirken OpenReadAsync metoduna bir Uri vermemiz gerekiyor bunun için Relative bir Uri yaratıyoruz. Relative yaratmamızın nedeni fotolar.zip dosyasının Silverlight uygulamasının çalıştığı adres ile aynı konumda bulunacak olması.

    Dim GelenVeri As System.IO.Stream = e.Result

    Dim FotoStream As System.IO.Stream = Application.GetResourceStream(New System.Windows.Resources.StreamResourceInfo(GelenVeri, Nothing), New Uri("creek.jpg", UriKind.Relative)).Stream

Artık yavaş yavaş VeriGeldi event-handlerımızda çalışacak kodları yazmaya başlayalım. İlk satırda söz konusu event-handlerımıza parametre olarak gelecek olan System.Net.OpenReadCompletedEventArgs tipinde e değişkeni üzerinden e.Result diyerek sunucudan gelen Stream'i alıyoruz. Sonraki satırda işler biraz karışık. Elimizdeki Stream'i, yani GelenVeri değişkenini bir StreamResourceInfo'ya dönüştürmemiz gerekiyor. Bunu da Application.GetResourceStream metoduna birinci parametre olarak veriyoruz. Böylece GetResourceStream metodu artık nereden Resource çıkartacağını biliyor. ZIP dosyamızın gelen stream'ini dönüştürerek GetResourceStream'e verdikten sonra tanımlamamız gereken ikinci parametre ise ZIP dosyası içerisinden hangi dosyayı yani Resource'u almak istediğimiz. Bunun için de bir Relative Uri yaratarak GetResourceStream'a metoduna ikinci parametre olarak veriyoruz. Artık GetResourceStream gerekli veriyi kendisine verdiğimiz ZIP Stream içerisinden alarak bize yine bir Stream olarak verecektir. FotoStream değişkenimizi de bu şekilde yakaladıktan sonra artık işlemlere devam edebiliriz.

    Dim Foto As New System.Windows.Media.Imaging.BitmapImage

    Foto.SetSource(FotoStream)

    Resim1.Source = Foto

    Resim1.Measure(New System.Windows.Size)

FotoStream'imizden bir Foto yaratabilmek için Foto adında bir BitmapImage nesnesi yaratıyoruz. Söz konusu nesnenin SetSource metodunu kullanarak doğrudan elimizdeki FotoStream'i kendisine aktarıyoruz. Artık elimizde bir Foto bulunduğuna göre bunu XAML kodumuzdaki Resim1'in Source özelliğine aktarabiliriz. Son olarak Resim1'e ait Measure metodunu da çağırarak görsel anlamda Resim1'in ekranda kaplayacağı yer olarak kendisini toparlamasını sağlamamız gerekiyor. Aksi halde resim yüklense de daha önce Resim1'in içi boş olduğu ve boyutu ekranda ufak olduğu için gözükmeyecektir. Artık tek yapmamız gereken aynı işlemleri ikinci resim için de yaparak GelenVeri'den ikinci dosyamızı da almak ve Resim2 içerisine yerleştirmek.

Private Sub VeriGeldi(ByVal sender As Object, ByVal e As System.Net.OpenReadCompletedEventArgs)

    Dim GelenVeri As System.IO.Stream = e.Result

    Dim FotoStream As System.IO.Stream = Application.GetResourceStream(New System.Windows.Resources.StreamResourceInfo(GelenVeri, Nothing), New Uri("creek.jpg", UriKind.Relative)).Stream

    Dim Foto As New System.Windows.Media.Imaging.BitmapImage

    Foto.SetSource(FotoStream)

    Resim1.Source = Foto

    Resim1.Measure(New System.Windows.Size)

    Foto = New System.Windows.Media.Imaging.BitmapImage

    Foto.SetSource(Application.GetResourceStream(New System.Windows.Resources.StreamResourceInfo(GelenVeri, Nothing), New Uri("autumn leaves.jpg", UriKind.Relative)).Stream)

    Resim2.Source = Foto

    Resim2.Measure(New System.Windows.Size)

End Sub

Peki bu ZIP dosyası içerisinde sadece resimler mi bulunabilir? Tabi ki hayır. Aynı ZIP dosyası içerisinde bir de deneme.txt adında metin dosyası bulunduğunu varsayalım ve söz konusu dosya içerisinden ufak bir metni alıp düğmemizin üzerine yazdıralım.

    Dim MetinStream As System.IO.Stream = Application.GetResourceStream(New System.Windows.Resources.StreamResourceInfo(GelenVeri, Nothing), New Uri("deneme.txt", UriKind.Relative)).Stream

 

    Dim bitler(MetinStream.Length) As Byte

    MetinStream.Read(bitler, 0, MetinStream.Length)

    Dim Metin As New System.Text.StringBuilder

    For Each bit As Byte In bitler

        Metin.Append(Convert.ToChar(bit))

    Next

    Dugme.Content = Metin.ToString

Her zamanki gibi yeni bir Stream yaratarak elimizdeki GelenVeri üzerinden ZIP dosyasında deneme.txt'yi alıyoruz. Stream'imizi bir byte dizisine aktardıktan sonra her bir byte'ı tek tek karaktere çevirerek bir StringBuilder yardımı ile sürekli bir metne dönüştürüyoruz. Son olarak elimizdeki metni de düğmemizin üzerine yazdırıyoruz.

Böylece harici bir ZIP dosyasını istemci tarafında asenkron olarak indirmiş ve sonrasında da dosya içerisindeki iki farklı resmi farklı Image nesnelerine aktarmış olduk. Bu kadarla kalmayıp aynı ZIP dosyası içerisindeki bir TXT dosyasından da metin alarak kullandık. Sonuç olarak istemci tarafından sunucuya sadece bir istek yolladık ve tek bir dosya aldık. Ayrıca aldığımız dosyanın sıkıştırılmış olduğunu da unutmamakta fayda var.

Hepinize kolay gelsin.

Saturday, March 29, 2008 8:29:47 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Friday, March 28, 2008

Bir Silverlight uygulamasında birden çok XAML dosyası kullanarak dosyalar arasında geçiş yapmak isteyebilirsiniz. Fakat bu noktada maalesef sizi ufak bir sorun bekliyor. Herhangi bir Silverlight uygulamasının ana görsel elementini maalesef ki değiştirme şansınız yok. Ana görsel element olarak bahsettiğimiz şey aslında Silverlight 2.0 uygulamasının XAML koduna ait "Root Element" oluyor. Söz konusu root element sadece uygulama ilk çalıştırılırken belirlenebiliyor. Peki bu durumda nasıl bir çözüm geliştirebiliriz?

Root Elementi bir Container olarak kullansak?

Uygulamamızın ana elementini bir Grid yapsak ve içerisinde XAML dosyalarımızı birer UserControl olarak yerleştirsek, böylece istediğimiz zaman Grid içerisindeki elementlerini değiştirerek farklı XAML dosyaları yükletemez miyiz? Güzel bir fikre benziyor. Deneyip görelim.

İlk olarak içerisinde basit bir şekilde iki adet XAML dosyası içeren yeni bir Silverlight 2.0 projesi yaratıyoruz. Bu dosyalardan birinde sadece bir TextBlock varken diğerinde bir TextBlock ve bir de Button olarak. İlk dosyadaki Button'a basıldığında ikinci dosyanın yüklenmesini sağlayacağız. Gelin önce dosyalarımızın XAML kodlarına hızlıca bir göz atalım.

[Page.xaml]

<UserControl

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    x:Class="SilverlightApplication4.Page"

    Width="640" Height="480">

 

    <Grid x:Name="LayoutRoot" Background="White" >

        <TextBlock x:Name="etiket" Margin="146,120,270,225" TextWrapping="Wrap" FontSize="72">

            <Run FontFamily="Portable User Interface" FontSize="14.666666984558106" FontStretch="Normal" FontStyle="Normal" FontWeight="Normal" Foreground="#FF000000" Text="1"/>

        </TextBlock>

        <Button Height="30" HorizontalAlignment="Left" Margin="169,0,0,78" VerticalAlignment="Bottom" Width="105" Content="Button" x:Name="Dugme"/>

    </Grid>

</UserControl>

[Page2.xaml]

<UserControl

    xmlns="http://schemas.microsoft.com/client/2007"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

    x:Class="SilverlightApplication4.Page2"

    d:DesignWidth="640" d:DesignHeight="480">

 

    <Grid x:Name="LayoutRoot" Background="White" >

        <TextBlock Margin="154,113,206,172" TextWrapping="Wrap">

            <Run FontFamily="Portable User Interface" FontSize="14.666666984558106" FontStretch="Normal" FontStyle="Normal" FontWeight="Normal" Foreground="#FF000000" Text="2"/>

        </TextBlock>

    </Grid>

</UserControl>

Herhangi bir Silverlight 2.0 projesinde ilk açılacak olan XAML dosyasının sınıfı App.xaml ile beraber çalışan code-behind dosyasına belirlenir. Bu dosyayı  WPF uygulamalarında app.xaml'a veya ASP.NET uygulamalarındaki Global.asax'a benzetebilirsiniz. App.xaml uygulama ile ilgili global işlemlerin yapıldığı yerdir. İlk olarak app.xaml dosyasının code-behind kısmına geçerek uygulamanın OnStartUp durumuna özel bir kod yazacağız.

Private Sub OnStartup(ByVal o As Object, ByVal e As EventArgs) Handles Me.Startup

    Dim BirGrid As New System.Windows.Controls.Grid

    BirGrid.Children.Add(New Page)

    Me.RootVisual = BirGrid

End Sub

Yukarıdaki kod içerisinde ilk olarak bir Silverlight 2.0 Grid kontrolü yaratıyoruz. Unutmayın ki WPF'de de oluğu gibi Grid kontrolleri birer DataGrid değiller. Grid kontrolleri HTML'deki karşılığı ile table diyebileceğimiz container kontrollerinden sadece biri. Yarattığımız Grid kontrolü içerisine Page.xaml dosyamızı yüklemek için Page.xaml'a ait code-behind'daki sınıfından bir kopya yaratarak Grid'imizin children listesine ekliyoruz. Son olarak da uygulamamızın ana / root elementini Grid kontrolü olarak tanımlıyoruz. Böylece bundan sonra ana elementi değiştirmeden doğrudan Grid içerisindeki kontrolleri değiştirerek aslında tüm uygulama arayüzünü de değiştirmiş olacağız.

Gelelim Page.xaml dosyamızın code-behind kısmına ve bakalım Page.xaml içerisinde bulunan düğmemize basıldığında nasıl olacak da uygulama arayüzünden page.xaml'ı kaldırarak page2.xaml'ı yükleyeceğiz.

Private Sub Dugme_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Dugme.MouseLeftButtonDown

    Dim Root As Grid = CType(Me.Parent, Grid)

    Root.Children.Clear()

    Root.Children.Add(New Page2)

End Sub

Yapmamız gereken aslında şu an içerisinde olduğumuz Page.xaml dosyasının parent elementini bularak içerisindekileri silmek. Bunun için Me.Parent ile Gridimizi yakalıyoruz ve sonrasında children.clear ile sayfadaki herşeyi siliyoruz. Son olarak da Page2.xaml dosyamıdan bir kopya yaratarak aynı Grid'in içerisine ekliyoruz. Böylece Silverlight 2.0 uygulamamızın içerisinde artık başka bir XAML dosyası yüklemiş olduk.

Hepinize kolay gelsin.

Friday, March 28, 2008 12:49:38 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, March 27, 2008

Yavaş yavaş Silverlight 2.0 yazılarına başladığımız bugünlerde derinlere inmeden önce Silverlight 2.0 konusunda Silverlight Streaming Services altyapısı nasıl kullanabileceğimize değinmek istiyorum. Daha önce bu konuda Silverlight 1.0 için detaylı bir yazı hazırlamıştım.

Silverlight ile ilgili Microsoft tarafından sağlanan ücretsiz bir barındırma hizmeti olan Silverlight Streaming Services içerisinde Silverlight 2.0 uygulamalarınızı yayınlayabilmeniz için bazı ufak ayarlara dikkat etmeniz gerekiyor. Silverlight 1.0'dan farklı olarak bu sefer manifest.xml dosyası içerisinde aşağıdaki yapının bulunması şart.

<SilverlightApp>

  <version>2.0</version>

  <source>Uygulamam.xap</source>

  <width>600</width>

  <height>500</height>

  <background>white</background>

  <isWindowless>false</isWindowless>

</SilverlightApp>

Gördüğünüz gibi artık harici JavaScript linklemek ve hangi JavaScript dosyasının önce çalışacağını belirtmek gibi bir derdimiz yok. Tek yapmamız gereken yukarıdaki şekilde uygulamamızla ilgili ayarları ve XAP dosyamızı belirttikten sonra XAP dosyamız ile beraber bu manifest.xml dosyasını ZIP'leyerek sunucuya göndermek.

Hepinize kolay gelsin.

Thursday, March 27, 2008 12:13:37 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Tuesday, March 18, 2008

Silverlight 2.0 (Beta 1) yazılarımın yavaş yavaş geleceğinden bahsetmiştim. İşte ilki ile karşınızdayım. Bu yazıda Silverlight 2.0 Beta 1 ile beraber gelen yeni dağıtım şeklinden bahsedeceğiz. Silverlight 1.0 uygulamalarında sitenize herhangi bir Silverlight animasyonu yerleştirebilmeniz için epey emek harcayarak birden çok JavaScript dosyasını sayfanıza linklemeniz sonrasında uygun HTML elementlerini ayarlamanız hatta bir de yanında XAML dosyanızı koymanız gerekiyordu. Bu durum Silverlight 2.0 ile beraber değişiyor ve karşımıza XAP uzantılı dosyalar geliyor. XAP'ın herhangi bir açılımı yok (en azından şimdilik).

XAP dosyaları aslında özünde birer ZIP dosyası. Bu dosyalar içerisinde Silverlight projenize ait DLL'ler bulunuyor. Silverlight 2.0 ile beraber VB veya C# kullanarak kodlama yapabildiğimiz için bu kodlardan DLL dosyaları yaratılıyor ve söz konusu DLL'ler XAP dosyası içerisinde istemciye gönderilerek istemci tarafında Silverlight Run-Time ile çalıştırılıyor. Expression Blend ile hazırladığınız XAML dosyaları da aynı DLL dosyaları içerisine birer Resource olarak ekleniyor.

Şu an ASP.NET 3.5 Extensions paketi içerisinde yer alan ve ileride ASP.NET'e eklenmesi düşünülen kontrollerden biri olan Silverlight kontrolü XAP dosyalarını alarak doğrudan ASP.NET sayfalarına yerleştirilebilecek. Örnek bir Silverlight kontrolünün kodunu aşağıda inceleyebilirsiniz.

<asp:Silverlight runat="server"

    PluginBackground="White"

    Source="animasyon.xap"

    Version="2.0">

          <PluginNotInstalledTemplate>

                   Plug-In Yüklü Değil

          </PluginNotInstalledTemplate>

</asp:Silverlight>

Gördüğünüz gibi artık bir Silverlight 2.0 animasyonunu herhangi bir ASP.NET sitesine yerleştirmek çocuk oyuncağına dönüşmüş. Tabi "artık"derken bu kullandıklarımızın hiçbirinin daha yayında olan yazılımlar olmadığını da akılda tutmakta fayda var. Fakat geleceğin böyle olduğunu görmek hoş.

Bir XAP dosyasında neler var?

İlk olarak tabi ki bizim yazdığımız uygulamanın kodlarını ve XAML kaynaklarını içeren DLL dosyamız var. Bu DLL dosyasını De-Compile ettiğimizde içerisinde Resource olarak XAML dosyalarımızın var olduğunu görebiliyoruz.

Silverlight 2.0 DLL dosyası içerisindeki XAML dosyalarımız.
Silverlight 2.0 DLL dosyası içerisindeki XAML dosyalarımız.

Haricen Silverlight 2.0 projemizde kullandığımız kontrollere ait DLL dosyaları da yine XAP içerisinde bulunuyor. Silverlight 2.0 içerisinde standart kontroller bile ayrı DLL dosyaları olarak geliyor. Bunların zamanla Plug-In'e dahil edilip edilmeyeceği belli değil fakat Silverlight 2.0 mimarisinde harici DLL dosyalarından farklı kontroller kullanılabileceği için bu yapı her zaman var olacaktır.

Silverlight 2.0 Beta 1 XAP dosyası içeriği.
Silverlight 2.0 Beta 1 XAP dosyası içeriği.

XAP dosyası içerisinde bir de XAML dosyası bulunuyor. Aşağıda içeriğini inceleyebileceğiniz örnek bir AppManifest.xaml dosyasına baktığımızda XAP paketi içerisinde tüm DLL'lerin sınıf isimleri ile ilişkilendirildiklerini görüyoruz.

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="SilverlightApplication3" EntryPointType="SilverlightApplication3.App" RuntimeVersion="2.0.30226.2">

  <Deployment.Parts>

    <AssemblyPart x:Name="SilverlightApplication3" Source="SilverlightApplication3.dll" />

    <AssemblyPart x:Name="System.Windows.Controls" Source="System.Windows.Controls.dll" />

    <AssemblyPart x:Name="System.Windows.Controls.Extended" Source="System.Windows.Controls.Extended.dll" />

  </Deployment.Parts>

</Deployment>

Deployment tagı içerisindeki EntryPointAssembly uygulama ilk çalıştırıldığında hangi DLL'in başlatılacağını belirliyor.

Bu haliyle yeni Silverlight 2.0 paketlerine baktığımızda olayın epey derlenip toparlandığını görüyoruz. Özellikle Silverlight 1.0 ile ilgili sıkça akla gelen "kod güvenliği" sorunları ile ilgili kısmi bir ilerleme var diyebiliriz. En azından artık XAP (ZIP) dosyasını açmanız DLL'i çıkarmanız ve De-Compile etmeniz gerekiyor. Tabi ki tüm bunlar mümkün :) fakat biraz daha zağmetli hale geldi diyebiliriz. Ayrıca artık Silverlight uygulamalarının dağıtımı ve paylaşımı çok daha kolay. Özellikle bu tip animasyonları içerik yönetim sistemlerinde kullanmak isteyenler için SL 2.0 büyük kolaylık olacaktır.

Hepinize kolay gelsin.

Tuesday, March 18, 2008 8:55:24 PM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight 2.0  | 
 Sunday, March 16, 2008

Silverlight 2 Beta 1'in yayınlandığından sizleri daha önceki yazılarımda haberdar etmiştim. Bu süreçte özellikle Silverlight 2 ile ilgili yazı yazmamı isteyen birçok mail aldım. Bu konu beni epey düşündürdü. Birincisi bugün yazacağım Silverligh 2 hakkındaki yazıların ileride Silverlight 2 yayına girdiğinde geçerliliğini kaybetme olasılığı çok yüksek. Tabi ki yazıların tamamen "çöplük" olmayacağı kesin ama Silverlight 2 tarafında şu anki Beta hali ile yayınlandığı zamanki hali arasında büyük farklar olacaktır. Diğer sorun ise yazılarımı okuyan arkadaşların yaşayacağı bazı sorunlara ürün Beta olduğu için çözüm bulma şansımızın olmaması da mümkün. Son olarak yazılarımı okuyan ve uygulamak isteyen arkadaşlar hali hazırda Silverlight 1 uygulamaları geliştiriyorlarsa Silverlight 2 ile ilgili denemelerini kesinlikle sanal makinede yapmaları gerekiyor. Aksi halde çok farklı sorunlar oluşabiliyor.

Tüm bunları tek tek düşünürken geçen Microsoft lansmanında ufak bir de kamuoyu yoklaması yaptım :) kabaca her önüme gelene fikrini sordum. Genelde aldığım cevap; "Abi sen yazmazsan kim yazacak?" şeklindeydi. Tabi burada gizli başka bir soru daha var; "Birinin yazması gerekiyor mu?" Yani ürün daha Beta! Her neyse, özetle, ben düşündüm, taşındım :) ve şu an için Silverlight 1.0 ile ilgili de çok yazılmamış birşey bırakmadığım için yavaş yavaş Silverlight 2.0 dünyasına geçmeye karar verdim.

Silverlight 2.0 ile ilgili yazılarımı sizlerle paylaşmadan önce genel anlamda uyarılarımı tekrarlamak istiyorum. Her yazının başında yazının SL 2.0 Beta 1 sürümü için yazılı olduğu ibaresi zaten yer alacak ama eğer SL 1.0 ile uygulama geliştiriyorsanız kesinlikle SL 2.0 denemelerinizi başka bir makinede veya sanal makinede yapın. SL 2.0 ile hazırladığınız uygulamaları bugün gerçek hayata ticari anlamda taşıma şansınız yok. İnsanların yükleyecekleri Plug-In Beta olacaktır ki bunu müşterilerden isteyemezsiniz, ayrıca ürün Beta olduğu için neyin ne olacağı hiç belli olmaz. Benden söylemesi :)

Silverlight 2 Beta 1 Developer Poster
Silverlight 2 Beta 1 Developer Poster

Artık bu kararı da sizlerle paylaştığıma göre gelin bunu kutlayalım :) Daha önceleri sizlerle paylaştığım SL 1.1 Developer Poster'in yenisi SL 2.0 için hazırlandı. Silverlight Developer Reference (13MB) posterini TIF formatında bilgisayarınıza indirebilirsiniz.

Sunday, March 16, 2008 11:37:08 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, March 15, 2008

Seminerlerde, videolarda ve geçen gün lansmanda üzerimdeki Silverlight T-Shirt'ü büyük beğeni kazandı :) O kadar ki bir an tekstil sektörüne girsem mi diye düşünmedim değil. Maalesef beğenilerini bana "Ben de istiyorum o T-Shirt'ten" şeklinde ileten arkadaşların hepsine birer T-Shirt hediye etmem mümkün olmayacak :) Onun yerine daha güzel birşey yaptım (en azından benim için daha güzel :)) ve kendi T-Shirt'ümün baskısını da yaptırmış olduğum Tish-O ile iletişime geçerek aynı tasarımın siteye yerleştirilmesini ve böylece herkesin sipariş verebilmesini sağladım :)

Orijinal Tasarımlar
Orijinal Tasarımlar

Tish-O'nun arayüzünü kendi sitesine girdiğinizde zaten rahatlıkla keşfedebilirsiniz. Farklı bedenlerde ve stillerde T-Shirt siparişi verebiliyor, tasarımınızı kendiniz yapabiliyorsunuz. Baskı kalitesi şaşırtıcı derecede iyi, benim T-Shirt yaklaşık 6, 7 defa yıkanmasına rağmen en ufak bir baskı sorunu yok.

Siteden Silverlight T-Shirt sipariş verebilmek için yapmanız gerekenleri bir iki adımda göstermek istiyorum.

Tish-O sitesinde adım 1.
Tish-O sitesinde adım 1.

Herhangi bir T-Shirt tasarımı yaparken T-Shirt'ün ön ve arka yüzüne hazır Silverlight tasarımlarını yerleştirerek sipariş verebilirsiniz.

Tish-O sitesinde adım 2.
Tish-O sitesinde adım 1.

Görselleri ekledikten sonra sitedeki arayüzde basılacak boyutu da ayarlayabiliyorsunuz. Artık hepinizi bir sonraki seminerde Silverlight T-Shirt'leri ile bekliyorum. Kahramanlar aramızda ;)

Saturday, March 15, 2008 3:19:00 PM (GTB Standard Time, UTC+02:00)  #    Comments [5]   Silverlight | Silverlight 2.0  | 
 Wednesday, March 12, 2008

Silverlight uygulamalarında kullandığımız XAML dosyalarının bazı durumlarda IIS tarafından istemciye gönderilmediğinden daha önceki yazılarımda bahsetmiştim. Bazen bu durum özellikle sunucu admini (hosting sağlayıcı) tarafından ek ücret talebi yapabilmek adına kasıtlı olarak yapılabildiği gibi bazen de gerçekten ortada bir sorun olabiliyor. Peki nasıl düzelteceğiz?

MIME Type tanımı nasıl yapılır?

Silverlight XAML dosyalarının IIS tarafından istemciye sunulabilmesi için aşağıdaki şekilde gerekli MIME type'ların tanımlanması gerecektir.

Dosya uzantısı: .xaml
MIME type: application/xaml+xml

Dosya uzantısı: .xap
MIME type: application/x-silverlight-app

XAML'ı biliyorduk da XAP da nesi? :) XAP şu an Silverlight 2.0 Beta 1 ile beraber kullanılan bir dosya uzantısı. Eğer olur ya bir fantezi çerçevesinde Silverlight 2.0 Beta 1 ile sanal makinenizde geliştirdiğiniz bir uygulamayı sunucuya koymak isterseniz şu an için XAP dosyaları için de gerekli MIME Type'ları tanımlamanız gerekecektir. İleride Silverlight 2.0'ın yayına çıkacak orijinal sürümlerinde bu uzantının kullanılmaya devam edeceği tabi ki garanti değil. Bahsettiğimiz teknoloji daha beta aşamasında.

Gelelim bu tanımlama işini nasıl yapacağımıza. Sunucuda IIS Manager'ı açtıktan sonra MIME Type ayarı yapmak istediğiniz siteyi seçerek sağ tuş tıklayarak gelen menüden "Properties" komutunu veriyoruz. Karşımıza gelen pencereden "HTTP Header" sekmesine geçerek en alttaki "MIME Types" düğmesine tıklıyoruz.

IIS Manager içerisinde MIME Types seçeneğini bulduk.
IIS Manager içerisinde MIME Types seçeneğini bulduk.

"MIME Types" bölümüne girdikten sonra hemen "New" düğmesine tıklayarak yeni bir "MIME Type" eklemek üzere bir önceki paragraftaki ayarları buraya aynen yazıyoruz ve gördüğümüz tüm "OK" düğmelerine basarak IIS Manager arayüzüne geri dönüyoruz.

Yeni bir MIME Type ekliyoruz.
Yeni bir MIME Type ekliyoruz.

Artık gerekli uzantılar tanımlandığı için herhangi bir sorun yaşamayacağız.

Hepinize kolay gelsin.

Wednesday, March 12, 2008 1:47:49 AM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Silverlight | Silverlight 2.0  | 
 Thursday, March 06, 2008

Silverlight bir sonraki sürümü olan Silverlight 1.1'den uzun süre önce blogumda bahsetmiştim. Özellikle arka planda .NET Framework desteğini de alarak VB, C# kullanabiliyor olmak bile yeterince heyecan verici. Eski adıyla Silverlight 1.1 bir süre önce 2.0 olarak değiştirildi ve şu anda Silverlight 2.0'ın Beta sürümünü de bilgisayarınıza indirerek yükleyebiliyorsunuz. Linkleri aşağıda sizlerle paylaşıyorum.

Silverlight 2.0 Beta 1 Runtime Plug-In
Microsoft Silverlight Tools Beta 1 for Visual Studio 2008
Silverlight 2 Beta 1 SDK

Tabi yenilikler bu kadarla kalmıyor. Daha Expression Blend 2 çıkmadan Expression Blend 2.5 Mart Preview da karşımızda. Silverlight 2.0 Beta ile beraber gelen yeniliklerden faydalanarak uygulama geliştirebilmek için Blend 2.5'in de bilgisayarınızda kurulu olması şart.

Expression Blend 2.5 March Preview

Özellikle Silverlight'ın bir sonraki sürümü Alpha seviyesinden Beta 1'e gelmiş olsa da sizleri uyarmam gerek. Tavsiyem bu yazılımları sadece sanal makinelere yüklemenizdir, aksi halde her tür sorunla karşılaşabilirsiniz ve bundan kimse de sorumlu tutulamaz :) Özellikle şu an Silverlight 1.0 ile proje geliştirenlerin çok dikkatli olmasında fayda var, Silverlight 1.1 Alpha yüklü makinelerde normal Silverlight 1.0 ile ilgili de birçok sorun yaşanıyordu. Aynı durum burada da mümkün olabilir. Bu nedenle ben şiddetle bu yazılımları deneyebilmeniz için sanal makine kullanmanızı ve normal çalışma ortamınızı zedelememenizi tavsiye ederim.

Hepinize kolay gelsin.

Thursday, March 06, 2008 8:57:22 AM (GTB Standard Time, UTC+02:00)  #    Comments [2]   Expression Blend | Silverlight 2.0  | 
Copyright © 2010 Daron Yöndem. Tüm hakları saklıdır.