You are on page 1of 323

2

<NDEKLER>
ColorfulExpressionilebirbiriileuyumlurenkleriyakalamak DinamikAssemblyretimi(KodlaDinamikDLLCompileEtmek) JavaveSilverlightkardelii KendiSilverlightYklemesajnzgstermeniziinipular NETiinDeCompileilemleriveObfuscation Reflectionnedir Silverlgiht2.0veWCFServisleri Silverlight2.0Beta1ierisindeDataGridkullanm Silverlight2.0Beta1ierisindeToggleButtonkullanm Silverlight2.0Beta1ileKlasikASMXWebServisikullanm Silverlight2.0Beta2ierisindedinamikresimyklemek Silverlight2.0Beta2ileASP.NETFormsAuthenticationkullanm Silverlight2.0Beta2ileberabergelenTabControlincelemesi Silverlight2.0Beta2vePHPilemailformuygulamas Silverlight2.0CalendarveDatePickerkontrolleri Silverlight2.0CrossDomainWebClientileREST(GET)veXLINQKullanm Silverlight2.0GridSplitterKullanm Silverlight2.0HyperlinkButtonKullanm Silverlight2.0ierisindeasenkronfontdosyasindirerekkullanmak Silverlight2.0ierisindeAutoCompleteBoxkullanm Silverlight2.0ierisindeCarouselkullanm Silverlight2.0ierisindeControlTemplatingveStyleyaplar Silverlight2.0ierisindecreateFromXamlalternatifivealtseviyelidinamiknesneretimi Silverlight2.0ierisindefareroller'nkullanmak Silverlight2.0ierisindefareninifttklamasnalglamannyolu Silverlight2.0ierisindehariciClassLibraryyaplarnnasenkronkullanm Silverlight2.0ierisindeharicidinamikXAP(Silverlight2.0)uygulamalarnnasenkron yklenmesi Silverlight2.0ierisindeHueSaturationveLightnessiledinamikrenkpaletleriyaratmann yolu Silverlight2.0ierisindeIsolatedStoragekullanm Silverlight2.0ierisindeLocalizationkullanm Silverlight2.0ierisindemaskeleme(clipping) Silverlight2.0ierisindeMultiScaleImagekullanmveDeepZoommaceralar Silverlight2.0ierisindeOpenFileDialogkullanm Silverlight2.0ierisindeProgressBarkullanm Silverlight2.0ierisindesatumensndeitirmek Silverlight2.0ierisindeScrollViewerkullanm Silverlight2.0ierisindeSilverlightToolkitveTreeViewkullanm Silverlight2.0ierisindeToolkit'denViewBoxkullanm Silverlight2.0ierisindeToolkit'tenLabelkontrolnnkullanm Silverlight2.0ierisindeToolTipKontrolveTooltipablonlar

Silverlight2.0ierisindeVisualStateManagerkullanm Silverlight2.0ierisindenDownloadpenceresiatrmak Silverlight2.0iinzelnyklemeekranlargelitirmek.(PreLoader) Silverlight2.0ileAnalogSaatUygulamas Silverlight2.0ileOyunProgramlama'yaGiri Silverlight2.0ilePowerpointdosyalarnnThumbnail'lerinigstermek Silverlight2.0ileTwitterveTwitXRComboWidget Silverlight2.0ItemsControlveObservableCollectionileDataBinding Silverlight2.0kontrolleriyaratmannyolu Silverlight2.0PlugInAlglamaveOBJECTTag Silverlight2.0PopUpKontrol Silverlight2.0RC0ierisindeComboBoxkullanm Silverlight2.0RC0ierisindePasswordBoxkullanm Silverlight2.0UygulamalarParametreGnderimi Silverlight2.0UygulamalarndafarklXAMLdosyalarkullanmak Silverlight2.0veAdaptiveStreaming Silverlight2.0veADO.NETDataServices Silverlight2.0veJavaScriptkardelii Silverlight2.0veJSONSerializeDeSerializelemleri Silverlight2.0veSocketProgramlamaMucizesi Silverlight2.0XAPPaketleri Silverlight2.0XAPPaketleriveKaynakDosyalar Silverlight2.0'dafareninhareketetmediinianlamak SilverlightierisindeClipBoardkullanm Silverlightierisindesayfaadresineulamak SilverlightRuntimeveSDKDLL'leriveaklamalar SilverlightToolkitierisindegelenhazrrenkablonlar(Thema)inceliyoruz SilverlightToolkit'tenWrapPanel'inkullanm SilverlightuygulamalarveIISMIMETypeayar Silverlightuygulamamzntarayctarafndantekrarboyutlandrldnnaslalglarz SilverlightveWPF'deDesignModeveInitdurumundakodlarsorunsal Silverligth2.0'dauygulamafonunueffafkullanmak SL2.0'daZIPierisindenasenkronkaynakkullanm VistaGradientlarXAMLKodlar

Colorful Expression ile birbiri ile uyumlu renkleri yakalamak. Renklerin birbirine uyumu zellikle biz yazlmclar iin pek anlalamayan bir sistemi tanmlar :) Kiisel olarak ben bir renk ynndaki renklerin birbirine uyumlu olup olmadn anlayabilsem de "Buyur uyumlu 3 renk se" derseniz pek de baarl olamam. Belli ki bu durum genel geer bir sorunu tanmlyor ki RD, Jonas Folloseo birazdan sizlere detaylarndan bahsedeceim uygulamay hazrlam. Uygulama znde Adobe'nin Kuler sitesinin API'larn kullanyor. Kuler'dan hzl bir ekilde bahsetmek gerekirse tasarmclarn birbirleri ile uyumlu renk emalarn paylatklar bir Web 2.0 portal diyebiliriz. Colorful Expression Aadaki adresten indirebileceiniz uygulama toplam 3 blmden oluuyor. http://www.codeplex.com/colorful Birincisi Colorful WPF adnda tek bana alabilen bir WPF uygulamas. Bu uygulama ierisinde birbirleri ile uyumlu renk emalarn inceleyebilir ve aramalar yapabilirsiniz. Unutmayn ki sistem Kuler'n API'larndan faydalanyor yani program ancak online durumdayken kullanabilirsiniz. Colorful WPF'in en gzel zellii herhangi bir renk emasnn altndaki dmeler aracl ile hzl bir ekilde bu renkleri kullanabilmenizi salayacak XAML Brush kodlarn alabiliyor olmamz.

Colorful WPF ierisinde "silver" kelimesi aratldnda kan birbiri ile uyumlu renklerin bir listesi.

Yukardaki ekran grntsnde yer alan en stteki "Silver" adndaki renk emasnn altndaki "Swatches" dmesine tkladmda dorudan aadaki XAML kodu panoya kopyalanyor ve rahatlkla 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 ierisindeki renk ablonlarn isterseniz dorudan Expression Design veya Blend ierisinde de kullanabiliyorsunuz. Bunun iin download paketi ierisinden program adna uygun klasrn iindeki 2 DLL dosyasn programlarn bilgisayarlarnzda ykl olduklar konumlara kopyalamanz gerek. Sonrasnda aadaki ekilde hem Blend hem de Design' altrdnzda Colurfull Expression' dorudan Blend veya Design ierisinde de kullanabilirsiniz. Blend.exe addin:Colorful.Blend.AddIn.dll Design.exe addin:Colorful.Design.AddIn.dll

Expression Design ierisinde Colorful paneli. Yukardaki ekran grntsnde Colurful Expression'n dorudan Expression Design ierisinde kullanlabildiini grebiliyorsunuz. Ayn ekilde Blend 2 ierisinde de rahatlkla Colurful paneline ulalabiliyor.

Expression Blend 2 ierisinde Colorful paneli. Blend ierisinde Colorful panelinin kullanm ile ilgili Design'a kyasla ek avantajlar da sz konusu. Sahneye srkleyip braktnz bir renk ablonu aslnda arka planda birer SolidColorBrush olarak sayfann Resource'larna ekleniyor. Bylece bu renkleri istediiniz kadar farkl yerlerde rahatlkla merkezi olarak kullanabiliyorsunuz.

Colorful'un yaratt XAML kodlar otomatik olarak karmzda. Hepinize kolay gelsin.
DaronYNDEM

Cross Domain Request iin sunucu tarafl ASP.NET Proxy stemci tarafl programlama sistemleri AJAX ile karmza kmt, Silverlight ile beraber ise artk istemci tarafl programlama neredeyse "hayatmz" oluyor. Bu durumda karlatmz en byk sorun "Cross-Domain-Request" snrlamas. Gvenlik nedenleriyle bir alan adndan bir baka alan adna balanarak veri talebinde bulunamyoruz. Eer kardaki alan adnn ihtiva ettii siteye admin eriiminiz 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 eriimimiz yoksa? te o zaman kendi sitemizde sunucu tarafl bir proxy kullanmamz art. ASP.NET ile sunucu tarafndan istediimiz siteye balanarak istediimiz dosyas alabiliriz. Bu durumda bir ASPX sayfas yapsak bizim yerimize gidip kendisine hedef gsterdiimiz adresten gerekli dosyay alp istemci tarafna, 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() Yukardaki kod ierisinde dorudan bir WebClient yaratarak farkl bir adresten veri indirme ilemi yapyoruz. Kod ierisindeki en nemli nokta indirmek istediimiz hedef veri ile istemciye gndereceimiz verinin ContentType deerlerinin ayn olmas gerektii. Bunun iin Response.ContentType' WebClient zerinden aldmz Content-Type header bilgisi ile eletiriyoruz. Bylece proxy'miz gerektiinde video veya resim dosyalarn da rahatlkla indirerek bize ulatrabilir. Performans? Yukardaki rneimiz ok basit bir yapya sahip. Dosyay sunucuya indirerek dorudan istemciye gnderiyor. Yksek sayda istek oluan projelerde veya byk dosyalar indirecek olan uygulamalarnda farkl performans senaryolar uygulamak gerekecektir. Aslnda baktmzda bu yapnn herhangi bir Proxy programlamaktan pek fark yok. Aklma ilk aamada gelen dikkat edilmesi gereken noktalar yle oldu;

Byk dosya indirirken istemcinin hala bal olup olmadn Response.IsClientConnected ile kontrol etmek gerekir. Byk dosya indirme ilemlerinde bufferlamak ve ksm ksm indirerek istemciye gndermek daha mantkl olabilir. zellikle video dosyalarnda. Kesinlikle bu dosyaya request yollayann headern kontrol etmek lazm. Kt niyetli biri bu proxy'yi sadece sunucunun bant geniliini harcamak iin kullanabilir veya gereksiz yere sunucuyu yorabilir.

Hepinize kolay gelsin.


DaronYNDEM

10

Dinamik Assembly retimi (Kodla Dinamik DLL Compile Etmek) Bir uygulama dnn kendini programlayabilen. Konumuz Star Trek veya Gelecee Dn deil. Emin olun gerek dnyadan ve yaplabileceklerden bahsediyorum. Uygulamalarnzn d sistemlerle ciddi bir balant ierisinde olduu durumlarda bazen kendi ilerinde d sistemlere uygun kodlar reterek kullanmalar gerekebilir. Bunu bazen uygulamalarn kendi ilerindeki yapay zeka ile yapabilecekleri gibi bazen ise baka bir d kaynaktan aldklar yeni parametrelerden yola karak kendi kodlarnda deiiklik yapabilirler. Eer bunlarn hibiri size gereki gelmiyorsa baka bir seenek olarak da harici uygulamalarn kullanabilecei DLL dosyalar yaratacak bir uygulama yazmak istediinizde yapmanz gerekenlerden bahsedebiliriz. Aslnda her ikisi de ayn kapya kyor. Bize dinamik olarak uygulamalar tarafndan kullanlabilecek DLL dosyalar yaratacak bir kod lazm. Kullanacamz nesnelerin ounun bulunduu esas namespace System.CodeDom.Compiler olacak. Bunun haricinde C# veya VB iin ayr ayr uygun namespaceleri kullanmamz gerek. Eer VB kodu derleyecekseniz VB snflarn C# kodu derleyecekseniz tabi ki C# snflarn kullanmalsnz. apraz ilem yaparak C# kodunuz ile VB kodundan DLL retme ansnz da var. Biz rneklerimizde C# ile C#dan derleme, VB kodu ile de VBden derleme yapacaz. [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 balangcnda ilk olarak birer CodeProvider nesnesi yaratyoruz. Elimizdeki hazr kodu derleyecek olan nesneler olarak bu snflar VB ve C# iin farkllayor. CodeProviderlar zerinden birer de derleyici nesnesi aldktan sonra sra geliyor derleyeceimiz kodun referanslarna karar vermeye. Referanslar DLL isimleri ile bir String dizisine aktarmanz art. Windows uygulamalarnda en azndan System.dllin web uygulamalarnda da System.Web.dllin referans alnm olmas gerekiyor. Son olarak reteceimiz DLL dosyasnn adn da baka bir deikene aktararak yolumuza devam edelim. [VB] Dim DerlemeParametreleri As New System.CodeDom.Compiler.CompilerParameters(Referanslarim, AssemblyAdi)

11

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 ilemini yaparken yapmamz gereken ayarlar var. Bu ayarlar derleyicimize bir CompilerParameters nesnesi olarak aktaracaz. DerlemeParametreleri deikenimizi yaratrken referanslarmz ve DLL adn aktardktan sonra zel olarak GenerateExecutable zelliini false olarak ayarlyoruz. Bylece derleyicimiz bize tek bana alabilir bir dosya yaratmaktansa bir DLL dosyas yaratacak. Bir sonraki admda da GenerateInMemory zelliini false yaparak yaratlacak dosyann uygulamamz ile ayn konuma, diske yazdrlmasn salyoruz. Aksi halde yaratlan Assembly sadece hafzada tutulacak ve diske yazlmayacaktr. Sra geldi dinamik olarak derlemeyeceimiz kodu bir deikene aktarmaya. [VB] Dim Kodum As String = <Kod>Public Class Deneme Function Metin() As String Return "alyor" 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# arasnda farkl ilemler yaptm. VBde dorudan yaratacam kodu uygulamann ierisine gmerken C#da derleyeceim C# kodunu harici bir Class1.cs dosyasndan ektim. Siz kendi uygulamalarnzda ister bu kodlar farkl dosyalardan ekin ister metin ilemleri ile dinamik kod yaratn. htiyalarnza gre uygun zm retmek tamamen size kalm. nemli olan tek nokta aslnda bu kodlarda hibir hatann olmamas gerektii, aksi halde derleme ilemi yaplamayacaktr. [VB] Dim Sonuc As System.CodeDom.Compiler.CompilerResults = KodUretici.CompileAssemblyFromSource(DerlemeParametreleri, Kodum) [C#] System.CodeDom.Compiler.CompilerResults Sonuc = KodUretici.CompileAssemblyFromSource(DerlemeParametreleri, Kodum);

12

Tm ayarlarmz tamamlandnda gre dorudan CodeProvider nesnemizin CompileAssemblyFromSource metodunu kullanarak derleme ilemini balatabiliriz. Tabi bu esnada daha nce hazrlam olduumuz DerlemeParametrelerini de metoda parametre olarak aktaryoruz. Derleme ilemimizi batan sona tamamlayan kodumuzu bir btn 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 "alyor" 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);

13

Dinamik olarak DLL dosyas derlemek ite bu kadar kolay. Dinamik kod yaratma aralar son dnemde ok popler. Veritabanna balanarak veritabanndaki nesneleri alglayp uygun Veri Katman kodunu dinamik olarak oluturan hazr uygulamalar olduu gibi baz durumlarda zel kodlar yazmak da gerekebiliyor. Byle bir durumda artk siz de uygulamalarnza farkl kaynaklardaki artlara uygun kodu dinamik olarak retebilir ve bir DLL olarak farkl uygulamalara aktarabileceiniz gibi kendi uygulamalarnzda da kullanabilirsiniz. Yarattnz DLL dosyasn hemen uygulamanzda kullanmak isterseniz bu sefer dinamik olarak Assembly kullanmn ve Reflection konusuna eilmenizde fayda var. Hepinize kolay gelsin.
DaronYNDEM

14

Java ve Silverlight kardelii. Silverlight'n sunucu tarafndaki programlama dillerinden ve sunucu platformundan tamamen bamsz olduundan srekli bahsediyoruz. Bu erevede daha nceki yazlarmdan birince PHP ile Silverlight 2.0 kullanmna deinmitim. Bu yazmzda da Java ile Silverlight kullanmna deineceiz. rneimizde Java tarafndan hazrladmz bir web servisini Silverlight 2.0 tarafnda Visual Studio ierisinden kullanacaz. Visual Studio ve .NET altyaps ile rahatlkla WSDL uyumlu web servislerini kullanabildiimizi dnrsek ayn standartlara uygun bir web servisinin Java ile hazrlanm olmas durumunda herhangi bir sorun yaamayacamza kesin gz ile bakabiliriz. lk olarak Java tarafnda aadaki kodumuz ile basit bir web servisi hazrlayalm. package com.daron.ws; public class wsclass { public int topla(int x, int y) { return x+y; } } Yukardaki ufak kod ile aslnda basit bir metod tanmlam oluyoruz. Metodumuz ald iki integer parametreyi toplayp geri dndryor. Bu parametreler ve metodun yapaca ilemler sizin rneklerinizde ok daha farkl olabilir. u an iin amacmz Silverlight tarafndan Java'ya veri gnderip geriye sonu alabiliyor olmak. Eclipse zerinden WSDL dosyasn da otomatik olarak yukardaki metod zerinden yarattktan sonra artk sra geliyor bu servisi Silverlight tarafnda kullanmaya. Silverlight 2.0 uygulamamz yine Visual Studio ierisinde gelitireceimiz iin Java servisinin bulunduu siteyi Visual Studio ierisinde de amanz daha rahat bir alma ortam yaratacaktr. Basit bir ekilde Visual Studio 2008 ierisinden "File / Open Web Site" diyerek Java ile hazrlanm siteyi aabilirsiniz. Tabi Java dosyalarn sadece birer dosya olarak greceksiniz, dzenleme ansnz olmayacak. Siteyi atktan sonra "File / Add / New Project" diyerek Silverlight projenizi sitenize ekleyebilirsiniz. Silverlight uygulamasn altracak olan rnek HTML dosyas otomatik olarak Java sitenize eklenecektir. Web servisini referans alalm... Web servisini referans olarak ekleyebilmeniz iin tabi ki servisin alyor olmas gerek. Bunun iin Eclipse zerinden Tomcat'i kullanabilirsiniz. IIS ykl bir makinede alyorsanz 8080 gibi harici bir port vermeyi unutmayn. Web servisini taraycnzda altrdktan sonra adresini kopyalayarak Silverlight projenize sa tklayarak "Add Service Reference" diyerek referans ekleme ilemini tamamlayabilirsiniz.

15

Java web servisimizi referans olarak ekliyoruz. Referans ekleme ilemi tamamlandnda artk Silverlight ile herhangi bir web servisini kullanr gibi Java web servisimizi de kullanabiliyoruz. rneimizi altrabilmek iin ilk olarak Silverlight ekranmza iki metin kutusu ve bir de dme yerletirelim. <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>

16

Her ey hazr olduuna gre artk web servislerimizi kodumuz ile tanmlayp 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>(Servis im_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) {

17

Dugme.Content = e.Result.ToString(); } } } Konumuz Silverlight ile web servisleri kullanm olmad iin yukardaki kodun detaylarna girmeyeceim. Bu konuda detayl bir yazy aadaki adresten inceleyebilirsiniz. http://daron.yondem.com/tr/PermaLink.aspx?guid=19fe09b2-2987-4369-a5d5-58e0641c8d6b Kodlar incelediimizde yaptmz eyin aslnda ASP.NET ile hazrlanm bir web servisi kullanmaktan farkl olmadn gryoruz. Java ile yazlm olan web servisimiz yine Silverlight tarafndan asenkron olarak kullanlabiliyor. Projenizi Visual Studio ierisinde Build ederek Silverlight XAP dosyasn oluturduktan sonra siteyi Tomcat zerinden altrmak zorunda olduunuzu unutmayn. Aksi halde web servisi almayaca iin Silverlight hata verecektir. Sonu Silverlight'n gzelliklerinden faydalanmak iin ASP.NET tarafnda olmanz art deil. ster Java ister PHP ister herhangi bir sunucu tarafl programlama dili kullann Silverlight ile kullanc arayznz hazrlayabilirsiniz. Java ile WSDL uyumlu web servisi hazrlayp altrabilme :) konusundaki yardmlarndan dolay sevgili Bilge Baaltun'a buradan ok teekkr ediyorum. Hepinize kolay gelsin.
DaronYNDEM

18

Kendi Silverlight Ykle mesajnz gstermeniz iin ipular Silverlight kullanlan web sitelerin art ile aslnda kullanclara da Silverlight ykletme konusunda srar giderek artyor :) Bu konunun bir srar olmamas ve kullanclarn gnl rahatl ile Silverlight Runtime'n ykleyebilmeleri iin aslnda ykleme srecinin ncesindeki kullanc deneyimi ok nemli. Eer istemcide Silverlight ykl deil ise sizin OBJECT taglar ile sayfaya yerletirdiiniz uygulama gsterilmeyecektir. Bunun yerine OBJECT taglar arasndaki HTML kodu kullancya gsterilir. Visual Studio ve Expression Blend ile yeni bir proje yarattnzda sz konusu HTML kodu varsaylan ekli ile aadaki 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> Yukardaki OBJECT taglar arasnda renkli olarak grdmz ksm sadece Silverlight ykl olmadnda gsterilecektir. Bu ksma istediiniz HTML kodunu koyabilirsiniz. Buradaki standart link Silverlight'n Microsoft sitesinde ykleme sayfasna ynlendirirken dieri de standart "Install Silverlight" grselini gsterir.

Standart Silverlight Ykleme mesaj. Kendi zel "Silverlight Ykle" grselinizi ve mesajnz hazrlarken kullanclar korkutup karmamak adna sizlere birka tavsiyem olacak.

nsanlara "Silverlight Ykle" derken neden yklemelerini istediinizi belirtin. Kullanclarn yklemeden nce de sitenizin nasl bir ey olduunu grmeleri salayn, merak uyandrn. zetle Silverlight yklerlerse nasl bir eyle karlaacaklarn grsnler ki yklemeye daha scak baksnlar.

Aada bulabileceiniz rnekte Silverlight ile alan bir sitenin Silverlight ykl olmadnda da nasl gsterildiini inceleyebilirsiniz. Standart "Install Silverlight" grseli yerine byle bir deneyim ok daha ekici olacaktr.

19

rnek Silverlight Ykleme Ekran Hepinize kolay gelsin.


DaronYNDEM

20

NET iin De-Compile ilemleri ve Obfuscation ster VB olsun ister C#, ister web ister Windows uygulamas olsun yazdmz tm kodlarn derlenerek (Compile) bir EXE veya DLL haline dntrldn biliyoruz. Aslnda .NET ierisinde yaplan ilem sizin yazdnz herhangi bir .NET dilindeki kodun MSIL (Microsoft Intermediate Language)a evrilmesidir. te tam bu noktada akla gelen ilk soru; acaba bu eviri ileminin tersini yapmak mmkn m? Yani elimizdeki DLL veya EXE dosyasndan yola karak VB veya C# kodumuzu geri alabilir miyiz? Cevap: Evet. u andan itibaren yapacaklarmz hedef olarak kullanacanz uygulamann lisans szlemesine gre yeri geldiinde su tekil edebilir. O nedenle sizi zellikle uyarmak istiyorum. ou zaman De-Compile ilemleri yaparkenki amacmz yazdmz kodun nasl derleyici tarafnda MSILe evrildiini incelemek veya kaynak kodunu kaybettiimiz ve bize ait olan bir uygulamann kodlarna ulamak olacaktr. Dier yandan lisans szlemesi ile aykr dmedii srece farkl uygulamalar da De-Compile ederek arka planda farkl ilemlerin nasl yapldn inceleme ansnz da olabilir. .NET tarafna getiimizde herhangi bir DLL veya EXEnin aslnda MSIL kodlar ierdiinden bahsetmitik. Tabi ki bu MSIL kodlar dorudan bilgisayarlar tarafndan altrlabilir kodlar deiller. O nedenle ierisinde MSIL bulunan bir .NET yapsnn alabilmesi iin hedef makinede .NET Frameworkn ykl olmas gerekiyor. .NET Framework ierisindeki CLR (Common Language Runtime) bizim MSIL kodumuzu makine diline evirerek almasn salayacaktr. Kabaca baktmzda De-Compile yolunda bizim ilk olarak elimizdeki DLL veya EXE ierisinden MSIL kodunu alarak karmamz gerekecek. Bunun iin dorudan .NET Framework SDK paketi ile beraber gelen MSIL DisAssembler (ILDASM) uygulamasn kullanabiliriz. IL DASM Kullanm Bilgisayarnza .NET Framework SDK paketini kurduktan sonra dorudan Balat mensnden ulaabileceiniz ILDASM programn Visual Studio ykleme konumu ierisinde SDK klasr altnda da bulabilirsiniz. Program atktan sonra File / Open mensnden istediiniz bir .NET DLL veya EXE dosyasn ama ansnz olacaktr.Deneme amal olarak gelin mini bir Windows uygulamas yazalm ve ILDASM ile aarak alacamz sonucu grelim. Uygulamamz ierisinde birer TextBox, Button ve Label bulunacak. Basit bir ekilde dmeye basldnda TextBox ierisindeki deeri Label ierisine aktaracaz. [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 {

21

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { label1.Text = textBox1.Text; } } } Yukarda yazdmz kodlar ile oluturduumuz uygulamay ILDASM ile aarak sonucu inceleyelim. Uygulamann ilk alan penceresinde bizim EXEye ait tm snflar ve namespaceler gzkyor olacaktr. Eer herhangi bir nesnenin tanm veya metodu ile ilgili MSIL kodunu grmek isterseniz dorudan ift tklayarak yeni bir pencerede kodlarn almasn salayabilirsiniz.

ILDASM ierisinde EXEmizin MSIL kodlar aka gzkyor Hazrladmz rnek uygulamann Button_Click durumundaki MSIL kodunu bulduumuzda aadaki sonu ile karlayoruz. [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

22

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 Yukardaki MSIL kodu normal artlarda CLR tarafndan makine koduna evrilerek hedef ortamda altrlyor. Artk MSIL kodumuzu aldmza gre bu kodu VB veya C# koduna evirmemiz lazm. Tabi bu i o kadar kolay deil ve tek tek elle yaplabilecek bir i de deil. O nedenle bu sefer de farkl bir ara kullanacaz. Reflector i banda Lutz Roeder tarafndan yazlm bir program olarak Reflector http://www.redgate.com/products/reflector/ adresinden bilgisayarnza indirebilirsiniz. Program aslnda bir nceki admda anlattm MSIL zme ilemini de kendi iinde yapabiliyor. Bununla kalmayp zd MSIL kodunu istediiniz .NET diline de evirebiliyor. Program altrdktan sonra File / Open mensnden istediiniz bir EXE veya DLL dosyasn seebilirsiniz. Uygulamann ana penceresindeki snf listesine hemen setiiniz program da gelecektir.

Reflector ile kaynak kodunu grebiliyoruz. Ufak bir gezinti ile istediiniz snfn veya metodun koduna dorudan ulaabilirsiniz. Reflector arayzndeki Programlama Dili seeneinde VB, C#, Delphi ve IL seenekleri bulunuyor. Bir nceki blmde hazrladmz uygulamamz aarak Button.Click durumundaki kodu farkl dillerde Reflector ile alp inceleyelim. [VB] Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Me.Label1.Text = Me.TextBox1.Text End Sub

23

[C#] private void Button1_Click(object sender, EventArgs e) { this.Label1.Text = this.TextBox1.Text; } Yazdmz kodlar ile Reflectorn bize verdii kodlar tam olarak ayn deil. Bu durum zaten ok normal. nk MSIL koduna eviri esnasnda aslnda ou ey deiiyor. rnein tanmladmz deikenlerin bize zel olan isimlendirmeleri yok oluyor veya bizim kullandmz baz ksa metotlar uzun ekilleri ile yazlabiliyor. Hatta zellikle VB ierisindeki casting kolaylklar Compile esnasnda farkl deiikliklere neden olabiliyor. Bu durumda De-Compile ile aldmz kod da yazdmz koddan biraz farkl oluyor. Yine de elimizde alr durumda bir kod olduuna kesin gz ile bakabiliriz. Nasl engelleriz? Obfuscation! Herhalde ounuz tm kodlarmz gzler nnde endiesi ierisindesiniz. Aslnda durum gerekten de yle. Tabi bu durumun birok faydas var. Kiisel olarak itiraf etmek gerekirse farkl yazlmlar De-Compile ederek ok ey rendiimi syleyebilirim. Bir defasnda da kendi rettiimiz bir yazlm De-Compile etmemiz gerekmiti, gerekten hayat kurtarmt. Peki bunu nasl engelleyebiliriz? lk olarak unu aka belirtiyim, herhangi bir .NET uygulamasndan MSIL kodunun alnmasn engellemenin hibir yolu yok. Yapabileceimiz tek ey MSIL kodunun okunabilirliliini azaltmak iin ilevsel olarak ayn ii gren fakat daha kark bir MSIL kodu yaratmak. Bu ilem obfuscation olarak adlandrlyor. Obfuscation ile ilgili sektrde ok sayda cretli yazlm bulabilirsiniz. Biz bunlardan Xenocode'aait Postbuild 2008 adndaki ticari yazlm kullanarak obfuscation ile neler yapabildiimize bakacaz. XenoCodeu ilk atmzda karmza hemen bir uygulama listesi geliyor. Bu listeye bir nceki admda kendi hazrladmz EXE dosyasn ekleyerek uygulamann st mensnden Protect tabna geiyoruz. Burada sadece Windowsda alacak EXE dosyalarna uygulanabilecek zel bir koruma yntemi olan Surpress ILDASM seeneinin iaretini kaldrmamz gerek. Bu seenek DLLlere zaten uygulanamayacaktr. Ekrann sa tarafnda korumak istediimiz snflarn ve metodlarn bir listesini iaretleyebiliyoruz. Tm ayarlar tamamladktan sonra uygulamann sa altndaki XenoCode Application dmesine basyoruz.

24

Obfuscation ilemi iin yollardayz Obfuscation ilemini tamamladktan sonra sra geldi testlerimizi yapmaya. lk olarak uygulamamz ILDASM ile aarak bakalm 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

25

Grdnz gibi aslnda ok byk bir deiiklik yok. Sadece snflarn ve metodlarn isimleri deitirilerek kark isimler verilmi. Ayn uygulamay Reflector ile atmzda ise aadaki 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 okunurluluunu kaybetmi durumda. Bizim rneimizde sadece tek bir satr kod bulunduu iin neyin ne olduunu anlamak ok zor olmuyor. Fakat binlerde satrdan oluan uygulamalarn kodlarndan anlalabilir bir sonu karmak neredeyse imknsz olacaktr. Hepinize kolay gelsin.
DaronYNDEM

26

Reflection nedir? Balk olarak Reflection yazdktan sonra ardna sayfalarca aklama ve rnek konulabilir. Hatta bu konuda ayr bir kitap bile yazlabilir. Reflectionn ok farkl kullanmlar var. zetleyerek hzl bir ekilde tanmlamak istersek aslnda Reflection bize hakknda bilgi sahibi olmadnz programatik nesnelerle ilgili alma zamannda (run-time) bilgi alabilmemize olanak tanyan bir metottur. Peki byle bir eye neden ihtiyacmz olsun? En basit rnek gerek zamanl olarak uygulamalara farkl DLL dosyalarnn baland durumlar gsterebiliriz. Byle bir durumda kaynak konumdaki snflar veya metotlar ile ilgili herhangi bir bilgi bulunmaz. Sz konusu bu bilgilerin program alrken elde edilerek kullanlmas gerekir. Gelin ilk olarak Reflectionn yapsn ve sistemini tanmak adna tek bir uygulama ierisinde nasl kullanlabileceimize gz atalm. rnek uygulamamzda aadaki ekli ile tanmlanm bir Urun snf kullanacaz. [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 "rnn ad: " & Me.Adi End Function End Class [C#] public class Urun { private string PAdi; public string Adi { get { return PAdi; }

27

set { PAdi = value; } } public Urun() { } public Urun(string adi) { this.Adi = adi; } public string Uyari() { return "rnn ad: " + this.Adi; } } Uygulamamz ierisinde iki adet dme yer alacak ve kullanacamz Windows penceresinde global olarak tanmlanm bir de Object tipinde deikenimiz bulunacak. [VB] Dim BirUrun As Object [C#] object BirUrun; Uygulama ierisindeki dmelerden birine basldnda global BirUrun deikenimiz yeni bir Urun deikenine dntrlecek. [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(); } Programmz ierisinde dier dmeye basldnda BirUrun adndaki deikenimizin Adi zelliini deitirerek Uyari adndaki metodunu kullanmak istiyoruz. Fakat Visual Studio ierisinde maalesef ki BirUrun adndaki deikenle beraber Urun tipine ait Intellisense

28

destei gelmeyecektir. Aslnda bu durumun hakl bir nedeni var. kinci dmeye basldnda BirUrun adndaki deikenin tipininin Object mi yoksa Urun m olaca belli deil. te tam da istediimiz ortam yaratm olduk. Kullanacamz nesnenin tipi belirsiz ve biz ona ait baz zellikleri kullanmak istiyoruz. Bu durumda ilk olarak ikinci dmeye basldnda gerekten BirUrun deikeninin tipi Urun m yoksa deil mi sorusunu kontrol etmemiz lazm. [VB] If TypeOf (BirUrun) Is Urun Then End If [C#] if ((BirUrun) is Urun) { } Buraya kadar her ey ok kolay. Bundan sonra eer IF kontrollerimize olumlu sonu dnyorsa ilk olarak gidip nesnenin Adi zelliini bulmamz ve ona bir deer aktarmamz gerekiyor. [VB] BirUrun.GetType.GetProperty("Adi").SetValue(BirUrun, "Daron", Nothing) [C#] BirUrun.GetType().GetProperty("Adi").SetValue(BirUrun, "Daron", null); Yukardaki kod ile elimizdeki nesnenin tipini bilmeden onun Adi adndaki zelliini (property) yakalayarak deerini Daron olarak deitiriyoruz. Kodumuzu detayl olarak adm adm bakacak olursak ilk aamada nesnenin tipini GetType ile alyoruz. Sonrasnda ise tipini yakaladmz nesnenin GetProperty ile Adi adndaki zelliini alarak SetValue ile sz konusu zelliin deerini deitiriyoruz. SetValue metodu toplam parametre alyor; bunlardan ilki deer deiiklii yaplacak nesnenin kendisi, ikincisi yeni atanacak olan deer, ncs ise eer deitirilecek olan zellik (property) indeksli ise sz konusu indeks deeri. Bizim rneimizde indeksli bir zellik olmad iin bu parametreyi bo geiyoruz. Deer atamamz tamamladmza gre bu sefer de sra geldi BirUrun deikenimize ait Uyari metodunu altrmaya. Metodumuz bize bir String dndrecek biz de onu dorudan bir mesaj kutusu ile kullancya gstereceiz. [VB] BirUrun.GetType.InvokeMember("Uyari", Reflection.BindingFlags.InvokeMethod, Nothing, BirUrun, Nothing) [C#]

29

BirUrun.GetType().InvokeMember("Uyari", System.Reflection.BindingFlags.InvokeMethod, null, BirUrun, null).ToString(); Reflection kullanarak tr bilinmeyen bir nesnenin bir metodunu altrmak iin InvokeMember metodundan faydalanmamz gerekiyor. InvokeMember aslnda ok geni kullanm olan bir metod, biz imdilik sadece bir eit kullanmna deineceiz. rneimizde InvokeMember bir metod altraca iin ilk parametresinde altrlacak olan metodun adn ikincisinde BindingFlags.InvokeMethod ile bir Metod altrlacan belirtiyoruz. nc parametre bizim imdilik kullanm alanmz dnda kalan Bindinglerle ilgili, ayn ekilde beinci parametre de bo braklarak geilecek. Drdnc parametrede ise hedef nesnemiz olan BirUrun deikenimizi atayacaz. Bylece metodumuzu da altrm olduk. Dinamik DLL Kullanm Kabaca Reflectionn nasl kullanlabildiine dair bir rnek yaptktan sonra artk sra geldi harici bir DLL dosyasnn alma annda programmza ekleyerek ierisindeki yaplar kullanmaya. Bu eit bir ilevsellii zellikle gerek zamanl DLL derlemesi ile birletirdiinizde ok farkl bir dnyaya kap am olacaksnz. Hedef olarak kullanacamz DLL dosyasn aadaki kodlardan yaratacaz. [VB] Public Class Deneme Function Metin() As String Return "alyor" End Function End Class [C#] public class Deneme { string Metin() { return "alyor"; } Yarattmz DLL dosyasn uygulamamz ile ayn konuma yerletirdikten sonra aadaki kod ile DLLimizi kullanmaya balayabiliyoruz. [VB] Dim BirAssembly As Reflection.Assembly = Reflection.Assembly.LoadFrom("ornek2.dll") [C#] System.Reflection.Assembly BirAssembly = System.Reflection.Assembly.LoadFrom("ornek2.dll");

30

Artk yukarda tanmladmz Assembly zerinden Reflection kullanarak ilerleyebiliriz. lk olarak Deneme adnda snfmzdan bir instance almamz gerekecek. Bunun iin Deneme tipini bulmamz lazm. [VB / C#] BirAssembly.GetModule("Ornek2.dll").GetType("Deneme") Assembly zerinden modlmz yakalyor sonra da Deneme adndaki tipinizi buluyoruz. Tabi tipi bulmak yeterli deil, sz konusu tipte bir deiken yaratmamz gerekiyor. Activator snfn kullanarak bu tip zerinden bir instance yaratarak Sinif adnda bir deikene aktaracaz. [VB] Dim Sinif = Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme")) [C#] object Sinif = Activator.CreateInstance(BirAssembly.GetModule("Ornek2.dll").GetType("Deneme")) ; Yarattmz snfn maalesef zellikleri otomatik olarak gelmeyecek. O nedenle Metin adndaki metodumuzu da elle bularak altrmak zorundayz. [VB] BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invo ke(Sinif, Nothing) [C#] BirAssembly.GetModule("Ornek2.dll").GetType("Deneme").GetMethod("Metin").Invo ke(Sinif, null) Yine Assembly zerinden yola karak bu sefer daha da ileri gidiyoruz. Deneme snfmz bulduktan sonra ierisinde Metin adndaki metodumuzu buluyor ve dorudan Invoke ile sz konusu metodu altryoruz. Invoke metodu bizden iki parametre istiyor; bunlardan ilki ana snfn kendisi. Bir nceki admda yakaladmz snf buraya parametre olarak aktaryoruz. Dieri ise bizim kullanmayacamz Binding parametresi. Metin metodumuz altrldnda geriye bir String deikeni dndryor. Bu deikeni de bir mesaj kutusu ile kullancya gstermek istersek uygulamamzn tam kodunun aadaki ekilde sonlanmas gerekiyor. [VB]

31

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("Me tin").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()); } } } Bylece harici bir DLL dosyasn ykleyerek istediimiz metodu dinamik olarak kullanabildik. Farkl durumlarda isterseniz bir DLL ierisinde tm metod, snf 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#]

32

var Metodlar = from Gelenler in BirAssembly.GetModule("Ornek2.dll").GetTypes() where Gelenler.GetMethod("Metin") != null select Gelenler; rnein yukardaki LINQ sorgumuz ile harici DLL dosyas ierisinde Metin adnda metodu olan tm snflarn bir listesini alyoruz. Hepinize kolay gelsin.
DaronYNDEM

33

Silverlgiht 2.0 ve WCF Servisleri .NET Framework 3.0 ile beraber karmza kan WCF servisleri aslnda oktan klasik web servislerinin yerini de alm durumda. Tabi ki dorudan bir karlatrma yapmak ok yanl olacaktr, WCF ok daha geni kapsaml bir erevede deerlendirilmeli. Silverlight 2.0 tarafna baktmzda ise istemci ile sunucu arasndaki veri trafiini klasik ASMX web servislerine balayabileceimiz gibi istersek dorudan WCF servislerini de kullanabiliyoruz. Bu yazda Silverlight 2.0 Beta 1 ile WCF servislerininin kullanmna deineceiz. WCF servisimizi hazrlayalm. Visual Studio 2008 ierisinde yarattmz yeni Silverlight projemize elik eden Web Project ierisinde yeni bir WCF servisi yaratyoruz. rneimizde Silverlight tarafndan gnderilen iki sayfa WCF servisi tarafndan alnarak sunucu tarafndan toplanacak ve geri dndrlecek. Bu erevede uygun bir WCF servisini hazrlarken aadaki kodlar yazmamz 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 hazr olduuna gre Silverlight tarafna gei yapabiliriz diye dnyorsunuz kesinlikle aldanyorsunuz. Varsaylan ayarlar ile Visual Studio ierisinde herhangi bir WCF servisi yarattlnda wsHttpBinding kullanlr oysa bizim Silverlight tarafnda basicHttpBinding'e ihtiyacmz var. O nedenle hemen projemizin Web.Config dosyasna ufak bir yolculuk yaparak aadaki ekilde ayarlarda deiiklik yapmamz gerekiyor. <services> <service behaviorConfiguration="ServiceBehavior" name="Service"> <endpoint address="" binding="basicHttpBinding" contract="IService">

34

<identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> Artk tm ayarlarmz tamamlad. Silverlight 2.0 tarafna rahatlkla geebiliriz. Silverlight 2.0 ve WCF balants WCF servisimiz ile Silverlight uygulamamzn ayn domain ierisinde olmas art. Gvenlik kurallar nedeniyle "cross-domain" yani alan adlar aras veri trafii oluturma ansmz yok. Visual Studio ierisinde Silverlight projenize sa tklayarak gelen menden "Add Service Reference" dmesine basarak proje ierisinde WCF servisini Silverlight uygulamasna referans olarak ekleyebilirsiniz. lk olarak gelin uygulamamzn XAML koduna bir gz atalm. <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 tarafna geerek bir nceki admda referans olarak projemize eklediimiz WCF servisini kullanmaya balayalm. WithEvents Servis As New WCFServisim.ServiceClient Yukardaki ekli ile servisimizi uygulama ierisinde global olarak tanmlyoruz. WCF servisimi bu ekilde tanmlamamn aslnda nemli bir nedeni var. Birazdan WCF servisi ile istemci tarafndan suncuya bir veri talebi gnderdiimizde, yani toplanacak olan saylar gnderip toplam istediimizde aslnda asenkron bir talepte bulunmu olacaz. Klasik Windows uygulamalarndan altmz yapdan farkl olarak Silverlight 2.0 ierisinde WCF servislerinin kullanm tamamen asenkron olarak gerekleiyor. Durum byle olunca asenkron bir istek sonrasnda sunucudan cevap (veri) geldiinde bizim kodumuzun da durumdan haberdar edilmesi gerekecek. Sz konusu haber yine WCF servisimize zel olan bir baka event-handler'n altrlmas ise bize ulatrlacak. Aslnda dinamik olarak servisimizi

35

yaratrken event-handler da balayabilirdik. Ama Visual Basic ile yukardaki gibi bir kullanm ok daha rahat oluyor. C# programclar dinamik event-handler balamay kullanabilirler. Global deikenimizde WCF servisimiz hazr olduuna gre artk dmemize bazldnda sz konusu servisi rahatlkla 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 Grdnz gibi Servis deikenim zerinden ToplamaAsync metodunu aryorum. Metodu altrdktan sonra sunucudan veri geldiinde bu metoda zel olan ToplamaCompleted event' altrlacak. 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 baktmzda ToplamaCompletedEventArgs ile karlayoruz. Bu tamamen bizim metodumuza zel bir deiken tipi. Buradan yola karak e.Result dediimizde ise dorudan bizim WCF metodumuzun dndrd nesneyi yakalayabiliyoruz. rneimizde gelen sonucu uygulama ierisinde bir TextBlock iine yazdryoruz. Kodumuzun tamamna baktmzda aadaki manzara ile karlayoruz. 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?

36

Visual Basic'e zel yaplar kullandm iin ayn kodun C# muadilini de sizlerle paylamak istiyorum. Bylece C# programclar iin anlalmas ok daha kolay olacaktr. 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.
DaronYNDEM

37

Silverlight 2.0 Beta 1 ierisinde DataGrid kullanm! Silverlight 2.0 Beta 1 ile beraber gelen ilgin kontrollerden biri de DataGrid kontroldr. Aslnda kontroln kendisinde herhangi bir ilginlik yok, ilgin olan WPF'in ilk srmlerinde byle bir kontrol yokken Silverlight'n ikinci srmnde DataGrid'in geliyor olmas. Bu yazmzda Silverlight 2.0 Beta 1 ile DataGrid kullanmna deyineceiz. Silverlight 2.0 projenizi Visual Studio 2008 ile yarattktan sonra hemen ara ubuunda DataGrid kontrol ile karlaabilirsiniz. Expression Blend ierisinde ise varsaylan ayarlar ile gelmeyecektir. Bunun aslnda basit bir nedeni var; DataGrid gibi veri kontrolleri Silverlight 2.0 iin harici bir Control Library olan System.Windows.Controls.Data altnda geliyor ve bu ktphane normal artlarda uygulamalar referans olarak eklenmi olmuyor. Eer uygulamanza bu snf referans olarak eklerseniz Blend ierisinde de gerekli seenekler gelecektir. Visual Studio ierisinde sahneye bir DataGrid yerletirdiinizde gerekli referanslar otomatik olarak ekleniyor. <UserControl xmlns:my="clrnamespace: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> Yukardaki kodu incelediinizde herhangi bir Silverlight uygulamasna DataGrid yerletirildiinde en st satrdaki XML namespace tanmn grebilirsiniz. Sz konusu tanm veri kontrollerinin Assembly'lerine bal. Bylece artk uygulamamzda veri kontrollerini kullanabiliriz. Bunun bir sonucu olarak artk uygulamamzdan retilecek XAP paketinde de System.Windows.Controls.Data.dll dosyas bulunacaktr. lk olarak istemci tarafndaki kodumuz ile DataGrid ierisinde gsterilmek zere bir veri yn yaratalm. Bu noktada siz uygulamalarnzda rahatlkla farkl web servislerinden ektiiniz 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

38

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) {

39

this.Adi = adi; this.Stok = stok; } } Yukardaki snf yapsn verimizi olutururken kullanacamz nesneler olarak hazrladk. Silverlight 2.0'daki DataBinding WPF ile byk bir benzerlie sahip. zellikle LINQ ile beraber kullanldnda nesneleri kontrollere bind edebiliyor olmak byk avantaj salyor. imdi gelelim bize geici 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 ierisinde de grdnz gibi elimizdeki veriyi dorudan BirGrid adndaki DataGridimizin ItemsSource zelliine balyoruz. Bylece DataBinding ilemi tamamlanm oldu. Fakat baladmz bu verinin Grid ierisinde kolonlara yerlemesi iin tabi bizim "kolon"lara ihtiyacmz var. Otomatik olarak veriye uygun kolon yaratlabilmesi iin DataGrid'in AutoGenerateColumns zelliinin True olarak ayarlanm olmas gerekiyor. <UserControl xmlns:my="clrnamespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverlightApplication25.Page" xmlns="http://schemas.microsoft.com/client/2007"

40

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 yukardaki gibi olmal. Bylece uygulamamz altrdmzda aadaki manzara ile karlaabiliriz.

Silverlight 2.0 ierisinde DataGrid grnts. sterseniz alternatif satrlarn fon renklerini hatta kolonlar aras izgilerin renklerini bile tek tek belirleyebilirsiniz. Aadaki kod yapabileceiniz renk deiikliklerine dair bir ipucu olabilir. <UserControl xmlns:my="clrnamespace: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>

41

</UserControl> Kendi kolonlarmz tanmlayalm! Aslnda AutoGenerateColumns zellii bizim ASP.NET'teki GridView'den de alk olduumuz bir zellik. Kolay bir kullanm salasa da ou zaman bu zellik istediimiz uygulamalar hazrlayabilmemiz iin yeterli deil. O nedenle gelin imdi beraber bir DataGrid ierisinde kolonlar nasl elle ayarlayabileceimizi inceleyelim. Eer AutoGenerateColumns zelliini True yapmazsanz hali hazrda varsaylan ayar zaten False olarak geliyor. O nedenle bir nceki projemize devam edeceimiz iin ilk olarak ya AutoGenerateColumns zelliini XAML kodunuzdan silin ya da False olarak ayarlayn. Bir DataGrid'in eit kolonu olabilir;

DataGridTextBoxColumn DataGridCheckBoxColumn DataGridTemplateColumn

Adlarndan da anlalaca zere ikisi kendi isimlerindeki kontrolleri kolonlara yerletirirken TemplateColumn ise bize daha esnek bir yap salyor. lk olarak gelin TextBoxColumn ve CheckBoxColumn kullanarak bir nceki admdaki rneimizin kolonlarn elle tanmlayalm. <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> Kolonlarmz ekledikten sonra her kolonun Header zelliini deitirerek o kolonda gzkecek olan bal ayarlayabiliyoruz. Son olarak da veri kaynandan hangi Property'nin sz konusu kolonda gzkeceini belirlemek iin bir Binding kullanyoruz. Grsel olarak sonu bir nceki rneimizdeki ile ayn olacak fakat bu sefer kolonlar biz el ile tek tek ayarlam olduk. Bunun getirecei esneklii zellikle TemplateColumn ile ok daha rahat grebiliriz. zel kolonlar : TemplateColumn zel bir kolon tanmlarken yapmamz gereken iki ey var; ilk olarak kolonun normal grntsn tanmlamak, ikincisi ise "edit" modundaki grntsn tanmlamak. Eer ReadOnly zelliklerini deitirmezseniz normal artlarda hem TextBoxColumn hem de CheckBoxColumn zerlerine tklandklarnda ilerindeki verinin deitirilebilmesine olanak

42

tanrlar. Hatta Binding Mode olarak da TwoWay parametresini aktarrsanz arka planda Bind ettiiniz List ierisinde gerekli deiiklikler de otomatik olarak yaplr. imdi biz tm bunlar bir TemplateColumn ile deneyeceiz. Amacmz Stok bilgisi gsteren kolonu biraz deitirerek normalde ierisinde True veya False yazmasn salamak. Yani normal artlarda o kolonda bir CheckBox gzkmeyecek, fakat kullancna kolona ift tklar ve deeri deitirmek isterse karnzda 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> Yukardaki kodu detayl olarak incelemekte fayda var. Yarattmz TemplateColumn'un ierisinde bir CellTemplate, bir de CellEditingTemplate var. Bu kolonun normal artlardaki grnts CellTemplate, dzenleme modundaki grnts ise CellEditingTemplate ierisindeki ablona gre hazrlanacak. CellTemplate ierisinde DataTemplate iinde sadece bir TextBlock koyuyoruz ve sz konusu TextBlock'un da Text zelliini Stok bilgisini bind ediyoruz. Bylece normalde Stok bilgisi String olarak bu TextBlock ierisinde gsterilecek. Gelelim CellEditingTemplate ablonunda; bu ablon ierisinde de bir CheckBox kullanarak sz konusu CheckBox'un IsChecked zelliini Stok Property'sine Bind ederken Mode olarak da TwoWay'i seiyoruz. Bylece bu CheckBox zerinde yaplan deiiklikler elimizdeki List verimize yansyacak, yani kaydedilecek. Uygulamamzn tam XAML kodunu aada inceleyebilirsiniz. <UserControl xmlns:my="clrnamespace: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}" />

43

<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 mdahale edin Bir nceki rnek biraz sama gelmi olabilir. Kolon ierisinde dorudan True veya False yazyor olmak pek ho deil. Stok bilgisinden bahsettiimize gre True veya Flase yerine "Var" veya "Yok" yazdrsak belki ok daha mantkl olabilirdi. Kullanc satra tkladnda ise yine karsna dzenleme modunda bir CheckBox gelecektir. Bu ilemi yapabilmemiz iin bizim CellTemplate ierisindeki TextBlock'un Binding'ine mdahale ederek "Eer True geliyorsa VAR yazdr, gelmiyorsa YOK yazdr" diyebilmemiz gerekiyor. te tam da bu ilemi yapabilmek iin Silverlight 2.0 Beta 1 ierisinde ValueConverter yaplarn 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

44

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 yukardaki ekilde System.Windows.Data.IValueConverter snfn implemente etmemiz gerekiyor. Bu ekilde bir Converter yapsnn her zaman bir Convert ve bir de ConvertBack metodlarnn bulunmas art. Bu metodlar aslnda bizim elimizdeki True veya False olan Boolean deerinin String'e evireceimiz ve Binding iin DataGrid'e gndereceimiz veriyi oluturmamza olanak tanyorlar. Kod ierisinde de duruma gre parametre olarak gelen Boolean deeri String'e veya tam tersine ilemler yapyoruz. Sra geldi bu Converter yapsn XAML kodumuzda kullanarak Binding ilemine dahil etmeye. <UserControl xmlns:my="clrnamespace: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"

45

xmlns:local="clr-namespace:SilverlightApplication25" Width="400" Height="300"> lk olarak yukardaki ekilde XAML ierisinde kullanacamz Assembly'mizi tanmlyoruz. Bylece Converter snfmz rahatlkla kullanabileceiz. Fakat ilemler bu kadarla bitmiyor. Tanmladmz Assembly ierisinde Convertor'mz da alarak sayfada Resource olarak yerletirmemiz art. <UserControl.Resources> <local:StokCevirici x:Key="StokCevirici" /> </UserControl.Resources> Tm bu ilemlerde Visual Studio'nun Intellisense yaps size yardmc olacaktr. Artk XAML tarafnda StokCevirici adn verdiimiz Converter yapmz istediimiz bir Binding iin kullanmaya hazrz. <UserControl xmlns:my="clrnamespace: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>

46

</my:DataGridTemplateColumn.CellEditingTemplate> </my:DataGridTemplateColumn> </my:DataGrid.Columns> </my:DataGrid> </Grid> </UserControl> Uygulamann son halinin tam kodunu yukardaki inceleyebilirsiniz. zellikle yarattmz Converter'n kullanm ekline dikkat etmekte fayda var. Artk TextBlock ierisinde gsterilen veriler sz konusu Converter'dan getikten sonra gsterilecei iin ekranda "Var" veya "Yok" yazlar yer alacak. Oysa kullanc ift tklayarak deeri deitirmek istediinde karsna bir CheckBox kacak ve True veya False olabilecek Boolean deeri deitiriyor olacak. Hepinize kolay gelsin.
DaronYNDEM

47

Silverlight 2.0 Beta 1 ierisinde ToggleButton kullanm Checkbox ve RadioButton kontrolleri neredeyse her projede en az bir defa kullandmz kontroller arasnda yerlerini alrlar. Bu kontroller gibi farkl kontroller oluturarak kullancy bir durumdan haberdar etmek veya kullancnn bir durumu deitirmesini salamak mmkn olabilir. rnein basit bir video oynatcs uygulamasnda "Play" dmesi ile "Pause" dmesini ayn dme ierisinde kullanabilirsiniz. Sz konusu dme kendi iinde deierek her tklandnda "Play" veya "Pause" eklinde zerindeki yazy deitirir ve videonun da durdurulmasn veya oynatlmasn salar. Checkbox veya RadioButton dmeleri gibi bu gibi kontrollere znde "ToggleButton" denir ve Silverlight 2 Beta 1 ierisinde Checkbox ve RadioButton da zaten hali hazrda ad ToggleButton olan bir kontrol yapsndan tretilmitir. Bu yazmzda ToggleButton kontrolnn detaylarna ve kullanmna deineceiz. <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> Yukardaki ekli ile standart bir ToggleButton kontroln ister Blend ister Visual Studio ierisinde uygulamanza yerletirebilirsiniz. Sonrasnda arkaplanda ToggleButton kontrolnn yakalayabileceimiz iki kendine zel event' var; bunlardan ilki Checked, dieri ise Unchecked durumlar. Yarattmz ToggleButton'n grsel zelliklerine deinmeden nce hemen bu event'lar ile neler yapabileceimize bir gz atalm. [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)

48

{ ToggleDugme.Content = "aretsiz"; } Basit bir ekilde ToggleButton kontrolmzn ierisine yazl metni deitirdiimiz rneimizi altrdmzda artk Button grnmndeki ToggleButton kontrolne her bastmzda iinde duruma gre "aretli" veya "aretsiz" yazacak. Ayrca isterseniz ToggleButton kontrolne ait IsChecked zelliini de kullanarak ToggleButton'un o anki durumundan haberdar olabilirsiniz. Belirsiz durumlara zel... Baz durumlarda sadece iki seenek yetmez ve "belirsizlik" seimi de yapmak gerekebilir. Bu durumda kullancya sadece Evet veya Hayr eklinde cevap vermenin yan sra isterse "Bilmiyorum" gibi bir seenee de ynelebilir. ToggleButton ierisinde byle bir yap da var. Eer bir ToggleButton'un IsThreeState zelliini True olarak ayarlarsanz artk iki deil seenekli bir ToggleButton sahibi olmu oluyorsunuz. Peki bu nc seenei kod tarafnda nasl yakalyoruz? [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)

49

{ ToggleDugme.Content = "aretsiz"; } Grdnz gibi ToggleButton'un ayrca bir de Indeterminate adnda bir event-handler' bulunuyor. Sz konusu durumu yakalayarak belirsizlik halinde de gerekli ilemlerin yaplmasn salayabilirsiniz. Byle bir durumda IsChecked zellii geriye null / nothing dndrecektir. Unutmayn ki herhangi bir kontroln Content zellii aslnda ierisine farkl Silverlight kontrolleri de alabilir hatta kontrollerin grsel yapsnn tamamen deitirebilirsiniz. Silverlight 2 Beta 1 ierisinde Control Templating ile ilgili yazy inceleyerek ToggleButton iin de ayn teknikleri uygulayabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

50

Silverlight 2.0 Beta 1 ile Klasik ASMX Web Servisi kullanm Silverlight 2.0 ile beraber .NET dillerini kullanabilirker aslnda sunucu tarafndaki veriye ulama yaps biraz deiiyor. Normal artlarda istemci tarafndan sunucuya balanabilmek iin AJAX isteklerini kullanrken artk istemci tarafnda elimizde .NET varken ne yapacaz? te bu soruya bir cevap olarak klasik ASMX web servislerinin Silverlight 2.0 Beta 1 ile kullanmna gz atarak hali hazrda elimizde web servisleri ile bulunan projelere nasl Silverlight 2.0 Beta 1 uygulamalarn balayabileceimizi greceiz. Klasik ASMX servisimiz hazr rneimizde kullanlmak zere kendisine verilen iki sayy toplayarak geri dndren bir method'u harici bir web servisi olarak hazrlayarak Silverlight uygulamamza balayacaz. Bunun iin Silverlight uygulamamz host edecek olan ASP.NET 3.5 sitesine bir web servisi ekleyerek ierisine aadaki kodu yazyoruz. 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 admda Silverlight projemize Visual Studio 2008 ierisinde sa tklayarak gelen menden "Add Service Reference" komutunu vererek servisimizi Silverlight projesine referans olarak ekliyoruz. Uygulamamz tasarlyoruz Silverlight uygulamamz ierisinde iki adet TextBox, bir Button ve bir de TextBlock yer alacak. Bu TextBox'lardan alnan deerler web servisine gnderilecek. Deerlerin toplam web servisinden geri dndnde ise sonu TextBlock ierisine yazlacak. Hazrlayacamz rnek bir Silverlight uygulamamsnn XAML kodu aadaki ekilde sonulanyor. <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">

51

<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 kullanalm... Sra geldi artk iin arkaplann geerek kodumuzu yazmaya. Projemize eklediimiz servis referansna verdiimiz isim zerinden servisimizin bir kopyasn yaratarak ierisindeki Toplama metodunu kullanmak istiyoruz. Dim BirServis As New KlasikServisim.servisimSoapClient BirServis.ToplamaAsync(Sayi1.Text, Sayi2.Text) Yukardaki kod aslnda alk olduumuz web servisi kullanmndan pek farkl deil. Fakat arada ufak bir deiiklik var. Bizim adn "Toplama" olarak koyduumuz metodun sonuna Async eklenmi. Aslnda bunun anlam ok basit; Silverlight tarafnda ardnz bir web servisi tamamen asenkron olarak altrlyor. Yani bizim AJAX tarafnda alk olduumuz istemciden sunucuya balanarak veri ekme mant bire bir web servisleri iin de uygulanm. Oysa eskiden Windows programlarnda web servisleri kullanrken ierisinde bulunduumuz Threat kesinlikle verinin gelmesini beklerdi. Peki veri asenkron geliyorsa bizim verinin geldiinden haberdar olmamz gerekmez mi? nk bu artlar altnda verinin ne zaman sunucudan geleceini bilemiyoruz. te tam bu noktada kodumuz ierisinde dinamik olarak bir event-handler tanmlamamz gerekiyor. Dim BirServis As New KlasikServisim.servisimSoapClient AddHandler BirServis.ToplamaCompleted, AddressOf Bitti BirServis.ToplamaAsync(Sayi1.Text, Sayi2.Text) Sonuc.Text = "Hesaplanyor..." Yukardaki kodumuzda Bitti adndaki bir event-handler' servisimizin ToplamaCompleted metoduna balyoruz. Bylece Toplama ilemi tamamlandnda sz konusu event-handler altrlacak. imdi bir de veri geldiinde nasl TextBlock ierisine yazdracamza gz atalm. Public Sub Bitti(ByVal sender As Object, ByVal e As KlasikServisim.ToplamaCompletedEventArgs) Sonuc.Text = e.Result End Sub Grdnz gibi bir nceki admda tanmladmz Bitti event'nn ald ikinci parametre olan ToplamaCompletedEventArgs tipinde e deikeni zerinden Result yani sonuca ulaabiliyoruz. Sz konusu parametre dorudan Toplama metoduna zel olduu iin

52

ierisinde Result zelliinin tipi de zaten web servisimizdeki metodun dn tipi olan Integer. Uygulamamzn tam kodu aadaki ekilde sonlanyor. 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 = "Hesaplanyor..." 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.
DaronYNDEM

53

Silverlight 2.0 Beta 2 ierisinde dinamik resim yklemek Silverlight 2.0 Beta 2 ile beraber gelen deiikliklerden biri de dinamik olarak Image nesneleri yaratmak ve bu nesnelere farkl resimler yklemekle ilgili. Eskiden Beta 1 ierisinde sadece Source zelliini deitirerek resimleri dinamik olarak ykleyebiliyorken artk biraz daha uramamz gerekiyor. lk olarak yeni bir Silverlight 2.0 Beta 2 projesi yaratarak projemize kullanacamz resimleri ekleyelim. Sonrasnda dinamik olarak bir Image nesnesi yaratp ierisini 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); Yukardaki kodumuzun ilk satrnda yarattm Silverlight Image nesnesini doldurmak iin bir ImageSource'a ihtiyacmz var. Bunun iin ilk olarak ykleyeceimiz resim adresini Uri tipinde yaratyoruz. Relative konumlandrma ile dorudan uygulamann ierisindeki resim dosyasn kullanacaz. Sonrasnda elimizdeki Uri'den bir ImageSource yaratyoruz ve bu ImageSource'u da Image nesnemizin SourcePropoerty'sine atyoruz. Tm bu ilemler tamamlandktan sonra tabi ki eldeki Image Silverlight nesnesini de sahneye eklememiz lazm. Peki ya proje harici bir resmi yklemek istersek? Harici resmin bulunduu internet adresi zerinden bir Uri yaratarak yukardaki kodun aynsn kullanabilirsiniz. Bylece uygulamanz sz konusu adresteki fotoraf ykleyecektir. [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. DaronYNDEM

54

Silverlight 2.0 Beta 2 ile ASP.NET Forms Authentication kullanm ASP.NET Authentication mekanizmalar neredeyse tm ASP.NET projelerinde kullandmz pratik zmlerden. zellikle Forms Authentication belki de zellikle internet projelerinde en sk karlatmz sistem. Peki nasl yaparz da Silverlight 2.0 Beta 2 uygulamalarmzda ASP.NET Forms Authentication yapsn kullanabiliriz? WCF zerinden Authentication servisine ulaalm. Silverlight tarafnda sunucuyla veri alverii iin en uygun seim WCF servisleri. Bu nedenle bize bir ekilde Authentication servisine ulaabileceimiz bir servis gerekiyor. Yeni bir Silverlight projesi yaratarak yannda gelen ASP.NET sitesiyle ilemlerimizi yapmaya balayalm. ASP.NET'in kendi WCF Authentication servis altyapsn kullanacaz. Tek ihtiyacmz olan bir Wrapper. Bunun iin hemen ASP.NET sitesine sa tu ile tklayarak gelen menden "Add New Item" diyip normal bir Text File ekleyelim. Bu yeni dosyann adn Auth.svc eklinde dzenledikten sonra iini aarak aadaki kodu yaptralm. <%@ ServiceHost Language="VB" Service="System.Web.ApplicationServices.AuthenticationService" %> Bylece servisimizi tamamladk. Sra geldi bu servisin almas iin Web.Config ierisinde yapmamz gereken ayarlara. lk olarak Forms Authentication yapmz ayarlayalm. <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> Yukardaki kodumuz ile default.aspx haricindeki sitedeki her eyi darya kapadk. ok uramamak iin hemen Web.Config ierisinde de bir kullanc tanmladm. Normalde bu tarz bir yapy kimseye tavsiye etmiyorum. Tabi tm dosyalar darya kapadmz iin Silverlight uygulamas da Auth.svc servisine de ulaamayacak. O nedenle servisimizi Authentication dnda tutup herkese amamz lazm. <location path="Auth.svc"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location>

55

Forms Authentication ayarlarmz tamamladmza gre artk 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 ulam salar. --> <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> </system.serviceModel> <!--Authentication servisini darya aar--> <system.web.extensions> <scripting> <webServices> <authenticationService enabled="true" requireSSL="false"/> </webServices> </scripting> </system.web.extensions> Her ey hazr. Internet taraycnzda Auth.svc adresini atnzda servisin alr halde olduunu grebilirsiniz. Sra geldi Silverlight ile bu servisi kullanmaya. WCF Authentication Servisimiz Silverlight ile dilleniyor. Herhangi bir WCF servisini Silverlight uygulamamza linklermi gibi yine projeye sa tklayarak "Add Service Reference" diyerek referansmz yaratyoruz. Sonrasnda artk kod ierisinde tm Authentication mekanizmalarn kullanabiliriz. [VB] WithEvents Servisim As New ServiceReference1.AuthenticationServiceClient

56

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>(Servi sim_LoginCompleted); Servisim.LoginAsync(Kullanici.Text, Sifre.Text, "", true); } void Servisim_LoginCompleted(object sender, SilverlightApplication2.ServiceReference1.LoginCompletedEventArgs e) { Giris.Content = e.Result.ToString(); } Yukardaki rnek kodlar ierisinde WCF servisimizin LoginAsync metodunu kullanarak bir Login ilemi yapmaya alyoruz. Yine servis ile beraber gelen event'lardan biri olan LoginCompleted durumunda ise Login ileminin baarl olup olmadn ekrana yazdryoruz. Bu ekilde servis ierisinde kullanabileceiniz Logout, IsLoggedIn gibi metodlar da bulunuyor. Hepinize kolay gelsin.
DaronYNDEM

57

Silverlight 2.0 Beta 2 ile beraber gelen TabControl incelemesi Silverlight 2.0 Beta 2 ile beraber gelen yeni kontrollerden biri olan TabControl zellikle Windows uygulamalarndan alm olduumuz sayfal uygulama tasarml ekranlar web ortamnda da rahatlkla oluturabilmemizi salyor. System.Windows.Controls.Extended snf altnda bulunan TabControl'u kullanabilmek iin projenize sz konusu snf reference olarak eklemi olmanz gerekiyor. Visual Studio ierisinde Silverlight projenize sa tu tklayarak "Add Reference" dedikten sonra gerekli eklemeleri yapabilirsiniz. Visual Studio ierisinde ara ubuundan bir TabControl alarak sahneye yerletirdiinizde de ilem otomatik olarak gerekleecektir. Referanslama ksm tamamlandktan sonra Expression Blend ierisinde de Asset Library'de Custom Controls ksmnda projenize referans olarak eklediiniz snflarn altndaki kontrolleri bulabilirsiniz.

Expression Blend 2 June Preview ierisinde TabControl ve TabItem Expression Blend ierisinde sahneye bir TabControl yerletirdikten sonra sra geldi sz konusu TabControl ierisinde TabItem (sayfa) yerletirmeye. Kolaylk olmas asndan Blend ierisinde yerletirmi olduunuz TabControl'a "Objects and Timeline" penceresinde ift tklarsanz sz konusu kontroln sar bir ereve ierisine alndn greceksiniz. Bu ekilde herhangi bir kontrol sar bir ereve ile iaretlendiinde o kontrol dnda ekranda bulunan her ey kilitlenmi olacaktr. Bylece rahatlkla ekrana yerletireceimiz yeni TabItem kontrollerinin kesinlikle TabControl ierisine yerletirileceini 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"

58

Width="400" Height="300" xmlns:System_Windows_Controls="clrnamespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended" xmlns:System_Windows_Controls_Primitives="clrnamespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Exten ded"> <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> Yukardaki kod ierisinde yerletirdiimiz TabControl ve TabItem'larn XML kodunda namespace olarak uzun uzun System_Windows_Controls adn gzyorsunuz. Aslnda bu yapy deitirebiliriz; eer dokmann zerindeki namespace isimlerini deitirirseniz ayn isimleri kodunuz ierisinde de rahatlkla kullanabilirsiniz. TabItem'larn iki nemli zellii var; bunlardan ilki Header yani TabItem'm sayfa bilgisinin gzkt yerde yazlacak olan yaz, dieri ise Content yani TabItem'n temsil ettii sayfada gsterilecek olan ierik. imdi rneimizdeki hem namespace'leri deitirerek daha okunakl bir isim verelim hem de TabItem'larmzn ierisine daha farkl ierikler yerletirelim. <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="clrnamespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended" xmlns:Pri="clrnamespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Exten ded" 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"

59

Width="76" Source="Dock.jpg"/> <TextBlock>Blm 1</TextBlock> </Grid> </Ex:TabItem.Header> <TextBlock>Deneme amal metin</TextBlock> </Ex:TabItem> <Ex:TabItem Content="TabItem2" Header="Tab2"/> </Ex:TabControl> </Grid> </UserControl> Kodumuz ierisinde yer alan TabItem'n hem Header (balk) ksmn hem de ieriini zel olarak dzenliyoruz. <Ex:TabItem.Header> taglar arasnda TabItem iin header grseli olarak farkl Silverlight kontrolleri kullanabiliyoruz. Tek bir snrlamamz var; Header ierisinde kk element sadece bir adet olabiliyor. Bu sorunu amak iin Container Elementlerimizden Grid'i kullanabiliriz. Header ierisine yerletirdiimiz bir Grid ierisine istediimiz kadar Silverlight kontrol koyabiliriz. Header taglar haricinde dorudan TabItem'n ierisine de TabItem'n sayfa ieriinde gzkmesini istediimiz kontrolleri koyabiliyoruz.

zelletirilmi TabItem kontrolmz karmzda! TabItem'larn Header'lar ierisine farkl Silverlight kontrollerini koymann yan sra istersek Header'n tamamen grsel ablonunu da deitirebiliriz. Bunun iin bir ControlTemplate hazrlayarak TabItem'mza balamamz 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="clrnamespace:System.Windows.Controls;assembly=System.Windows.Controls.Extended" xmlns:Pri="clrnamespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Exten ded"

60

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>Blm 1</TextBlock> </Grid> </Ex:TabItem.Header> <TextBlock>Deneme amal metin</TextBlock> </Ex:TabItem> <Ex:TabItem Content="TabItem2" Header="Tab2"/> </Ex:TabControl> </Grid> </UserControl> Kodumuzda yarattmz ControlTemplate ierisinde bir Grid ve onun iinde de bir Image ile ContentPresenter yer alyor. Sz konusu ContentPresenter'n Content zelliini Template'in uygulanaca kontroln Header zelliine balanm. Bylece bu ablonu bal bir TabItem'n Header'na yerletirilen kontrollerin bu ablon uygulandnda ablon ierisindeki ContentPresenter'n ierisine yerletirilecek. XAML kodunu ok uzatmamak adna rnekte srekli Image nesneleri kullandmz iin ortaya kan rnek ok anlaml olmayacaktr fakat Expression Blend ierisinde biraz daha detayl bir alma ile gzel sonular alnabilir.

61

Expression Blend 2 July Preview ierisinde Silverlight ControlTemplate destei. Tm bu yaplar tamamen XAML kodlar yazarak oluturabileceiniz gibi Expression Blend ierisinde aralar kullanarak da yapabilirsiniz. Herhangi bir TabItem kontrolne sa tu ile tklayarak yukardaki ekilde "Edit Control Parts / Edit Template" diyerek TabItem'larn grselliklerini Blend ierisinde de ayarlayabilirsiniz. Her kontrol iin ilk bata "Edit a Copy" diyerek var olan grsellikten bir ablon kopyas alarak veya "Create Empty" diyerek bo bir ablon yaratarak ilerleyebilirsiniz. Son olarak her TabControl'n bir de TabStripPlacement zellii olduundan bahsetmek gerek. Bu zellie verdiiniz deerler ile TabItem'larn Header ksmlarnn TabControl'n stnde, sanda, solunda veya altnda gzkmesini salayabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

62

Silverlight 2.0 Beta 2 ve PHP ile mailform uygulamas ster PHP olsun ister farkl sunucu tarafl programlama dilleri olsun hepsi de "ad zerinde" sunucu tarafnda alyorlar. Biz ise Silverlight tarafnda tamamen istemcide alyor. Bu erevede Silverlight'n tamamen sunucudan bamsz olduunu dnrsek aslnda sunucu ile belirli standartlar yakaladmz srece istediimiz sunucu tarafl programlama altyaps ile entegrasyon salayabiliriz. Bu standartlar WSDL kurallar erevesinde hazrlanm bir web servisi olabilecei gibi bazen ok basit bir POST ilemi bile olabilir. Bu yazmda Silverlight 2.0 Beta 2 ile beraber sunucu tarafnda bir PHP kodu kullanarak mail gnderim ilemi yapacaz. Hazrladmz Silverlight 2.0 uygulamasnn XAP dosyasn sunucuya atmamz uygulamamzn almas iin yeterli olacaktr. nce PHP tarafn zelim! PHP tarafnda ok detaya girmeyeceiz. Yapacamz ey basit bir ekilde sayfaya POST ile gnderilen deikenleri alp uygun bir mail mesaj stringi haline evirdikten sonra mail olarak istediimiz kullancya gndermek 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) ?> rneimize devam ederken ufak bir uyarda bulunmam gerek. Kesinlikle yukardaki gibi bir PHP dosyasn sitenize bu haliyle brakmayn. u an yukardaki dosyada ne post eden arkadan kimlii, ne sender'n agent tipi hibir ey kontrol edilmiyor. Gvenlik asndan kesinlikle bu kodun gelitirilmesi gerek aksi halde nne gelen buraya bilgileri POST ederek size milyonlarca mail yollayabilir. Uygulamamzn tasarmn yapalm Yine ok basit bir mailform hazrlayacaz. Blend 2.5 ierisinden Silverlight sayfamza toplam adet TextBox ve bir de Button koyuyoruz. Site ziyaretileri isimlerini, maillerini ve mesajlarn yazarak dmeye basp gize gnderebilecekler. Oluturduumuz uygulamann XAML kodunu aada 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="Adnz" TextWrapping="Wrap" x:Name="txtAdi"/>

63

<TextBox Height="29" Margin="96,88,74,0" VerticalAlignment="Top" Text="Mailiniz" TextWrapping="Wrap" x:Name="txtMaili"/> <TextBox Margin="96,132,74,81" Text="Mesajnz" TextWrapping="Wrap" x:Name="txtMesaji"/> <Button Height="32" HorizontalAlignment="Stretch" Margin="180,0,146,31" VerticalAlignment="Bottom" Content="Gnder" x:Name="btnGonder"/> </Grid> </UserControl> Kodlamaya geelim Uygulamamzn kod ksmnda bir WebClient nesnesi kullanacaz. WebClient nesnemize sahnedeki tm bilgileri bir String olarak vererek POST metodu ile bilgileri kendisine parametre olarak vereceimiz bir adrese gndermesini isteyeceiz. [VB] Dim VeriGonder As New System.Net.WebClient VeriGonder.Headers(HttpRequestHeader.ContentType) = "application/x-www-formurlencoded" [C#] System.Net.WebClient VeriGonder = new System.Net.WebClient(); VeriGonder.Headers[HttpRequestHeader.ContentType] = "application/x-www-formurlencoded"; VeriGonder adn verdiimiz WebClient nesnemin hemen ContentType bilgisini ayarlamam gerekiyor. Bunun iin WebClient'n Headers dizisinden ContentType' bularak form-urlencoded olarak deitiriyorum. Bylece birazdan URLEncode teknii ile hazrladmz verileri bu WebClient ile rahatlkla sunucuya gnderebileceiz. [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 ierisinde hemen gndereceimiz verileri Key/Value iftleri eklinde birletiriyoruz. Gndereceimiz her verinin bir ismi ve tabi ki deeri olmas gerekiyor.

64

Aslnda yaptmz ey normalde URL zerinden gndereceimiz veriyi URLEncode ile ayn ekilde oluturmak. Eer gndereceiniz verilerin says ok ise performans asndan standart String ilemleri yerine bir StringBuilder kullanmanz 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 gndermeden nce gnderme ilemi tamamlandnda altrlmak zere VeriGonder nesnemizin UploadStrintCompleted event'na da bir eventhandler balyoruz. Artk verimizi sunucuya gndermeye hazr olduumuza gre 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 gnderme ilemi tamamlandnda ekrandaki kontrolleri kaldrp bir teekkr mesaj gstermek gzel olabilirdi. in o ksmn ben size brakm oliyim. imdilik UploadStringCompleted event'nda dmeye "Tamam" yazdrarak rneimizi altrabiliriz. @ aret Sorunu! Ufak bir sorunumuz var. Silverlight 2.0 Beta 2 ile beraber gelen bu sorun ufak gibi gzkse de aslnda epey nemli :) Yukardaki rnei altrdnzda greceksiniz ki herhangi bir TextBox ierisinde @ iareti koyamyorsunuz. Bunun basit bir nedeni var, aslnda AltGr tuu ile oluturduunuz hibir karakteri TextBox'lara yerletiremeyeceksiniz. Neden mi?

65

Bilmiyorum, bu bir bug. Silverlight 2.0'n Beta 2 sonrasnda srmlerinde bu hata giderilecek. imdilik aadaki gibi bir zm 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 altmz mant kavrayalm. txtMail adndaki textBox ierisinde herhangi bir tua basldnda yukardaki gibi KeyDown event' alacaktr. Bu event'a baktmzda klavyede AltGr tuuna basldnda sras ile iki tua baslm gibi sistemin 17 ve sonrasonda da 18 numaral PlatformAnahtarlar'n dndrdn grebiliriz. Bu tularn Macintosh dahil tm sistemlerdeki PlatformKeyCode adnda anahtarlar vardr ve bu deerler srekli ayndr. Normalde biz @ iaretini koyabilmek iin AltGr'ye bastkdan sonra bir de Q harfine basarz. O zaman kontrol etmemiz gereken durum u; Q harfine basldysa acaba bir nceki baslan tu AltGr miydi? Eer leyse bana bir @ iareti lazm. te kodumuz da bu kontrol yapyor. Srekli olarak baslan son iki tuu Oncekiler adndaki dizimizde saklyor ve her tua basldnda KeyDown ierisinde eer Q harfine baslm ise son baslan iki tuun KeyCode'larnn da 17 ve 18 olup olmadn kontrol ediyoruz. Eer durum buysa txtMaili TextBox' ierisine bir @ iareti ekleyip imleci metnin en sonuna gnderiyoruz.

66

Sonu Makalemizde kullandmz teknik aslnda web programclnn en ilkel zamanlarndan bu gne kadar gelen ve yap ta diyebileceimiz POST metodunun ta kendisi. Bu erevede sunucu tarafl programlama sistemlerinin hepsi bu ekilde veri trafiine ak olduu iin ayn teknikler ile Silverlight' sunucu taraf ile rahatlkla konuturabilir ve ister sunucunun iletim sistemi olsun, ister kullanlan teknoloji olsun her konuda tam bamszln tadn kartabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

67

Silverlight 2.0 Calendar ve DatePicker kontrolleri. Silverlight 2.0 ile beni en ok artan zelliklerden biri de WPF'in web srm diyebileceimiz ve WPF'e kyasla bir ok eksii olan bir torun olarak Silverlight ile beraber artk WPF'de bulunmayan baz kontrollerin geliyor olmas. Tahminen uzun vadede her iki taraf da birbirinden besleniyor olacaktr. Bugn baktmzda ilk dikkati eken kontrollerden biri de maalesef WPF tarafnda olmayan Calendar ve DateTimePicker kontrolleri. Bu yazmzda bu iki kontrol ve bu kontrollerle neler yapabileceimizi inceleyeceiz.

Calendar kontrol ekilden ekilde girebiliyor. Yukardaki ekli ile birer Calender kontrol yaratmak iin tek yapmanz gereken XAML kodunuzu aadaki ekilde dzenlemek. <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 yaptmz bir Calendar tag aarak kenarlardan olan uzakln belirtmek. "ocuk oyunca" denen bu olsa gerek. Peki daha neler yapabiliriz? Aslnda bu aamadan sonra bahsedeceimiz tm zellikler Calendar ve DatePicker kontrolleri iin birebir ayn. O nedenle gelin ncesinde bir de DatePicker kontrolnn XAML koduna bakalm. <DatePicker Height="20" Margin="42,0,156,23" VerticalAlignment="Bottom"/> DatePicker kontroln de sahneye yerletirmek en az Calendar kontrol kadar basit. Bu durumda hzlca programatik ilevselliklere gz atabiliriz. Aadaki gibi bir Silverlight uygulamas hazrlayarak kodlamaya balayalm. <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">

68

<Calendar Margin="21,20,145,57" x:Name="Takvim"/> <DatePicker Height="20" Margin="42,0,156,23" VerticalAlignment="Bottom" x:Name="TarihSecici"/> </Grid> </UserControl> Uygulamamzda Takvim adnda bir Calendar kontrol ve TarihSecici adnda bir DateTimePicker bulunuyor. Bu kontroller Silverlight uygulamas ile beraber ilk gsterildiklerinde ilerinde herhangi bir tarih seili gelmiyor. Oysa aadaki ekilde gncel tarihi seili hale getirebilirsiniz. Takvim.SelectedDate = Date.Now TarihSecici.SelectedDate = Date.Now Makalemizin en stndeki grsele baktnzda Calendar kontrolnn iki farkl grsel durumunun bulunduunu grebilirsiniz. Normal artlarda Calendar kontrol gnleri gsterecek ekilde alyor, sonrasnda eer stteki ay ismine tklarsanz aylarn seilebilecei arayz geliyor. Oysa isterseniz Calendar kontrol sayfada ilk aldnda da aylarn seilebilecei arayzn otomatik gelmesini salayabilirsiniz. Takvim.DisplayMode = CalendarMode.Year Eer Calender nesnesinin DisplayMode zellii Month olursa tam bir ay gsteriyor, Year eklinde dzenlendiinde ise tm yl yani aylar gsteriyor. Bunun haricinde isterseniz her iki kontroln de hangi tarih aralklarn gsterebileceini ek olarak dzenleyebilirsiniz. TarihSecici.SelectableDateStart = Date.Today.Subtract(New TimeSpan(5, 0, 0, 0)) TarihSecici.SelectableDateEnd = Date.Today.AddDays(5) Yukardaki kod ierisinde DatePicker kontrolmzn SelectableDateStart ve SelectableDateEnd zelliklerine DatePicker ierisinde seilebilecek balang ve biti tarihlerini aktaryoruz. Bunu yaparken sz konusu tarihlerin hesaplamalarn da tabi ki dinamik olarak yapabilirsiniz. Bylece bu rneimizde kontrol srekli olarak mevcut tarihden 5 gn ncesinin ve 5 gn sonrasnn seilebilmesine olanak tanyacaktr. TarihSecici.DisplayDateStart = Date.Today.Subtract(New TimeSpan(5, 0, 0, 0)) TarihSecici.DisplayDateEnd = Date.Today.AddDays(5) Seili tarihleri belirlemenin yan sra isterseniz belirli tarihleri seilemez yapmann yan sra tamamen o tarihlerin gsterilmemesini de salayabilirsiniz. Bunun iin DisplayDateStart ve DisplayDateEnd zelliklerinden faydalanabilirsiniz.

69

SelectableDateve DisplayDate arasnda fark. Hepinize kolay gelsin.


DaronYNDEM

70

Silverlight 2.0 Cross-Domain WebClient ile REST (GET) ve XLINQ Kullanm Silverlight 2.0 ile beraber istemci tarafnda .NET dillerini kullanabildiimizi ilk duyduumda aklma gelen ilk ey WebClient snfn artk istemci tarafnda da kullanp kullanamayacam olmutu. Kesinlikle kullanabiliyoruz, hatta bununla kalmayp istersek daha detayl bir kullanm iin HttpWebRequest'i de tercih edebiliriz. Tm bu snflar bize REST kullanmnda yardmc oluyorlar. Normal artlarda uygulamalar arasnda veri transferi iin WSDL tanmlarna sahip servislerin kullanm tavsiye edilse de hala maalesef herhangi bir kural tanm olmayan veri kaynaklarn da kullanmak durumunda kalabiliyoruz. te tam bu noktada WebClient basit ilemler iin imdatmza yetiiyor. Eer farkl HTTP Verb'lerini (GET, PUT, POST, DELETE) kullanacaksanz daha detayl ilemler iin HttpWebRequest'i tercih etmeniz gerekecektir. WebClient iin sadece GET ksmnda yer alyor. rneimizdeki Silverlight 2.0 Beta 1 uygulamasnda System.Net.WebClient snfn kullanarak sunucudaki bir xml dosyasn okuyacaz. lk olarak okuduumuz veriyi gstermek zere uygulamamza bir TextBlock ve veriyi ekme ilemini balatmak zere bir de Button ekleyerek aadaki XAML kodunu yaratalm. <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> Sayfamz hazr olduuna gre artk WebClient nesnemizi yaratacak olun kodu dmemizin arkasna 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 Yukardaki kodumuz ierisinde ilk olarak WebClient nesnemizi yaratyoruz. Bir sonraki admda elimizdeki WebClient nesnesinin DownloadStringCompleted durumunu harici bir event-handler'a balyoruz. Bunu yapmamzn nedeni WebClient snfnn kendisine verilen bir adresten alaca veriyi tamamen asenkron olacak alyor olmas. Yani sunucudan veri tam olarak geldiinde bizi haberdar edecek olan event-handlar tanmlamamz gerekiyor. Son admda ise DownloadStringAsync komutuna hedef adresi de bir Uri deikeni olarak aktararak veri talebimizi sunucuya gndermi oluyoruz. Sra geldi veri geldiinde altrlacak olan event-handler kodunu yazarak veriyi TextBlock ierisine yazdrmaya. Fakat onun ncesinde ilk olarak hedef aldmz XML dosyasnn yapsna bir gz atalm.

71

<?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 dosyamz sunucudan istemciya aldktan sonra biz sadece adnn ierisinde "Dar" geen ilk kayd bularak onun Adi'ni gstermek istiyoruz. Bu XML dosyas ok daha farkl olabilirdi, ierisinde ID ve Adi bilgileri olan bir rn listesi olabilir ve istemci tarafna aldktan sonra farkl ekillerde filtrelemek isteyebilirdiniz. Tm bunlar rahatlkla yapabilmek iin Silverlight 2.0 Beta 1 ile istemci tarafnda XLINQ kullanacaz. Silverlight 2.0 ierisinde XLINQ kullanabilmek iin Silverlight projenizde "Solution Explorer" ierisinde sa tklayarak gelen menden "Add Reference" komutu vermeniz ve "System.Xml.Linq" snfn eklemeniz gerekiyor. Sonrasnda artk normalde olduu gibi XDocument ve tm 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 admda dmeye tklandnda yarattmz WebClient nesnesine aktardmz event-handlar burada tanmlyoruz. Bylece sunucudan veri geldiinde bu metod altrlyor olacak. Sunucudan gelen ham veriye e.Result ile ulaabiliyoruz. Gelen veri znde XML olaca iin hemen bir XDocument yaratarak XDocument snfnn Parse zellii ile verimizi ilenebilir hale getiriyoruz. Son admda ise klasik bir XLINQ sorgusu yazarak adnda "Dar" geen kayd bularak deeri Metin adndaki TextBlock nesnemize aktaryoruz. Bylece sunucudan farkl bir XML dosyasn alarak XLINQ ile rahatlkla istemci tarafnda ileyebildiimizi grdk. Peki ya bakan bir alan adndan veri ekmek istersek? Aslnda bu blmde bahsedeceimiz sorun Silverlight'dan bamsz olup tm AJAX uygulamalarnda geerli bir sorun. Maalesef tarayclardaki uygulamalar gvenlik sebepleri ile kendi altklar alan ad haricindeki konumlardan veri alamaz veya gnderemezler. Bu

72

nedenle maalesef Silverlight tarafndan da yola karak baka bir alan adndan veri almak mmkn deil gibi gzkebilir. Oysa bir yol var. ster harici klasik ASMX Web Servisleri, ister WCF servisleri veya ister dorudan REST kullanmak isteyin, harici bir alan adna ulamak istiyorsanz aslnda sz konusu alan adndaki veri kaynann size ulam izni vermi olmas gerekiyor. Silverlight 2.0 kar hedef alan adnda clientaccesspolicy.xml adnda bir dosya arar. Eer bu dosyay bulabiliyorsa ierisinde yazl kurallar erevesinde sizin sz konusu alan adndaki ierie ulamanza 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> Yukardaki gibi bir clientaccesspolicy.xml dosyas herhangi bir alan adndan hedef alan adndaki her konuma ulalabilecei anlamna gelir. sterseniz bu dosyay deitirerek farkl kurallar koyabilir, sadece belirli alan adlarnda alan uygulamalarn hedef konuma ulaabilmesini salayabilirsiniz. <?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> rnein yukardaki gibi bir policy dosyasnda sadece daron.yondem.com adresinden xml dosyasnn bulunduu alan adnda servisler klasr ierisinde kaynaklara ulalabilecei tanmlanm. Policy dosyalar ile ilgili detaylara buradan ulaabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

73

Silverlight 2.0 GridSplitter Kullanm Silverlight 2.0 ierisinde Grid kullanm HTML ierisinden alk olduumuz Table yapsndan pek farkl deil. Kolonlar ve satrlar yaratarak grsel eleri ekranda konumlandrabilmenizi salayan Grid kontrol ile beraber kullanabileceimiz kontrollerden biri de GridSplitter kontrol. GridSplitter kontrol bir Gridin kolon veya satrlarnn kullanc tarafndan fare ile boyutlandrlabilmesini salyor. Herhangi bir Grid yaratarak satr veya stunlar oluturduktan sonra istediiniz Grid hcresine GridSplitter kontrol yerletirebiliyorsunuz. <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> Yukardaki XAML kodunda yer alan Grid'in toplam kolonu var. Bu kolonlardan birinin ierisinde gzkecek ekilde bir de GridSplitter nesnesi yerletirilmi. GridSplitter nesnesinin Grid.Column zellii 1 olduu iin ierisinde bulunduu Grid'in 1 Index numaral kolonunda gzkecek.

GridSplitter kontrol 2 resmi boyutlandryor.

74

Yukardaki gibi bir rnek elde etmek iin Grid'in dier kolonlarna birer Image nesnesi yerletirdim. GridSplitter kontroln fare ile tutup srklediimde her iki resim de ierisinde bulunduklar kolonlara sacak ekilde kendilerini boyutlandrdlar. <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> Yukardaki kod ierisinde dikkat etmemiz gereken nokta GridSplitter kontroln yerletirdiimiz Grid kolonunun Width zelliinin Auto olmas, bylece GridSplitter'n genilii ne ise sz konusu kolonun genilii de o olacaktr. GridSplitter kontroln yukardaki taktikleri izleyerek sadece dikey olarak ekran blmek iin deil yatay olarak Grid'in satrlar arasnda da kullanabilirsiniz. Ayrca birden ok Grid kontroln i ie kullanarak farkl ekranlar yaratmak da mmkn. <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>

75

<GridSplitter HorizontalAlignment="Stretch" Width="Auto" Grid.Row="1" VerticalAlignment="Center" Height="10" Background="#FF0092FF"/> <Image Grid.Row="2" Source="Garden.jpg"/> </Grid> </UserControl> Yukardaki rnekte toplamda satr bulunan bir Grid kontrolnn ikinci satrnda GridSplitter bulunuyor. Ayn Grid'in birinci satrnda ise ierisinde kolun bulunan ayr bir Grid var. teki bu Grid'in de ikinci kolonunda bir GridSplitter var. Bylece yatay GridSplitter kullanldnda dikey olan ve i Grid'de bulunan GridSplitter da otomatik olarak boyutlandrlm oluyor.

2 Grid ve 2 GridSplitter'n kardelii. Bu gibi arayzler neredeyse ou yazlmda karmza kan sistemler ierisinde. Silverlight 2.0 ile beraber i uygulamalar gelitirirken bu tarz kolaylklarn byk bir i ykn omuzlarmzdan kaldraca kesin. GridSplitter deiiklikleri alglamak? GridSplitter' kullanmak gerekten ok kolay. Fakat istemci tarafnda kullanc tm GridSplitter'lar ayarladktan sonra Silverlight uygulamasn baka bir zamanda tekrar atnda tm ayarlar tekrar yapmak zorunda kalmas hi ho olmaz. O nedenle GridSplitter ile yaplan ayarlar bir ekilde saklamamz gerek. Aslnda GridSplitter'n yapt ilem ierisinde bulunduu Grid'in kolonlarnn boyutlarn deitirmek te deil. Bu durumda bizim Grid'in kolonlarnda deiiklik olup olmad yakalamamz ve sz konusu deiiklikleri 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

76

Herhangi bir Grid'in LayoutUpdated metodunu yakaladnzda aslnda Grid'in grselliindeki tm boyut deiikliklerini de yakalam oluyorsunuz. GridSplitter Grid'in kolonlarnn boyutunu deitirdike LaoutUpdated metodu altrlacaktr. Bizim yapacamz da basit bir ekilde IcGrid adn verdiimiz Grid'in sfrc kolonunun geniliini alarak kaydetmek. Kaydetme ilemini bir web servisi ile sunucu tarafna yapabileceiniz gibi doruda Isolated Storage kullanarak istemci tarafnda da saklayabilirsiniz. Ben rnek ierisinde sz konusu deeri Metin adndaki bir TextBlock ierisine yazdrdm. Kaydettiiniz genilik ve ykselik deerlerini Silverlight uygulamas tekrar aldnda grsel arayze 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 stediimiz herhangi bir Grid'in kolonunu yakalayarak Width zelliini deitirebiliyoruz. Hepinize kolay gelsin ;)
DaronYNDEM

77

Silverlight 2.0 HyperlinkButton Kullanm Silverlight 1.0 ierisinde harici sayfalara linkler verecek dmeler yaratmak iin el ile kod yazmak gerekiyordu, eer bir de gerekten bir HTML linki gibi gzken bir HyperLink yaratmak isterseniz epey bir uramanz gerekecektir. Silverlight 2.0 Beta 1 ile bu soruna ok basit bir zm 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> Yukarda da grebileceiniz gibi HyperlinkButton ksmen bizim ASP.NET tarafnda altmz yaplardan farkl deil. NavigateUri zelliine verdiiniz adrese ynlendirme yaparken TargetName ile isterseniz hedef bir pencere veya frame de belirtebiliyorsunuz. Son olarak HyperlinkButton ierisinde gzkmesini istediiniz ierii de Content zelliine aktarabilirsiniz. zellikle ASP.NET ile bir karlatrma yaparsak ASP.NET ierisinde HyperLink kontrollerinin iine farkl kontroller koyabildiimizi de hatrlayabiliriz. rnein rahatlkla bir Image kontroln HyperLink ierisine koyarak kullanabiliriz. Ayn durum Silverlight iin de geerli. <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 zellii aslnda sadece metin ierii almak iin dzenlenmi deil. sterseniz herhangi bir Silverlight kontroln de Content ierisine yerletirebilirsiniz. Bunun iin tek yapmanz gereken Content zelliini Inline olarak deil de HyperlinkButton ierisinde ek taglar iinde dzenlemeniz. sterseniz birden ok kontrol de

78

Content ierisine yerletirebilirsiniz, tek art elinizdeki tm kontrolleri Canvas gibi bir container element ierisine toplam olmak. HyperlinkButton iin Template Kullanm Bir uygulamada birden ok HyperlinkButton kullanlmas olas. Bu gibi durumlarda tm bu linklerin grsel zelliklerinin ortak bir noktada tutuluyor olmas gerekiyor. Hali hazrdaki bir HyperlinkButton'un grsel zelliklerinin deitirilebilmesi iin Content zelliine farkl ierikler aktarmaktansa dorudan HyperlinkButton'un Template zellii dzenlenebilir. <HyperlinkButton VerticalAlignment="Center" Height="Auto" NavigateUri="http://www.live.com" TargetName="_blank" HorizontalAlignment="Center" Content="TIKLA" Template="{StaticResource LinkTemplate}" /> Yukardaki HyperlinkButton'un Template zellii uygulama ierisindeki kaynaklardan birine balanm. Birazdan LinkTemplate adndaki HyperlinkButton ablonumuzu hazrlayacaz. Bylece ayn grsel ablonu birden ok link kullanabilecek. rneimizde ulamak istediimiz noktay belirleyelim. HyperlinkButton'un Content zelliine verilen ieriin dorudan grsel ablonun ortasnda gzkmesini istiyoruz. Bunun iin bir ContentPresenter kullanacaz. Bu ContentPresenter'n arkasnda ise kenarlar yuvarlatlm bir dikdrtgen kullanalm. Bylece HyperlinkButton'umuz normal bir dme gibi gzksn. <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> Yukardaki kod tm isteklerimizi yerine getiriyor. imdi nemli noktalara tek tek deinelim. lk olarak ControlTemplate ierisine iki kontrol koyacamz iin bunlar bir container

79

element ierisine almamz gerekiyor. Biz rneimizde Grid kullandk. ContentPresenter kontrolmzn Content zelliini ablonun hedefi olacak HyperlinkButton'un Content zelliine baladktan sonra geriye sadece ufak iki ayar kalyor. Birincisi ContentPresenter ile Rectangle arasnda mesafe kalmas iin ContentPresenter'a elle Margin vermek. Bylece HyperlinkButton ierisine ne konulursan konulsun her zaman arkasnda Rectangle'n kenarlarndan 10'a piksel uzak kalacak. kinci ufak detay ise ControlTemplate'in TargetType zelliinin kesinlikle ayarlanm olmas gerektii. Artk birden ok HyperlinkButton kullanarak ayn grsel zellikleri kullanabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

80

Silverlight 2.0 ierisinde asenkron font dosyas indirerek kullanmak Silverlight 1.0 ile beraber istemci tarafnda herhangi bir font yklemesi olmadan istediimiz fontlar TextBlock ve TextBox gibi kontrollerde kullanabilir hale gelmitik. Silverlight 2.0 tarafnda gelen yeniliklerle beraber artk her eyi VB veya C# kodumuz ile halletmemiz gerekiyor. Bu yazmzda Silverlight 2.0 ile beraber zel font kullanmn inceleyeceiz. Sunucudan asenkron font indirerek kullanmak Sunucudaki istediimiz bir fontu asenkron olarak istemci tarafna indirip istediimiz kontrollere balayabiliriz. Bylece gerekli fontlar sadece gerekli olduunda istemci tarafna tam oluruz. Bunun iin Silverlight 2.0 tarafnda bir WebClient nesnesi kullanarak ilk olarak font dosyasn istemci tarafna 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 yklendii gibi hemen bir WebClient nesnesi yaratarak ardndan OpenReadCompleted event' iin dinamik bir event handler balyoruz. Sz konusu event handler WebClient nesnesinin sunucudan ald dosyann download ilemi bittiinde altrlacak ve bylece biz de veri geldiinde istediimiz kontrole balayabileceiz. Event-handler balantsn da tamamladktan sonra OpenReadAsync ile sunucudan verimizi almaya balyoruz. [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")

81

End Sub [C#] void Yukleme_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { Label1.FontSource = new FontSource(e.Result); Label1.FontFamily = new FontFamily("DEVELOAD"); } Veri sunucudan geldiinde, download ilemi bittiinde alan event-handler ierisinde hemen elimizdeki TextBlock olan Label1 adndaki kontroln FontSource zelliini deitiriyoruz. Tanmladmz yeni FontSource veri kaynan e.Result ile alyor, yani WebClient'n indirdii Stream'i dorudan FontSource'a evirerek TextBlock'a aktaryoruz. Son olarak tabi ki TextBlock'un FontFamily zelliini de uygun ekilde deitirmemiz gerek. sterseniz WebClient nesnesinin DownloadProgressChanged durumuna da bir eventhandlar balayarak Fontlarn yklenmesi esnasnda yklemenin ne kadarnn tamamlandn da takip edebilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

82

Silverlight 2.0 ierisinde AutoCompleteBox kullanm. AutoComplete ilevsellii AJAX gnlerinden alk olduumuz bir sistem. Herhangi bir TextBox'a kullanc yaz yazarken ayn anda uygun alternatifleri gstermek ve aslnda arka planda bir arama sistemi kurmak gibi ilemleri uzun zamandr farkl arayz aralar kullansak da bir ekilde programclar olarak hazrlayabiliyoruz. Silverlight tarafnda ise Silverlight'n grsel gcnden de faydalanarak ok ilgin zmler retmek mmkn. Silverlight dnyasnda AutoComplete altyaplarn incelerken Silverlight Toolkit ierisindeki AutoCompleteBox kontroln kullanacaz. Not: Silverlight Toolkit'i kullanabilmeniz iin CodePlex zerindeki adresten ktphaneyi indirerek ierisindeki Microsoft.Windows.Controls.dll dosyasn projenize referans olarak eklemelisiniz. En hzl ekilde AutoCompleteBox kullanm.. AutoCompleteBox'n kullanm aslnda ok basit. Hemen bir String Array veya List yaratarak AutoCompleteBox'a bind etmeniz yeterli olacaktr. Tm filtreleme ve AutoComplete ilemleri otomatik olarak yaplacaktr. [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; } Yukardaki kod ile hazrladmz basit bir uygulamann aada da XAML kodunu inceleyebilirsiniz. [XAML] <UserControl x:Class="SilverlightApplication3.Page"

83

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300" xmlns:controls="clrnamespace: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 rnei. AutoCompleteBox'n zellikleri. IsTextCompletionEnabled - Bu zellik ak olduunda kullanc yaz yazdka sadece alternatifler gsterilmez, ek olarak en yakn alternatif sanki yazlm gibi TextBox ierisinde de gsterilir. Varsaylan deeri True eklindedir. SelectedItem - Eer kullanc AutoCompleteBox'n alan ListBox ksmndan bir e seerse SelectedItemChanged alr ve SelectedItem geriye bir Item dndrr. Kullanc ListBox ierisinde yer alan bir Item'n metnini elle yazmsa SelectedItem geriye deer dndrmeyecektir. SearchMode - AutoComplete ilemi yaplrken kaynak veride ne ekilde arama yaplacana karar veren SearchMode zellii varsaylan deeri olan StartsWith ile gelir. sterseniz Contains seeneini seerek dorudan kaynak verinin iindeki tm metinlerin iinde arama yaplmasn da salayabilirsiniz. Eer kendi arama sisteminizi entegre edecekseniz None seeneini semeniz gerekecektir. MinimumPopulateDelay - Kullanc yaz yazarken ne kadar sre sonra alternatiflerin gsterileceini belirler. Eer veri kayna istemci tarafnda bir Silverlight deikeni ise varsaylan deer olan 0 ile herhangi bir sorun yaamazsnz. Fakat alternatifleri sunucudan her seferinde ekiyorsanz buradaki bekleme sresini uzatmakta byk fayda olacaktr. MinimumPrefixLength - Alternatifler gsterilmeden nce ka karakterlik verinin girilmi olmas gerektiine dair ayar bu zellik zerinden yaplabilir. Kendi filtreleme mekanizmamz yazalm. Bir AutoCompleteBox' aslnda iki ekilde veri balam olabiliriz. Bunlardan birincisi yazmzn bandaki gibi basit bir metin dizisini AutoCompleteBox'a aktarmak ikincisi ise kendi tanmladmz nesnelerin bir dizisini balamak. Gelin her iki durumda da filtreleme ilemlerini nasl zelletirebileceimize bakalm.

84

Bir nceki rneimizin zerinden yola devam edersek zaten hali hazrda bir String listesini alp AutoCompleteBox'mza balamtk. AutoCompleteBox'n TextFilter zelliini deitirirek filtreleme ileminin tam olarak nasl yaplacana karar verebiliriz. Bizim yapacamz rnekte kullancnn yazd metin ile balayan deil de biten eleri gstermeye alacaz. [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; } } Yukardaki fonksiyonumuzu filtreleme ilemlerini yapmak iin kullanacaz. Gelen iki parametreden ilki kullancnn TextBox ierisine yazd metin, ikincisi ise o an fonksiyonumuza aktarlan ana kaynak veriden gelen bir Item. Burada kafalar biraz karabilir o nedenle biraz daha detaya inelim. AutoCompleteBox filtreleme ilemini yaparken elindeki verinin iindeki her bir eyi tek tek bizim filtreleme fonksiyonumuza verecek ve sz konusu enin gsterilip gsterilmeyeceine dair bir cevap bekleyecek. Yani eer veri kaynanda 10 adet e varsa bu fonksiyon 10 defa arlacak. [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

85

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; } Hazrladmz filtreleme fonksiyonunu tabi ki AutoCompleteBox'n TextFilter'na da aktarmamz gerek. Yukardaki kodlardaki kaln satrlarda sz konusu aktarma ileminin nasl yapldn inceleyebilirsiniz. TextFilter bizden bir AutoCompleteSearchPredicate istiyor, biz de kendisine istediini veriyoruz :) Peki ya AutoCompleteBox'a kendi yarattmz nesne trlerinden bir liste balam olsaydk bu filtreleme ilemini nasl yapacaktk. Byle bir durumda TextFilter yerine ItemFilter' kullanmak zorunda kalacaktk. Gelin ilk olarak rneimizde ilerleyebilmek iin Kitap adnda kendi snfmz tanmlayalm. [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

86

End Class [C#] public class Kitap { public string Adi { get; set; } public double Fiyat { get; set; } } imdi bu snflar zerinden yola karak Silverlight tarafnda birka kitap yaratp AutoCompleteBox'larmza DataBind edeceiz. [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 ierisinde ok byk deiiklikler yok. Bu sefer bir String listesi yerine Kitap listesi yaratyor ve AutoCompleteBox'n ItemsSource'una eitliyoruz. Filtreleme ilemi iin

87

yine Filtreleme adnda bir metod kullanacamz iin ItemFilter zeliine de sz konusu metodu balyoruz. Aradaki en nemli fark elimizdeki Predicate'in artk Object trn tayor 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 artk Object tipinde. Biz aslnda buradaki deikenin bir Kitap nesnesi olduunu biliyoruz nk AutoCompleteBox tek tek kendisine verilen eleri bu filtreleme fonksiyonuna iletecektir. Bu nedenle elimizde gelen objeyi Kitap tipine cast edip bu sefer de kitaplarn fiyatlar zerinden filtreleme yapyoruz. Kullanclarn TextBox ierisinde saysal bir fiyat gireceini ve bu fiyatn altndaki kitaplarn listeleneceini varsayalm. Bu ekilde uygulamamz altrrsak ufak bir karklk olacaktr. AutoCompleteBox'a baladmz veri Kitap'lardan oluuyor. Peki AutoCompleteBox bu Kitap nesnelerinin hangi zelliini ekrana nasl getirecek? rnein kitabn adn m yoksa fiyatn m gsterecek AutoComplete esnasnda? te bu noktada da bizim XAML tarafna geip birka ilem yapmamz 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="clrnamespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"> <UserControl.Resources> <DataTemplate x:Key="DataTemplate1"> <Grid>

88

<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> Artk bizim AutoCompleteBox'mzn ItemTemplate'ini deitirmemiz ve zelletirmemiz gerekiyor. Bylece tam olarak gelen veriden hangi elerin nerelerde nasl gsterileceine karar verebiliriz. Yukardaki kod ierisinde AutoCompleteBox'n ItemTemplate zelliinin deitirildiini grebilirsiniz. DataTemplate1 adnda yarattmz DataTemplate'i UserControl.Resources ierisine koyup kullanabiliyoruz. DataTemplate ierisinde ise bir Grid ve TextBlock bulunuyor. Sz konusu TextBlock dorudan Fiyat adnda bir Field'e DataBind edilmi durumda. Hatrlarsanz bizim Kitap snfmzn Fiyat adnda bir Property'si vard. Bylece AutoCompleteBox'a kendisine verilen verilerden her birinin Fiyat zelliinin DataTemplate ierisindeki bu TextBlock'un Text'ine balanmasn saladk. Tm bu ilemleri Visual Studio ierisinde XAML yazarak yapabileceiniz gibi isterseniz Expression Blend'in arayznden de tabi ki daha rahatlkla yapabilirsiniz. Tek yapmanz gereken AutoCompleteBox'a sa tu tklayp gelen menden "Edit Other Templates / Edit ItemTemplate" demek. Bylece tasarm modunda Blend ierisinde de DataTemplate'in grselliini deitirebilirsiniz. Artk filtreleme ilemlerini bitirdik, filtreleme esnasndan Kitaplarn sadece fiyatlarnn gzkmesini de saladk. Fakat neden sadece fiyatlar gzksn ki? Kullanc TextBox ierisinde 25 yazdnzda 25YTL'den ucuz kitaplarn hem ad hem fiyat yazsa? Ve bunlarn arasndan bir kitap seilince fiyat otomatik olarak TextBlock ierisine yerlese daha gzel olmaz m? AutoCompleteBox'n alan ksmnn grselliini ne de olsa yukarda deitirmitik, gelin imdi ikinci bir TextBlock ekleyerek onu da Kitap nesnelerinin Adi zelliine balayalm. [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>

89

Grdnz gibi DataTemplate'i deitirerek aslnda iimizi zm olduk. Geriye tek bir sorun kalyor. Kullanc herhangi bir Item' ListBox ierisinden setiinde TextBox'n iine ne yazlacak? Kitap nesnesinin Adi m? yoksa Fiyat m? Tabi ki bizim rneimizde Kitap nesnesinin fiyat yazlacak aksi halde filtreleme mekanizmamzla akacaktr. [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? dediinizi duyar gibiyim. Maalesef AutoCompleteBox'n ListBox'tan seili elerin hangi zelliklerinin alnacana dair bir ayar yok. Aslnda arka planda

90

AutoCompleteBox kendi ierisinde bir e seildiinde o eyi ToString() metodu ile alp TextBox ierisine yerletiriyor. Bu durumda bizim de ToString metodunu Override etmemiz her eyi zecektir. Artk herhangi bir Kitap nesnesi zerinden ToString altrlrsa kitabn fiyat bilgisi verilecek.

zelletirilmi bir AutoCompleteBox rnei. Hepinize kolay gelsin.


DaronYNDEM

91

Silverlight 2.0 ierisinde Carousel kullanm. Carousel kontrolleri son dnemin modas diyebiliriz. ou yazlmn arayznde Carousel kontrolleri grmeye baladk. zellikle web sitelerinde de neredeyse RIA denildii anda bir yere bir Carousel konulmas gibi bir moda da mevcut. Bu erevede Silverlight 2 uygulamalarnzda Carousel yaplarndan faydalanmak isterseniz hereyi sfrdan yazmanza gerek yok. Bu yazmda sizlere ak kaynak kodu ile datlan hazr bir Carousel kontroln tantacam. Coolmenu Carousel kontrol lk olarak gelin kullanacamz kontrol kendi web sitesinden bir bilgisayarmza indirelim. Aadaki adresten indirebilecein kontroln tm kaynak kodlar ile alp inceleme ansnz var. Biz imdilik RC0 iin hazrlanm olan paketi alarak ierisinde Coolmenu.DLL dosyasn kullanacaz. Yani kaynak kodlar ile uramayacak dorudan kontroln Compile edilmi halini projelerimize entegre edeceiz. http://pagebrooks.com/archive/2008/08/21/coolmenu-a-silverlight-menu-control.aspx Projemize Carousel ekleyelim! Projemizde Coolmenu Carousel kontroln kullanabilmek iin ilk olarak download paketinden Coolmenu.Dll dosyasna Silverlight projemize referans olarak eklemeliyiz. Sonrasnda XAML tarafnda sz konusu kontrol sayfaya koyabilmemiz iin gerekli namespace tanmlarn yapmamz 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="clrnamespace:SilverlightContrib.Controls;assembly=CoolMenu"> <Grid x:Name="LayoutRoot" Background="White"> <SilverlightContrib_Controls:CoolMenu x:Name="Carousel"/> </Grid> </UserControl> Yukardaki XAML kodunu incelediiniz zellikle dikkat etmemiz gereken aslnda iki nokta var. Bunlardan ilki xmlns tanmmz. SilverlightContrib_Controls adnda tanmladmz yeni XML namespace'imiz dorudan Coolmenu assembly'sini hedefliyor. Bylece sz konusu assembly ierisindeki tm kontroll XAML ierisinde kullanabileceiz. Bir sonraki admda da tanmladmz NameSpace'i kullanarak CoolMenu kontrolnden bir adet ekrana yerletirerek adn da Carousel olarak tanmlyoruz. Bu aamadan sonras iin kod tarafna gememiz ve bu Carousel ierisinde gsterilecek eleri tanmlamamz gerek. [VB] Dim Foto As New Image

92

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 kodlarmz ierisinde srekli yeni Image nesneleri yaratarak bunlar tek tek birer e (CoolMenuItem) olarak Carousel kontrolmze ekliyoruz. Her bir CoolMenuItem'n Content zelliine herhangi bir Silverlight nesnesi atayabilirsiniz. Bu ister bizim rneimizdeki gibi bir resim ister bir video, yani MediaElement olabilir. rnek Carousel Kontrol (Tklamay unutmayn :)) Hepinize kolay gelsin...
DaronYNDEM

93

Silverlight 2.0 ierisinde ControlTemplating ve Style yaplar. Silverlight 2.0 Beta 1 ile beraber gelen grsel zellikler ierisinde zellikle tasarmclarn en ok beenecekleri ve bildiimiz teknolojiler arasnda CSS'e benzetebileceimiz "Resource" yaps ok nemli bir yere sahip. WPF'de hali hazrda var olan ve Silverlight tarafna da (ciddi farkllklar ile) tanan bu zellikler sayesinde Silverlight uygulamalar ierisinde kontrollerin programatik ilevselliklerinden bamsz olarak grsel zellikleri ayarlanabildii gibi merkezi bir ynetim de salanabiliyor. Gelin hzl bir rnek ile konumuza giri yapalm. <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 yukardaki gibi yaratacamz yeni bir Silverlight 2.0 uygulamasna basit bir Button yerletirelim ve Button ierisinde yaznn (Content) yerine farkl bireyler koymay deneyelim. Yukardaki kod ierisinde Content deeri dorudan bit metne eitlenmi durumda. Oysa bu deerin ierisine baka bir Silverlight kontrol yerletirebiliriz. <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> Yukardaki kod ierisinde Button nesnesinin Content zelliini belirlemek iin Button taglar arasnda ayrca bir Button.Content taglar atk.

94

Button.Content zelliini deitirilen Button nesnesi sada. Bu noktada Button.Content ierisinde istediiniz Silverlight kontroln yerletirebilirsiniz fakat dikkat etmeniz gereken bir nokta var; maalesef bu taglar arasnda sadece bir Silverlight kontrol yerletirilebilir. Aslnda cmle olarak yanl bir cmle oldu, daha doru tabiri ile Button.Content ierisinde XAML kodunun her zaman tek bir RootElement'inin olmas gerekiyor. Yani eer bu blgeye iki kontrol yerletirmek istiyorsanz kontrollerinizi bir Container Element ierisinde gruplayarak yerletirmek zorundasnz. Aadaki rneimizde Container Element olarak bir StackPanel kullanacaz. <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> Grdnz gibi Root Element olarak Button.Content ierisinde bir StackPanel kullandktan sonra artk StackPanel ierisine istediimiz kadar kontrol yerletirebiliyoruz.

95

Button.Content ierisinde birden ok Silverlight kontrol. Bu yap ile farkl kontrollerinin farkl grsel zelliklerini tanmlamak mmkn. Bir kontroln tm grsel yapsn nasl deitiririz? Bu noktaya kadar elimizdeki bir dmenin ierisinde farkl Silverlight kontrolleri yerletirdik. Oysa sz konusu dmenin tm grsel yapsn deitirmek de isteyebilirdiniz. rnein bir Resim nesneninin bir Button olarak tanmlanmas mmkn mdr? <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> Yukardaki kodumuz ierisinde bir Button nesnesinin Template zelliini baka bir ControlTemplate atayarak deitiyoruz. Tanmladmz ControlTemplate ierisinde sadece bir adet Image nesnesi var. Bylece artk dmemiz sadece bir Image nesnesinden oluacak oysa programcmz iin bu nesne hala bir Button.

96

Bir Button nesnesine benzemiyor deil mi? Ama yle. Peki tm bunlarn anlam nedir? Yukardaki iki yapy Button.Content ve Button.Template beraber kullanmanz halinde istediimiz gibi dmeler oluturabilirsiniz. Gelin imdi gzel bir dikdrtgen izelim ve bunu yeni yarattmz bir Button nesnesinin Template zelliine aktaralm. <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> Yukardaki kod ierisinde en nemli nokta Button'umuzun ControlTemplate'i ierisindeki Rectangle nesnesinin Margin zelliklerinin TemplateBinding ile ierisinde olduu kontroln Margin zelliine balanm olmas. Bylece Button nesnesi bydke otomatik olarak ControlTemplate ierisinde tanmlanm Rectangle da byyecek. Her zaman olduu gibi eer ControlTemplate ierisinden birden ok Silverlight kontrol kullanarak grsel zellikler tanmlamak isterseniz bir Container Element kullanmanz gerekecektir. Bizim rneimizde tek nesne bulunduu iin gerek olmad.

97

Yeni Silverlight Button nesnemiz karnzda! Grdnz gibi dmemizin grsel zellikleri tamamland. Peki ya bu dmenin ierisine yazlacak olan yaz nerede? u anda kontroln bu hali ile Button.Content zelliine farkl deerler verdiiniz grsel anlamda herhangi bir deiiklik grmeyeceksiniz. nk kontroln ControlTemplate tanm ierisinde herhangi bir ekilde Content ieriinin konaca bir yer ayarlanm deil. Yani Button.Content ierisine konacak nesnelerin veya yaznn ControlTemplate ierisinde nereye konacan tanmlamamz 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> Yukardaki kod ierisinde tanmladmz Button'n ControlTemplate'i ierisinde bir ContentPresenter nesnesi bulunuyor. Bu ContentPresenter'n Content zellii ise

98

TemplateBinding ile ana Button nesnesinin Content'na balanm durumda. Bylece Button'un Button.Content' ierisindeki tm Silverlight kontrolleri otomatik olarak ControlTemplate ierisindeki ContentPresenter ierisine yerletirilmi olacaktr. Bu noktada dikkat etmemiz gereken nemli bir ayar var, ControlTemplate'n TargetType'nn zel olarak ayarlanm olmas gerekiyor, aksi halde sz konusu ControlTemplate bir Button ierisinde bulunmasna ramen doru olarak almyor. Umarm Beta srm sonrasnda srmlerde bu yap dzeltilir, u anki alma yaps pek mantkl deil.

Button'umuzun son hali. Peki neden dorudan hereyi ControlTemplate ierisine koymuyoruz? ok mantkl bir soru. nk bu noktaya kadar yaptmz tm grsel ayarlarn zerinden bir merkezi ynetim sistemi kurmak istiyoruz. Bir nceki admda Button nesnemizin Template zelliini ayarlamtk. imdi sra geldi sz konusu Template' birden ok kontrol tarafndan kullanlabilir 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>

99

</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 tanmmz Button'un ierisinden keserek dorudan UserControl.Resources altna alyoruz. Bylece artk tm Silverlight XAML sayfas ierisinde kullanabileceiz. Tabi bunu yaparken bir Style tanmlyoruz ve TargetType zelliini de Button olarak dzenliyoruz. Style ierisinde bir Setter yerletirerek hedef kontroln Template zelliini deitirmek istediimizi de belirttikten sonra Setter.Value ierisine daha nce hazrladmz Template yapsn yerletiriyoruz. Son olarak adn Dugme koyduumuz bu Style' kullanmak istediimiz tm Button kontrollerinin Style zelliini StaticResource olarak stilimize balayarak kullanabiliyoruz. Bylece tm dmelerimiz ayn ControlTemplate'i kullanacaklar ve hepsi de kendi ierisindeki Content' hedef Style ierisindeki ContentPresenter'a yerletirerek gsterecekler. Herhangi bir grsel deiiklik gerektiinde ise merkezi olarak Style'mz deitirerek ilerleyebileceiz. sterseniz bu Stlye'nz Silverlight uygulamasnn App.xaml dosyas ierisine koyarak Silverlight uygulamanzdaki tm XAML dosyalar ierisinde kullanlabilir hale de getirebilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

100

Silverlight 2.0 ierisinde createFromXaml alternatifi ve alt seviyeli dinamik nesne retimi Silverlight 1.0 ierisinde JavaScript tarafnda sahip olduumuz createFromXaml metodu ou durumda iimizi kolaylatryordu. Dinamik olarak yaratmak istediimiz nesnelerin XAML kodunu bir kereliine Blend ile yaratarak sonrasnda sz konusu XAML kodunu programatik olarak String tipinde deitirip dorudan createFromXaml metoduna verdiimizde istediimiz tm Silverlight nesnelerini gerekli zellikleri ile beraber alm oluyorduk. Silverlight 2.0 tarafnda ise tm nesneler artk birer .NET nesnesi olduuna gre aslnda bu nesnelerin yaratlarak sahneye yerletirilmesi ok daha kolay gibi gzkyor. 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> Tasarmcmz Expression Blend ile yukardaki gibi znde ok basit olan bir Ellipse tasarladn dnelim ve biz de bu Ellipse'in ykseklik ve genilik zelliklerini elimizdeki herhangi bir veriye bal olmak art ile deitirerek birden ok Ellipse yaratmaya alacaz. Bu noktada Silverlight 1.0 ierisinde createFromXaml kullanrken SL 2.0 ierisinde .NET nesneleri eklinde gerekli ilemleri yaparak Ellipse'ler yaratmaya karar verirsek aadaki kodu yazmamz 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)

101

[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); Grdnz gibi aslnda her eyi .NET kodumuz ile de yapabiliyoruz fakat tasarmcnn Blend ierisinde yapm olduu tasarm yukardaki koda evirmek ciddi "ikence" kvamnda. Tabi ki tasarmcnn sahneye koyduu nesnelerin zelliklerine tek tek erierek .NET kodumuz ile deitirebiliriz fakat u anda yapmak istediim bu nesnelerden programatik olarak birden ok yaratp zelliklerini de ayarlayarak sahneye yerletirmek. zmlerden ilki UserControl yaps; eer yaratacanz nesnelerin yaplar sabit ise yani byk deiiklikler yoksa sz konusu yapy bir UserControl olarak tasarlayarak belirli zelliklerini deitirip sahneye yerletirebilirsiniz. Fakat baz durumlardan UserControl yaps da gerekli esneklii salayamayabiliyor. te byle durumlarda yardmmza System.Windows.Markup.XamlReader.Load metodu yetiiyor. Bu metod Silverlight 1.0'da alk olduumuz createFromXaml metodu ile birebir ayn mantkta alyor. Parametre olarak ald String XAML kodundan bize Silverlight nesneleri yaratarak geri dndryor. imdi de aadaki ekilde XAML kodumuzun dinamik olarak yaratp Silverlight nesnemizi oluturalm. [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>

102

</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 tarafna alp System.Windows.Markup.XamlReader.Load ile kullanacamz zaman kopyaladmz XAML kodu ierisinde kullanlan tm XML namespace tanmlamalarn ana XAML dosyasndan kopyalam olmamz gerekiyor. Yukardaki kodlarda kaln yazl ksmlar bu ekilde kopyalanmtr. LINQ ile beraber VB ierisinde "inline XML" yaps geliyor, bu yapy Silverlight ierisinde de kullanabiliyoruz. Bunun iin tek yapmamz gereken Silverlight projemize sa tu tklayarak "Add Reference" diyip System.XML.Linq ktphanesini projemize eklemek. Bylece artk tasarmcnn Blend ierisinde dzenlemi olduu XAML kodunu dorudan Silverlight ierisinde VB dosyamza kopyalayabiliriz. C# ierisinde ise XAML kodumuzu bir string deikene aktarabilmek iin bolca escape char kullanmamz gerekiyor. Sra geldi yarattmz XAML kodu ierisinde istediimiz zellikleri deitirmeye. VB ierisinde yarattmz deiken dorudan XAML ald ve bir XElement nesnesi oluturduu iin XML ierisindeki zelliklere rahatlkla ulaabiliyoruz. [VB] EllipseXAML.@Width = 300 Maalesef C# ierisinde byle bir ansmz yok. Bir seenek olarak C# ierisinde tm XAML kodunu harici bir dosyada tutup sz konusu harici dosyay bir XML dosyasym gibi XDocument olarak ykleyerek kullanmak olabilir. Yukardaki ekliyle zelliklere dorudan ulamann yan sra istersek XAML kodunun ierisine ilk tanmlama esnasnda da yerletirebiliriz. [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">

103

<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>"; Yukardaki kod ierisinde yarattmz bir Integer deikenin deerini kendi XAML kodumuzdaki Elipse'in yksekliine atyoruz. VB ierisinde bu ilemi yine Inline XML tekniini kullanarak yaparken C# ierisinde standart string ilemi olarak ilerlememiz gerekiyor. Son olarak sra geldi elimizdeki bu XAML kodundan nesnemizi yaratarak sahneye yerletirmeye. [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); rneimizi tamamladk. Fakat eer bir veriye bal olarak birden ok nesne yaratacak olsak nasl olurdu? Hemen minik bir rnek ile onu da inceleyelim. Farkl yksekliklerden birden ok Ellipse yaratabilmek iin elimizdeki yksekliklerin bir listesinin dizi olarak bulunduunu varsayalm. [VB] Dim Yukseklik() As Integer = {57, 67, 80}

104

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 programclar iin biraz yeni bir yap olduu iin ilk nce yukardaki VB kodumuzu inceleyelim. Her zamanki gibi yine VB ierisinde inline XML zelliklerinden faydalanyoruz. Birden ok Ellipse'i dorudan XamlReader.Load'a verme ansmz yok. XamlReader ayn SL 1.0'daki createFromXaml'da olduu gibi sadece tek bir nesne geri dndrebiliyor. O nedenle tm Ellipse'lerimizi bir Canvas ierisine yerletiriyoruz. XamlReader bize ierisinde Ellipse'lerin bulunduu Canvas nesnesini geri dndrecek. VB kodumuzda Canvas XML taglar arasnda <%=%> iaretleri ierisinde bir LINQ sorgusu gryorsunuz. Bu sorgu kodumuzun en stndeki veri kaynamz olan Yukseklik dizisini sorgulayarak kaytlar alyor. Alnan her kayt iin yaplan Select ileminde ise geriye bir XML dndrlyor. Doal olarak bu XML bizim Ellipse'in XAML kodu olacak. Tm bu ilemleri yaparken Select esnasnda yarattmz XAML'n yksekliine de sorgunun alt satrdaki deeri, yani dizinin ierisindeki deeri ykseklik olarak atyoruz. Bylece sorgumuz geriye ykseklikleri veri kaynandan alnarak ayarlanm bir Ellipse serisini XML olarak dndryor. Bu dnen deeri Canvas taglar arasna alarak dorudan EllipseXAML deikenimize aktaryoruz. 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\"/>" +

105

"<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 baktmzda ise "inline XML" destei olmad iin yine String zerinden gitmek durumunda kalyoruz. XamlReader'a verilmek zere tm Ellipse'lerimizi ana bir Canvas ierisine alrken Ellipse retimi iin LINQ'n sorgularnn yardmn istiyoruz. C# ierisinde LINQ sorgumuz gerekli deerleri de XML ierisine yerletirerek bir string dizisi retiyor. Son olarak elde ettiimiz XAML kodundan nesnelerimizi yaratp sahneye yerletiriyoruz. Sonu Yukardaki teknikler ile farkl uygulamalarnda tm Silverlight nesnelerini en alt seviyeden mdahale ederek XAML zerinden retebilirsiniz. Fakat unutmamakta fayda var ki bu tarz yazlm uygulamalarn sonradan deitirilmesi, ynetilmesi ok zor olacaktr. rnein tasarmc yukardaki rneklerdeki Ellipse'in tasarmn deitirmeye karar vermesi programc sanrm intihara epeyce yaklaacaktr. O nedenle XamlReader.Load teknii olabildiince en zor durumlarda, en sktnz anlarda kullanmakta fayda var. Normal artlarda UserControl yaplar ou zaman gerekli zm sunacak ve daha rahat bir alma ortam salayacaktr. Hepinize kolay gelsin...
DaronYNDEM

106

Silverlight 2.0 ierisinde fare roller'n kullanmak... Silverlight 2.0 ierisinde .NET programlama dillerini kullanrken istemci tarafnda bir taraycda olduumuzu srekli hatrlamak gerek. Bu bilgiyi aklmzda tutarsak aslnda Silverlight ierisinde yaplamayan baz eyleri taraycnn zelliklerinden faydalanarak yapma ansmz olabiliyor. Bu konuya rneklerden biri Silverlight 2.0 ierisinde farenin roller'n yakalayarak zoom-in veya zoom-out efekti yaratmak. Maalesef imdilik Silverlight ierisinde farenin roller'n yakalayabileceimiz herhangi bir event-handler yok. Bu durumda biz de taraycnn zelliklerinden faydalanacaz. lk olarak hazrlayacamz Silverlight 2.0 Beta 1 uygulamasnn XAML kodunu inceleyelim. Page.xaml ierisinde basit bir Image nesnesi yer alyor. Farenin rollern kullanarak sz konusu Image nesnesini zoom yapabileceiniz, yani znde Image nesnesinin boyutlarn byterek klteleceiz. <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> Yukardaki kod ierisinde zellikle dikkat edilmesi gereken bir nokta var. Normal artlarda Expression Blend ierisinde bir Image nesnesi yerletirirseniz Image.RenderTransform tag ve ierisindekiler gelmeyecektir. Eer sz konusu Image nesnesini sadece bir kere arayz ierisinde boyutlandrrsanz hemen bu taglar eklenir. Sonrasnda RenderTransform ierisindeki ScaleTransform ksmyla ilgileneceiz. Image nesnemizin bykln deitirecek olan tag bu. ScaleTransform'un ScaleX ve ScaleY adnda X ve Y dorultusunda boyutlandrma yapabilen arpanlar var. Bu arpanlara ve ScaleTransform nesnesine programatik olarak ulaabilmek iin hemen ScaleTransform'a ZoomCarpani adn veriyoruz. Bylece artk rahatlkla kod tarafndan bu resmin boyutu ile oynayabiliriz. Gelelim code-behind sayfamza; ilk olarak internet taraycmzn farenin roller'n alglad event-handlerlar yakalayarak kendi .NET event handlerlarmz balamalyz. Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

107

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 uygulamamz sayfaya ilk yklendiinde hemen mevcut HtmlPage (HTML sayfa) zerinden tarayc penceresini (Window) yakalayarak DOMMouseScroll ve onmousewheel durumlarna kendi FareTekerlekDondu kodumuzu atyoruz. Ayrca sayfada ykl dokmann da (Document) onmousewheel event'n ayn ekilde yakalamamz gerekiyor. Tm bu farkl event-handlerlar aslnda hep bizim tek event-handlarmz olan FareTekerlekDondu'ye ynlendiriliyor. Bunun nedeni farkl tarayclarn farkl eventhandlerlar ile alyor olmas. Bizim rneimiz rahatlkla Opera, Safari, FireFox ve IE'de alacak. Sra geldi FareTekerlekDondu'y kodlamaya. Private Sub FareTekerlekDondu(ByVal sender As Object, ByVal e As System.Windows.Browser.HtmlEventArgs) ... End Sub Yukardaki ekli ile kodumuzu yazarken dikkat etmemiz gereken nokta e parametresinin tipi. HtmlEventArgs bize taraycnn dndrd deerleri aktaracak. Dim DonMiktar As Integer = 0 Dim Gelen As System.Windows.Browser.ScriptObject = e.EventObject Kodumuzda iki adet deiken tanmlyoruz. Bunlardan ilki olan DonMiktar taraycndan gelen farenin roller'n dn miktarn alarak ynn belirleyecek. Tarayclardan dn miktar + veya - deer olarak gelebilir ve maalesef bu durum tarayc tipine gre farkl ynlerde dnleri tanmlyor. Tanmladmz bir dier deiken ise Gelen adnda; bu deiken dorudan e parametresinden EventObject'i alarak bize dn miktarn ulatracak. '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 Yukardaki kod biraz kark gzkebilir fakat aslnda yapmaya altmz ey ok basit. Taraycdan farenin roller'nn dn miktarn almaya alyoruz. Maalesef farkl tarayclarda bu sistemin farkl almas gerekiyor. Opera ve IE bu deeri wheelDelta zellii zerinden verirken Mozilla ve Safari detail adnda bir property kullanyor. Ayrca IE

108

dnda tm tarayclarda deerler ters, veya belki de IE'de ters :) Ama duruma gre gelen deeri eksi ile arpmak zorunda kalyoruz. If DonMiktar > 0 Then ZoomCarpani.ScaleX += 0.1 ZoomCarpani.ScaleY += 0.1 Else ZoomCarpani.ScaleX -= 0.1 ZoomCarpani.ScaleY -= 0.1 End If Artk elimizde DonMiktar deikeni hazr olarak bulunduunda gre DonMiktar'n eksi veya art deer almasna gre elimizdeki resmi bytp kltebiliriz. Bu noktada bytme ve kltme miktarn el ile ayarlamakta fayda var. Aslnda DonMiktar ierisinde farenin roller'nn bir defada ne kadar dndrldne dair bir deer geliyor fakat bunu kullanmak farkl sistemlerde ok ilgin sonular verebiliyor. En iyisi sabit bir yol izlemek. If DonMiktar <> 0 Then e.PreventDefault() Gelen.SetProperty("returnValue", False) End If Son olarak taraycya farenin roller deiimi ile ilgili ilemlerini bizim yaptmz belirtmemiz gerek. Bylece tarayc ierisinde sayfa scroll etmeyecektir. Uygulamamzn tam kodu aadaki ekilde sonulanyor.... 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

109

If DonMiktar <> 0 Then e.PreventDefault() Gelen.SetProperty("returnValue", False) End If End Sub Hepinize kolay gelsin...
DaronYNDEM

110

Silverlight 2.0 ierisinde farenin ift tklamasn alglamann yolu. Silverlight ierisinde otomatik olarak farenin ift tklamasn alglayacak bir sistem bulunmuyor. ok ciddi bir eksik gibi gzkmese de aslnda zellikle i uygulamalar hazrlarken bu eksik can skabiliyor. Aslnda bu eksii gidermenin ok kolay bir yolu var. ift tklama sistemi entegre etmek istediiniz bir kontrol normal tklama durumunu kontrol ederek bir nceki normal tklama ile aradaki sreyi ve bir nceki tklama ile u anki tklamann pozisyonlarn kontrol etmeniz yeterli olacaktr. [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 Yukardaki kod ierisinde de grebileceiniz zere ilk olarak bir nceki tklama bilgilerini saklamak zere bir Date bir de Point deikenimizi global olarak tanmlyoruz. Bu deikenlerin srekli en son tklamaya ait konum ve zaman bilgilerini saklayacak. Sonrasnda MouseLeftButtonDown event-listener' ierisinde bir nceki tklama ile u anki tklamann koordinatlarn karlatryoruz. Kullanc tabi ki biraz fareyi kaydrm olabilir o nedenle yaklak 20 piksellik bir kayma pay verebiliriz. Eer yeni gelen tklamann koordinatlar bir nceki ile ayn ise bu sefer de ikinci tklama an ile bir nceki tklama arasnda geen sreyi hesaplyoruz. Sre bir saniyenin altnda ise byk ihtimal ile bir ift tklama gereklemi demektir. Bizim rneimizde basit bir MessageBox gsteriyoruz, sizin kodlarnzda tabi ki farkl ilemler yaplacaktr. Tm bu kontrollerin sonucu olumlu ve olumsuz olsun, en sonunda da Son Tklama'ya ait bilgileri saklayacak olan deikenlerimize yeni tklamann bilgilerini aktarmay unutmuyoruz ki bir sonraki tklamada bu bilgileri "bir nceki" tklama bilgileri bal ile incelenebilsin. Hepinize kolay gelsin.
DaronYNDEM

111

Silverlight 2.0 ierisinde harici Class Library yaplarnn asenkron kullanm. Silverlight projeleriniz bydke projenin baz blmlerini sonradan istemci tarafna aktarmay daha uygun bir seenek olarak grebilirsiniz. Bu gibi durumlarda acaba ayr bir XAP dosyas yapsak da onu haricen istemciye yklesek diye dnrseniz maalesef sz konusu XAP dosyasn kendi kodlarnz ile ZIP eklinde amanz ve ierisindeki Manifest.xml'i yine kendi kodunuz ile okuyup tek tek DLL'leri yklemeniz gerekecektir. Bu konuda detayl bir makaleye buradan ulaabilirsiniz. Bu zorluklarla uramadan hzl bir ekilde belki de sadece bir UserControl' haricen sonradan yklemek istiyorsanz aslnda ok daha pratik ve hzl bir yntem de kullanlabilir. Bu ynteme sadece UserControl'ler deil harici olarak yazlan snflar da dahil. Gelin daha fazla teorik konuma yerine bir rnek zerinden ilerleyelim. Haricen yklenecek ierii hazrlayalm.... lk olarak ana Silverlight uygulamamza sonradan yklenecek olan ierii hazrlayalm. Bunun iin Visual Studio ierisinde "File / New Project" dedikten sonra "Silverlight" seenei altndaki "Silverlight Class Library" proje tipini seiyoruz. Bu proje tipinde dorudan tm proje ierii bir DLL ierisine konacak fakat bu DLL ayrca bir XAP dosyas ierisinde sktrlmayacak. Bylece biz de Silverlight ile istemci tarafnda bir XAP dosyas amak veya Manifest ile uramak zorunda kalmayacaz. Normal artlarda Silverlight Class Library projesi yarattnzda proje ierisinde sadece bir CS veya VB dosyas grebilirsiniz. Oysa bu projelere de isterseniz XAML dosyalar ile beraber UserControl'ler eklenebilir. Projenize sa tu tklayarak Solution Explorer ierisinden "Add New Item" demeniz ve gelen seeneklerden de "Silverlight User Control" semeniz yeterli olacaktr. Artk isterseniz bu projeyi Blend ierisinde de ap normal bir Silverlight projesindeki gibi animasyonlar vs kullanabilirsiniz. rnek olarak projemize bir resim dosyas ekleyerek UserControl'mz ierisinde de onu gsterebilir. Unutmayn ki resim dosyasn projeye "Add Existing Item" diyerek eklerseniz artk bu resim de DLL'inizin ierisine 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> Yukardaki ekli ile UserControl'mz hazr olduktan sonra projemizi Build ederek DLL'imizi yaratm oluyoruz. Bu DLL'i bir sonraki admda yaratacamz Silverlight projesinin XAP dosyas ile ayn konuma koyabilirsiniz. Silverlight projemiz ierisinden bu DLL'i istemciye asenkron olarak download ederek sahneye DLL ierisindeki UserControl' ykleyeceiz.

112

Gelelim Silverlight projemize... Tertemiz bir Silverlight projesi yarattktan sonra proje ile beraber gelen ASP.NET sitesi ierisinde ClientBin klasrne bir nceki admda yarattmz DLL dosyasn kopyalayalm. Bylece projeyi Build ettiimiz ayn konuma otomatik olarak kopyalanacak olan XAP dosyas zerinden DLL'e de rahatlkla ulaabiliriz. Yeni Silverlight projemizin ana Page.XAML dosyasna bir Button ve bir de Canvas ekleyelim. Bylece dmeye basldnda harici DLL'i ykleyecek ve DLL ierisindeki UserControl'mz de Canvas ierisine yerletireceiz. [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> Dmeye tkland anda hemen bir WebClient yaratarak download ilemimizi balatalm. [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("SilverlightA pplication5.xap", "SilverlightClassLibrary1.dll") Yukleyici.OpenReadAsync(New Uri(Yol, UriKind.Absolute)) End Sub [C#] System.Reflection.Assembly BirAssembly; public Page()

113

{ 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("SilverlightApplicat ion5.xap", "SilverlightClassLibrary1.dll"); Yukleyici.OpenReadAsync(new Uri(Yol, UriKind.Absolute)); } Yukardaki kodu dikkatli incelemek gerekirse ilk admda en stteki Assembly tipindeki BirAssembly adndaki deikenimizi aklamak gerekecek. Kodumuz sunucudan bir DLL indirecek ve iindeki UserControl' sahneye koyacak. Aslnda DLL'i indirdikten sonra ierisinden UserControl1 snfndan bir instance alarak sahneye koyacaz. Eer bu ilemi yaptktan sonra baka instance'lara da ihtiyacmz olursa tekrar DLL'i indirmemek iin eldeki Assembly'yi bir deiken olarak tutmak daha mantkl olacaktr. O nedenle en stteki BirAssembly deikenimiz imdiden yerini alm durumda. Button'umuzun Click koduna baktmzda bir WebClient yarattmz ve OpenReadCompleted event listener'n da baka bir koda baladmz grebilirsiniz. Sunucudan bir dosya indirecei ve indirme ilemi bittiinde de baka iler yapacaz. O nedenle bu event'lar yakalayabiliyor olmak ok nemli. steyenler WebClient'n DownloadProgressChanged event'n da yakalayarak download durumu ile ilgili yzde zerinden ne kadarnn indirildiine dair bilgileri de ekranda gsterebilirler. Sunucudan indireceimiz dosyann tam yolunu verebilmek iin u anki XAP dosyasnn tam yolunu alp sadece dosya adn deitiriyoruz. Bizim rneimizde saten her eyin yeri ve dosya adlar belli olduu iin herhangi bir sorun olmayacaktr. Son olarak OpenReadAsync metoduna da indirilecek olan dosyann yolunu verip download ilemini balatyoruz. Peki ya bu iler bitince alacak olan Yukleyici_OpenReadCompleted metodunda neler yapacaz? [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

114

[C#] AssemblyPart GelenAssembly = new AssemblyPart(); BirAssembly = GelenAssembly.Load(e.Result); UserControl Kontrol = (UserControl)BirAssembly.CreateInstance("SilverlightClassLibrary1.SilverlightControl1"); this.Icerik.Children.Add(Kontrol); Download ilemi bittii anda bir AssemblyPart deikeni yaratarak onun da Load metodunu kullanyoruz. Load metoduna e.result ile aslnda Yukleyici_OpenReadCompleted eventlistener'na gelen argman zerindeki datay alm oluyoruz. Yani znde sunucudan indirdiimiz DLL'in Stream'i e.result ierisinde saklanyor ve biz de bu AssemblyStream'i dorudan bir AssemblyPart zerinden Load ederek Assembly tipindeki BirAssembly deikenimize yklyoruz. Hatrlarsanz zaten bu deikenimiz de global anlamda srekli hafzada tuttuumuz bir deikendi. Bir sonraki admda bir UserControl deikeni tanmlayarak bunu da Assembly'miz ierisinde SilverlightControl1'e eitlememiz gerekiyor. Assembly zerinden CreateInstance metodu bizden yaratlacak nesnenin TypeName'ini istiyor. Silverlight Class Library projesinin ierisindeki UserControlmzn tipinin adn full path olarak veriyoruz. Bunu zaten UserControl'n XAML dosyasnn en stnden de bulabilirsiniz. Artk elimizdeki Kontrol deikeni yine elimizdeki BirAssembly'nin ierisinden SilverlightControl1'in bir instance'dr. Herhangi bir UserControl gibi bu da alp sahnede istediimiz yere yerletirebiliriz. Hepinize kolay gelsin.
DaronYNDEM

115

Silverlight 2.0 ierisinde harici dinamik XAP (Silverlight 2.0) uygulamalarnn asenkron yklenmesi. Dinamik olarak Silverlight 2.0 uygulamalarnda farkl XAP dosyalarn istemci tarafna ykleyerek ana XAP ierisinde gsterebiliyor olmak kullanc deneyimi asndan byk nem tayor. erisinde youn animasyonlarn ve belki de harici kontrollerin bulunduu bir arayz Silverlight uygulamas istemciye ilk gnderildiinde topluca gndermek doru olmayabilir. Bu durum hem ana Silverlight uygulamasnn istemcide alma sresini uzatacak hem de belki kullancnn hi kullanmayaca uygulama blmlerinin gereksiz yere kullancya gnderilmesine neden olacaktr. Tm bu nedenlerle dinamik olarak harici XAP dosyalarn, yani Silverlight uygulamalarn baka bir Silverlight uygulamas ierisine ykleyerek altrabilmek byk nem tayor. Sonraki rneimizde dinamik XAP ykleme ilemini nasl yapabileceimizi inceleyeceiz. Projemizi hazrlayalm... lk olarak Visual Studio ierisinde yeni bir Silverlight projesi yaratarak beraberinde bir de ASP.NET uygulamas yaratlmas iin ilk alta gelen uyar kutusunda gerekli iaretlemeyi yapalm. Bu standart prosesi atlattktan sonra artk Visual Studio ierisindeki Solution'mza yeni bir Silverlight projesi daha eklememiz gerekiyor. Toplam olarak Solution ierisinde bir ASP.NET ve iki Silverlight projesi bulunacak. Solution'a Solution Explorer ierisinde sa tu ile tklayarak gelen menden "Add / New Project" yeni bir Silverlight projesi seerek ekleyebilirsiniz. Ekleme ilemini yaparken size aadaki ekilde bir pencere ile eklenen Silverlight uygulamasnn Solution ierisinde bir ASP.NET sitesi ile ilikilendirip ilikilendirilmeyecei sorulacaktr. Bu noktada var olan uygulama ile yeni Silverlight'mz ilikilendirmemiz gerekiyor, bylece Visual Studio ierisinde F5'e bastmzda bu Silverlight uygulamas da compile edilerek ASP.NET sitesi ierisine kopyalanacaktr.

116

kinci Silverlight uygulamamz Solution ierisine eklerken... Sonradan yklenecek Silverlight uygulamamz hazrlayalm... lk olarak uzaktaki (remote) Silverlight uygulamamz hazrlayalm. rnek olmas ve konudan ok uzaklamamak adna uygulamamz ok basit olacak fakat unutmayn ki uzaktaki Silverlight uygulamas video gsteren veya belki de harici kontroller (DataGrid) kullanan bir uygulama da olabilirdi. Byle bir durumda kardan yklenecek uygulamamz ok daha byk bir boyuta sahip olurdu. Biz imdilik uygulama ierisinde toplama ilemi yapan iki TextBox ve bir de Button bulunsun. Bylece ana uygulamada toplama ilemi yaplaca zaman bu harici uygulamay ykleyerek kullancnn istediini yapmasn salayalm. [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>

117

</UserControl> Uygulamamzn XAML kodu yukardaki ekilde sonlanyor. imdi geelim arkaplanda alan ve basit bir ekilde toplama ilemi yaparak sonucu dmenin zerine yazdran 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 uygulamamz hazrlayalm... Sra geldi gerektiinde uzaktaki Silverlight uygulamamz ykleyerek kullancnn kullanmasn salayacak olan ana uygulamamz gelitirmeye. Bunun iin yine basit bir rnek olarak uygulamamz ierisine bir StackPanel yerletirelim. Sz konusu StackPanel ierisinde imdilik uzaktaki uygulamamzn yklenmesini salayacak olan bir dme 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 ilemi iin tkla" x:Name="Dugme"/> </StackPanel> </UserControl> Uygulamamzn tasarm da hazr olduuna gre artk dmeye basldnda alacak kod ksmna geebiliriz. Dmemize tklandnda bir WebClient kullanarak sunucudan dier uygulamann XAP dosyasn istemci tarafna yklememiz gerekiyor. [VB]

118

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 satrnda bir WebClient yarattktan sonra WebClient'n OpenReadCompleted event'n da bir event-handler'a balyoruz. Sonrasnda da OpenReadAsync metodu ile uzaktaki XAP dosyasn istemciye indirmeye balyoruz. ndirme ilemi tamamlandnda event-handler kodumuz alacak. imdi esas ilemleri yapacamz, XAP dosyas istemciye indiinde alacak olan event-handler kodumuza geelim. [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 bakta biraz kark gelebilir fakat aslnda ok basit. Her Silverlight uygulamas ierisinde (XAP dosyas ierisinde) bir AppManifest.xaml bulunur. Bu dosya ierisinde tek tek sz konusu uygulamada kullanlan Assembly'lerin adlar ve ilikili DLL dosyalarnn adlar bulunur. Bizim de hedefimiz uzaktaki uygulamada kullanlm tm

119

Assembly'leri bularak istemci tarafnda bellee yklemek. Aslnda bizim rneimizde tek bir Assembly olduunu biliyoruz fakat eer rnek farkl olsayd ve harici kontroller kullanlm olsayd doal olarak birden ok Assembly olacakt. O nedenle biz daha genel geer bir taktik kullanarak esnek olalm. Yukardaki kod ierisinde bir StreamResourceInfo nesnesine e.Result ile indirdiimiz XAP dosyasn aktaryoruz. Bu StreamResource ierisinden de Application.GetResourceStream ile AppManifest.xaml dosyasn istiyoruz. Dosyay aldmzda Stream'ini de bir StreamReader ile sonuna kadar ReadToEnd ile okuyoruz. Bylece artk 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 admda AppManifest.xaml ierisinde tanml olan Deployment eklini bir Deployment nesnesine eitlememiz gerekiyor. Bunu aslnda elimizde String olarak var olan bir XAML' .NET nesnesine evirme olarak deerlendirebilirsiniz. Markup.XamlReader.Load metodu ile elimizdeki dosyay okutarak gelen nesneyi de Deployment'a Cast ediyoruz. Zaten uzaktaki (remote) uygulamamz Compile ettiimizde oluan XAP dosyasnn ierisine girerek AppManifest.xaml'na baktmzda da aadaki XAML ile karlayoruz. [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> Sra geldi artk Deployment ierisindeki tm Assembly'leri gezerek hepsini istemci tarafnda hafzaya yklemeye. Tm bu yklemeleri yaparken aralarndan SilverlightRemote.dll adnda olan bir kenara ekerek referansn ayr bir deikende tutacaz. Bunun yapmamzn nedeni ise bu DLL ierisindeki Page snfndan bir adet treterek sahneye almak zorunda olmamz. Assembly'leri hafzaya yklesek de iin grsel ksmn sahneye almamz lazm. Bunun detaylarna birazdan deineceiz, nce bir Assembly'leri tek tek ykleyelim. [VB] Dim GorselAssembly As System.Reflection.Assembly = Nothing

120

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); } } Satr satr yukardaki kodumuzu inceleyelim. lk satrda Assembly tipinde bir deiken yaratyoruz. Bu deiken gerektiinde bizim uzaktaki uygulama ierisinde grsel arayz tanmlayan Page snfnn bulunduu DLL'in referansn tayacak. Sonrasnda hemen Deployment nesnemiz olan Dagitim'n Parts dizisinde bir ForEach dngs balatarak tm Assembly'leri gezmeye balyoruz. Her Assembly'nin Source'unu yani tam DLL dosyasnn adn alarak bu dosyalar tek tek StreamBilgi adndaki deikenimize yklyoruz. XAP dosyas ierisinden DLL'leri alrken ayn AppManifest.Xaml' alrkenki teknii kullanyoruz. Son olarak hemen o an iin zerinde altmz Assembly'nin grsel arayzmzn bulunduu Assembly olup olmadn kontrole diyoruz. Bunun iin dorudan Assembly'e ait DLL adn karlatryoruz. Burada hemen bir dipnot geelim. Bir Silverlight uygulamas ierisinde harici kontrolleri ieren veya farkl snflar ve kodlar barndran DLL'ler bulunabilir. Bunlarn haricinde bir de

121

her XAML (grsel) dosya arkasndaki UserControl tipindeki snflar vardr. Biz yukardaki kodumuzda ierisinde UserControl bulunan DLL'i ayrarak bir kenara referansn kaydediyoruz nk bu UserControl'lar sahneye almamz gerekiyor. Oysa dier Assembly'leri kullanabilmek iin sadece bellee yklememiz yeterli. IF koulumuz ierisinde gerekli kontrolleri de yaptktan sonra normal Assembly'leri Load metodu ile Stream'ini vererek bellee yklerken ierisinde UserControl'lerimizin bulunduu Assembly'i yklerken GorselAsssembly deikenine de bir referansn alyoruz. [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); Sra geldi GorselAssembly ierisindeki ana UserControl'mz olan Page snfndan bir instance olarak sahneye yerletirmeye. Bunun iin Assembly'nin CreateInstance metoduna snfmzn tam yolunu vererek bir kopyasn alyor ve UIElement tipine cast ediyoruz. Sonrasnda da elimizdeki nesneyi uygulamamzdaki StackPanel ierisine ekliyoruz. Artk uygulamamz altrabiliriz. lk Silverlight uygulamas istemciye yklendikten sonra dmeye bastnzda ikinci uygulama sunucudan alnarak ierisinde UserControl sahneye yerletirilecektir. Bylece rahatlkla bir Silverlight projesini paralar eklinde gelitirebilir ve uygulamann blmlerini gerektike istemci tarafna aktarabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

122

Silverlight 2.0 ierisinde Hue / Saturation ve Lightness ile dinamik renk paletleri yaratmann yolu. Silverlight 2.0 ile beraber istemci tarafl CLR altyaps ile aslnda hayal bile edemeyeceimiz bir sr ilemi bildiimiz .NET dilleri ile yapabiliyoruz. Birazdan yapacamz rnei Silverlght 2.0 ncesi herhangi bir teknoloji ile uygulamaya kaltmzda bir .NET yazlm gelitiricisi iin ok daha ac verici bir sre sz konusu olabilirdi. Oysa dorudan istemci tarafnda .NET kullanm ile ok daha rahat bir platform salanabiliyor. Silverlight 2.0 Beta 1 ierisinde ister farkl User Control yaplar olsun veya ister farkl grsel stiller kullann belirli noktalarda dinamik olarak Gradient yaplar kurmanz gerekebiliyor. te tam da bu noktada bir rengin gei yapabilecei baka uygun bir rengi programatik olarak bulmak ciddi sknt verebilir. Aslnda en basit zm Expression Design gibi programlarda yapabildiimiz; bir rengin Hue / Saturation / Lightness deerlerini deitirmektir. Bylece rengin ana yaps deimese de parlaklk ve k miktar deitirilerek farkl geiler salanabilir ve bu farkl renklerden Gradient'lar dinamik olarak yaratlarak rahatlkla kullanlabilir. Fakat maalesef Silverlight ile beraber gelen yapya baktmzda biz renklerin RGB (Red, Green, Blue) olarak geldiini gryoruz. Peki Hue, Lightness ve Saturation nasl hesaplanyor? Bu konuda live.com'da ufak bir aratrma HSL ile RGB arasnda eviri ilemlerinin nasl yaplacan renmemiz iin yeterli. Maalesef internette bu ii hazr yapan bir kod bulamadm. Ben matematik hesaplamalarn ve sisteminin mantnn detayna girmeden sizinle yazm olduum kodu paylaacam. 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

123

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)

124

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 Yukardaki kodu isterseniz harici bir DLL olarak derleyerek tm projelerinizde kullanabilirsiniz. Silverlight ierisindeki kullanmna da ufak bir rnek ile gz atalm. Aadaki ekilde Silverlight 2.0 uygulamamza bir dikdrtgen ve Slider yerletirerek Slider ile dikdrtgen ierisindeki rengi deitireceiz.

125

<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 alabildii maksimum deere dikkat etmekte fayda var. Bu deer zerinden bizim daha nceki HSL nesnesini kullanarak RengiAc ve RengiKoyulastir metodlarn altracaz. Geelim uygulamann kod ksmna. 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 Yukardaki kod ierisinde ilk olarak dikkat edilmesi gereken nokta bizim global AnaRenk deikenimiz. Bu deiken ierisinde srekli bizim ana rengimiz duruyor ve bu renk zerinden gerekli ilemleri yaparak yarattmz yeni rengi Kutu nesnesinin Fill zelliine atanm SolidColorBrush'n Color zelliine aktaryoruz. RengiAc metodunu kullanrken de Slider'n mevcut deerine gre -0.5 ile 0.5 arasnda bir deer gelmesini salyoruz. Zaten ayn metod kendisine eksi deer verildiinde rengi amak yerine kapatyordu. Bylece rahatlkla renklerin Hue / Saturation ve Lightness zellikleri Silverlight tarafnda dinamik olarak deitirilebiliyor. Bu zellikleri kullanarak sadece tek bir renk zerinden giderek baka renkler de yaratp gzel Gradient yaplar kurabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

126

Silverlight 2.0 ierisinde Isolated Storage kullanm Web uygulamalarnda Cookie kullanm alk olduumuz bir yapdr. Bu yapnn bir benzeri Silverlight 2.0 Beta 1 ile beraber de karmza geliyor. "Isolated Storage" olarak adlandrlan alan sadece Silverlight uygulamanza zel olarak varsaylan ayarlar ile 100KB'lk bir alan istemci tarafnda programcnn kullanmna sunuyor. lk olarak gelin bu alana veri yazma ve okuma ilemlerinin nasl yapldna bir gz atalm. rneimizde uygulamamz ierisinde bir TextBox ve iki Button yer alacak. Buttonlardan birine basldnda TextBox ierisindeki veri Isolated Storage ierisine kaydedilecek dieri ise veriyi silecek. Isolated Storage ierisinde dorudan dosyalar ve klasrler saklayabiliyoruz. O nedenle biz de rneimizde saklamak istediimiz metni bir TXT dosyas eklinde diske kaydedeceiz. Gelin ilk olarak uygulamamzn arayzn aadaki ekilde hazrlayalm. <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 SL" x:Name="DgmSil"/> </Grid> </UserControl> Uygulamamz ilk aldnda Isolated Storage ierisinde daha nce kaydedilmi "deneme.txt" adnda bir dosyann olup olmadn kontrol edeceiz. Eer byle bir dosya varsa ieriini okuyarak dorudan TextBox ierisinde gstereceiz. 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 yapacamz tm ilemleri IsolatedStorageFile.GetUserStoreForApplication() ile mevcut kullancnn alann ele alarak yapacaz. O an iin istemci ilem yapan kullancnn bizim uygulamamz iin ayrlm olan alanna ulatktan sonra hemen hedef konumda deneme.txt adnda bir dosya olup olmadn FileExists metodu ile kontrol edebiliyoruz. Eer sz konusu dosya varsa OpenFile metodu ile dosyamz aarak bir StreamReader'a kaynak olarak veriyoruz.

127

Bundan sonras aslnda alk olduumuz dosya okumat metodlar. Eer byle bir dosya yok ise TextBox ierisinde dorudan "Dosya Yok" yazdryoruz. Eer dosyamz herhangi bir klasr ierisinde olsayd gerekli metodlara sadece dosya ismini deil klasr ismi ile beraber bir yol adresini vermek durumunda kalacaktk. Unutmayn tm bu klasrler ve dosyalar bizim uygulamamza ait Isolated Storage alanna saklanyor olacak. Klasr yaratma konusunda zellikle bir uyarda bulunmam gerek. Normal artlarda Windows'ta herhangi bir klasr bo ise diskte yer kaplamaz. Isolated Storage ierisinde her klasr 1KB alan kaplyor. Bunun aslnda mantkl bir aklamas var; kt niyetli Silverlight programclarn istemci tarafnda milyonlarca klasr yaratmasn engellemek :) imdi geelim bir sonraki adma ve elimizdeki metin kutusuna yazlan herhangi bir deeri TXT dosyas olarak Isolated Storage ierisine nasl kaydedeceimizi 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 Yukardaki kod ierisinde yine GetUserStoreForApplication diyerek mevcut kullancnn Isolated Storage alann alyoruz ve sonrasnda CreateFile metodu ile yeni bir dosya yaratyoruz. Yarattmz dosyann ierisine ise bir StreamWriter ile elimizdeki metni yazdryoruz. Kodun en sonunda Istatistik denen bir kodu altrdm greceksiniz. Sz konusu kodu ileriki admlarda yazacaz. Amacmz Isolated Storage ierisinde kullanlan ve kalan alan kullancya gstermek olacak. Artk dosyamz da kaydettiimize gre sra geldi ikinci dmeye basldnda sz konusu dosyay Isolated Storage alanndan silmeye. Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication() If DEPO.FileExists("deneme.txt") Then DEPO.DeleteFile("deneme.txt") End Using Kodumuz gerekten ok basit. Yine mevcut Isolated Storage alanndan yola ekerek FileExists ile dosyann varln kontrol ettikten sonra DeleteFile ile sz konusu dosyay istemciden siliyoruz. Uygulamamzn tam kodunu incelemeden nce bir de Istatistik adndaki kodumuzu yazalm. 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) & ")"

128

End Using End Sub Kullancnn Isolated Storage alann bir deikene aktardktan sonra dorudan Quota ile mevcut kotay, AvailableFreeSpace ile de bo alannn byte olarak alabiliyoruz. rneimizde bu saylar 1024'e blerek kullancya KB biriminde bir istatistik gsteriyoruz. imdi uygulamamzn 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()

129

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 rneimizdeki gibi farkl dosyalar yaratarak Isolatetd Storage alan ierisinde saklayabilirsiniz. Ayrca isterseniz CreateDirectory, DeleteDirectory metodlarn kullanarak istemci tarafnda farkl klasrler yaratabilir, gerektiinde GetDirectoryNames ve GetFileNames ile daha nce kaydedilmi dosya ve klasrlerin isimlerini de birer liste olarak alabilirsiniz. Peki ya 100KB bize yetmezse? Eer 100KB size yetmiyorsa hedef istemcideki kullancnn iznini alarak sz konusu alan arttrabilirsiniz. Bunun iin aadaki gibi bir kod yeterli olacaktr. Using DEPO As IO.IsolatedStorage.IsolatedStorageFile = IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication() DEPO.TryIncreaseQuotaTo(1000000) End Using TryIncreaseQuotaTo metoduna parametre olarak istediiniz alann byte miktarn aktarmanz gerekiyor. Bylece kullancya uygulamann daha fazla alan istediine dair bir uyar gsterilecek onay isteniyor. Eer kulland onay verirse TryIncreaseQuotaTo metodu geriye True dndryor, aksi halde ise False Boolean deeri geliyor. Daha kolay kullanm birey yok mu? Isolated Storage gerekten bize istemci tarafnda mini bir sabit disk verirmicesine olanaklar salyor. Oysa baz durumlarda sadece ufack bir deeri, uygulamayla ilgili bir ayar istemci tarafnda saklamak gerekebilir. Bunun iin tek tek gidip dosyalar yaratmak ve verileri dosyalara kaydetmek uratrc gelebilir. te byle bir durumda zel olarak hazrlanm olan System.IO.IsolatedStorage.ApplicationSettings snfndan faydalanabiliyoruz. 'Mevcut AppSettings nesnesini alalm. Dim Ayarlar As System.IO.IsolatedStorage.ApplicationSettings = System.IO.IsolatedStorage.ApplicationSettings.Default 'Yeni bir ayar ekleyelim

130

Ayarlar.Add("RenkSecimi", "Kirmizi") 'Var olan ayar deitirelim Ayarlar("RenkSecimi") = txtMetin.Text 'Var olan bir ayarn deerini alalm txtMetin.Text = CType(Ayarlar("RenkSecimi"), String) 'Var olan bir ayar silelim Ayarlar.Remove("RenkSecimi") System.IO.IsolatedStorage.ApplicationSettings snf zerinden varsaylan ayarlar bir deikene aktardktan sonra yukardaki rnek kod ierisindeki metodlar kullanarak rahatlkla farkl ayarlar Isolated Storage ierisine kaydedebiliyor, deitirebiliyor ve silebiliyoruz. Hepinize kolay gelsin.
DaronYNDEM

131

Silverlight 2.0 ierisinde Localization kullanm Birden ok dil kullanlan projelerde .NET ile beraber gelen dahili Localization zellikleri hzl zmler yaratmak adna ciddi birer kurtarc olarak deerlendirilebilir. Kiisel olarak her zaman daha zelletirilebilir altyaplara sahip olmak adna el yapm altyaplar tercih etsem de her zaman bunun iin zaman bulunamayabiliyor. Silverlight 2.0 ile beraber de artk .NET dillerini ve altyapsn kullanabildiimize gre bize yardmc olacak bir Localization sistemi olsa gerek diyerek beraberce yola kalm. rn Beta 2 aamasnda olduu iin baz sorunlar radikal zmlerle atlatacaz fakat sonunda tabi ki alr bir rneimiz olacak. Yeni bir Silverlight 2.0 Beta 2 projesi yarattktan sonra hemen Visual Studio ierisindeki Solution Explorer penceresinde Silverlight projemize sa tu tklayarak "Add / New Folder" diyelim ve Resources adnda bir klasr ekleyelim. Uygulamamzda olmasn istediimiz dillere ait bilgileri bu klasr ierisine yerletireceiz. Resources klasrne sa tu ile tklayarak gelen mennden "Add / New Item" komutunu vererek yazilar.resx adnda bir "Resources File" ekleyelim. Karnza kan ekranda Resource dosyas ierisine istediiniz "Name / Value" iftini girebilirsiniz. imdilik rnek olmas amacyla aadaki ekilde dzenlememizi yapalm.

ngilizce Localization Resource dosyamz. Unutmamanz gereken detaylardan biri dosya ile ilgili Access Modifiers ayarsn Public olarak deitirmek. Bu ayar yaptmzda aslnda arka planda otomatik olarak deimesi gereken bir kod daha var. Sz konusu kod Resource dosyamzla beraber otomatik olarak yaratlan Designer.vb veya Designer.cs dosyas ierisinde yer alyor.

132

Arkaplandaki sinsi kod dosyas! Yukardaki ekran grntsnde de grebileceiniz zere Visual Studio ierisinde Solution Explorer'da "Show All Files" dmesine tkladnzda karnza ek dosyalar kacaktr. Bu dosyalardan Resource dosyamzn arkasnda durdan VB/CS dosyasn aarak aadaki kodlar deitirmemiz gerekiyor. Eskisi [VB] Friend Sub New() MyBase.New() End Sub [C#] internal yazilar() { } [C#] public Resource1() { } Yenisi [VB] Public Sub New() MyBase.New() End Sub

Artk sra geldi bu Resource dosyas ierisindeki verileri Silverlight XAML sayfalarmzda kullanmaya. Bunun iin Page.XAML dosyamz aarak 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"

133

Width="400" Height="300"> Yukardaki ekli ile eklediimiz NameSpace aslnda Intellisense destei sayesinde otomatik olarak karnza kacaktr. Eer herhangi bir hata alrsanz projenizi bir kereliine Build ederek sonra tekrar deneyin. NameSpace'in ismini tanmlamak tamamen size kalm ben rnekte "yerel" anahtar kelimesini kullanmay tercih ettim. Son olarak aadaki kod ile Assembly ierisinden kullanacamz kaynamz da sayfann Resource'lar ierisine ekleyelim. <UserControl.Resources> <yerel:yazilar x:Name="LocStrings" /> </UserControl.Resources> Dillere gre metinleri grebilmek iin uygulamamzn arayzne iki adet TextBlock koymakta fayda var. TextBlock'lar da koyduumuzda uygulamann XAML kodu aadaki ekilde sonulanyor. <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 ierisindeki bilgileri bu TextBlock'lara balamamz gerek. Bunun iin klasik bir Binding kullanrken veri kayna olarak da sayfann Resource'larna eklediimiz Kaynak adndaki veri kaynamz kullanacaz. <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> Balama ilemini de tamamladmza gre geri kald ikinci bir dil iin Resource dosyas oluturmaya. Elde olan yazilar.resx dosyasndan bir kopya alarak yaziler.tr.resx adnda bir

134

dosya yaratabilirsiniz. Bu dosya ierisinde de yine Baslik ve Metin kaynaklarnn Trke karlklarn yazmamz gerekecek.

Trke Localization Resource dosyamz. Artk neredeyse her ey hazr. Fakat ufak bir sorunumuz daha var. Visual Studio bizim iin Silverlight projemizin Bin/Debug klasrnde gerekli dillere zel klasrleri yaratarak DLL'leri yaratsa da maalesef bunlar Silverlight'n XAP dosyasna kopyalamyor. Bu ufak hata Silverlight'n Beta 2 sonras srmlerinde dzeltilene kadar bizim Silverlight projemizin .proj uzantl dosyasn NotePad ile aarak elle dzenlememiz gerekiyor. <SupportedCultures>tr</SupportedCultures> Yukarda grdnz ekilde PROJ dosyas ierisinde normalde ii bo olan bu taglarn arasnda kullanacamz dillerin dil kodlarn sralamamz art. Tm ilemlerimizi tamamladk, artk Silverlight uygulamasn sayfaya yerletirirken hangi dil ayarn parametre olarak aktarrsanz o dile uygun kaynaklar yklenecektir. <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> Yukardaki kod ierisinde uygulamann Trke ayarlar ile almasn salyoruz. Hepinize kolay gelsin.
DaronYNDEM

135

Silverlight 2.0 ierisinde maskeleme (clipping) Bu yazmzda Silverlight 2.0 ierisinde maskeleme (clip) ilemlerine gz atacaz. lk olarak basit bir maskeleme ileminin XAML ierisinde nasl yapldna baktktan sonra bu maskeleri nasl anime edebileceimize ve programatik yoldan ulamna deineceiz. Bir maske yaratalm! Herhangi bir nesneye maske aktarmak demek aslnda o nesnenin Clip zelliine uygun bir ekil aktarmak demektir. Elinizde var olan bir geometri nesnesini alarak bir element'in Clip zelliine verdiiniz anda artk sz konusu Geometri nesnesi bir maske grevi grr. Expression Blend ierisinde baktnzda maskeler nesnelerin birer Property'sine atand iin ayr birer obje olarak arayzde gzkmez.

Expression Blend ierisinde maskelenmeye hazr kontroller. Yukardaki ekran grntsnde de grebileceiniz zere sahnede bir Image ve bir de Ellipse nesnesi bulunuyor. Bir sonraki admda amacmz bu Ellipse nesnesini Image iin bir maske haline getirmek. Yapacamz ilem bu iki nesneyi fare ile seip "Objects and Timeline" ksmnda sa tklayp "Path / Make Clipping Path" komutunu vermek. Bylece sz konusu Ellipse artk Image'in Clip zelliine bir geometri olarak aktarlacak ve ortada Ellipse diye bir nesne kalmayacak.

136

Maskelenmi Image kontrolmz karnzda. Artk kontrolmz maskeledik ve Ellipse diye bir nesne kalmad peki arkaplanda XAML tarafnda neler oldu? Gelin Blend'in bizim iin yaratt XAML kodunu bir detaylca 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"/> Grdnz gibi Image nesnesinin uzun bir Clip datas var. Bu data bizim bir nceki admda yarattmz Ellipse'in ta kendisi. Aslnda bu kodu bu ekilde yazmak yerine daha okunakl bir ekilde de yazabilirdik. Nasl 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 deiti? Nesne basnda Clip vermi olduk. Image nesnesinin Clip zelliine dorudan koordinatlar girmek yerine ayr bir element vermeye karar verdik ve bu nedenle de Image.Clip taglar aarak ierisine bir Geometry nesnesi yerletirdik. EllipseGeometry

137

nesnesi gibi GeometryGroup, LineGeometry, PathGeometry nesneleri de mevcut. Bizdeki rnekte EllipseGeometry'nin Center zellii maskelenen Image nesnesinin merkez noktasna gre maskenin ne kadar uzaklkta olacana dair X ve Y deerlerini verirken RadiusX ve RadiusY'de yatay ve dikey olarak Ellipse'in yarapn tanmlyor. Peki bu iki metod arasndaki dier farklar nelerdir? Gelin olayn animasyon ksmna bir bakalm. Maskelere animasyon katalm.... Herhangi bir nesnenin maskesine animasyon verebilmek iin Expression Blend ierisinde animasyon modunda sol taraftaki ara ubuundan Selection arac yerine "Direct Selection" aracn kullanmalsnz. Sz konusu arac setiiniz anda seili nesnenin maskesine ait tanml noktalar ekranda grebilirsiniz. Bylece rahatlkla KeyFrame'ler yaratarak noktalarn pozisyonlarn deitirebilir ve maskeyi anime edebilirsiniz.

Maskemize animasyon verirken. Biz rneimizde maskedeki tm noktalar toplu seerek bir Ellipse ekliden tm maskenin pozisyonunu deitiren bir animasyon hazrlyoruz. Bylece sanki bir k ile resme baklyormu gibi resmin zerinde geziliyor grnts yaratyoruz. Gelin Blend'in bizim iin yaratt XAML koduna gz atalm. [XAML] <Storyboard x:Name="Storyboard1"> <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.St artPoint)"> <SplinePointKeyFrame KeyTime="00:00:00" Value="258.5,130"/>

138

<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.Se gments)[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.Segme nts)[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.Segme nts)[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.Segme nts)[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.Segme nts)[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.Segme nts)[1].(BezierSegment.Point3)"> <SplinePointKeyFrame KeyTime="00:00:00" Value="53.5,130"/> <SplinePointKeyFrame KeyTime="00:00:01" Value="13.937328102718,129.064332728402"/>

139

</PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="image" Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segme nts)[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.Segme nts)[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.Segme nts)[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.Segme nts)[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.Segme nts)[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.Segme nts)[3].(BezierSegment.Point3)"> <SplinePointKeyFrame KeyTime="00:00:00" Value="258.5,130"/> <SplinePointKeyFrame KeyTime="00:00:01" Value="218.937328102718,129.064332728402"/> </PointAnimationUsingKeyFrames> </Storyboard>

140

Animasyonun kodu grdnz gibi epey uzun. Aslnda Blend kendi Clip'ini noktalardan yaratt iin mecburen bu noktalar tek tek anime ederek noktalarn pozisyonlarn deitirmek zorunda kalyor. Bu esnada bizim Image'in XAML kodlarna bakarsan zaten minik bir deiiklik 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> Sz konusu Clip'in iindeki noktalar anime edebilmek iin Blend de ksmen bizim taktie geri dnm ve bir PathGeometry yerletirmi. Oysa biz zamannda Ellipse koymutuk :) Neden dorudan o esnada EllipseGeometry koymadn? diye Blend'e sorarsak eminim cevab basit olacaktr. "Nereden bilebilirim ki bu noktalar ayr ayr anime etmeyeceinizi?" Aslnda Blend hakl. Blend her ihtimali dnmek zorunda nk o bir GUI :) Oysa biz kendi rneimizde maske olarak Ellipse'in eklini deitirmeyeceiz, sadece konumunu deitireceiz o nedenle bu sistem bize ok da uygun deil. Yukardaki PointAnimation taglarna bakarsan tek tek Image nesnesinin Clip zelliindeki deerin alnp bu deerdeki noktalarn Index numaras verilerek bulunduunu ve pozisyonlarnn deitirildiini grebilirsiniz. Performans asndan bir sknts olmasa da oluan kodun okunabilirlilii ok zayf olmakla beraber bu gibi bir Clip nesnesinin programatik olarak anime edilmesi de neredeyse imkansz. C# veya VB kodu ile tek tek bu noktalar bulup anime etmek ikenceden farksz olacaktr. Peki ya bizim teknikle yaparsak? Bizim esas istediimiz maskenin konumunun deimesiydi. Daha nceki kodlarmzda bir EllipseGeometry'yi maske olarak verebilmitik. Bu EllipseGeometry nesnesinin Center zellii maskenin konumunu belirliyordu. Bu durumda bizim kodumuzda bu zelliklerin anime edilmesi yeterli olacaktr. Fakat eer Blend ierisinde bu animasyonu yapacak olursanz bizim EllipseGeometry'yi srarl bir ekilde yukardaki gibi bir PathGeometry'ye evirecek ve yine ayn animasyon kodunu retecektir. Bu durumda bizim de programatik olarak bu maskeyi anime etmemiz yine zorlaacaktr.

141

Sonu olarak eer bir nesnenin maskesinin pozisyonunu ok uramadan kod ile anime edebilmek istiyorsanz Blend'in arayznden anime etmemeniz gerekiyor. Programatik olarak maskeye erimek... Bir nesnenin maskesine programatik olarak erimek iin sz konusu nesnenin Clip zelliini alp uygu Geometry tipine cast edebilirsiniz. Sonrasnda elinizde Geometry nesnesi ile ilgilenmeniz yeterli olacaktr. Oysa bir dier seenek de XAML ierisinde 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> Grdnz gibi basit bir ekilde bizim EllipseGeometry nesnesine bir isim verdik. Artk kod tarafnda bu isim ile EllipseGeometry'ye ulaabilir ve Center veya RadiusX ve RadiusY zelliklerini deitirebiliriz. [VB] Maskesi.Center = New Point(200, 200) Bylece tamamen kod ile bu maskeyi anime etmek istediinizde de rahatlkla bu noktay anime ederek maskenin pozisyonunun deitii bir animasyon retebilirsiniz. rnek bir kodu aada 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);

142

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(); Eer bu animasyonu XAML tarafnda temiz olarak yazmak isterseniz aslnda 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 dorudan Maskesi adndaki EllipseGeometry'yi hedef alarak onun Center property'sini anime ediyor. Unutmayn ki bizim rneimizde byle bir optimizasyon yapabilmemizin nedeni maskenin sadece pozisyonunu deitirmek istememiz. Eer maskedeki her bir noktann konumunu ayr ayr birbirinden bamsz olarak anime etmek isterseniz Blend'in yapt teknikten farkl bir seeneiniz zaten yok. Hepinize kolay gelsin.
DaronYNDEM

143

Silverlight 2.0 ierisinde MultiScaleImage kullanm ve DeepZoom maceralar Silverlight 2.0 ile beraber gelen kontrollerden biri de MultiScaleImage kontrol. Bu kontroln yapabildikleri arasnda gerekten ok ilgin uygulamalar var. Genel itibari ile ok byk boyutta resimlerin istemci tarafnda bant geniliinin en uygun performans ile kulllarak gsterilmesini saladn syleyebiliriz. rnein elinizde ok yksek znrlkte 2GB'lk bir fotoraf var ve bu fotoraf istemci tarafnda gstermek istiyorsunuz veya elinizde toplam 3GB'lk bir fotoraf arivi var ve bunu gzel bir Silverlight galerisi eklinde kullanclarla paylamak istiyorsunuz. Fakat uygulamann alrken doal olarak tm resimleri yklememesi hatta sadece o an ekranda gzken ksmlar yklemesi gerekiyor. Tm bunlar elle tek tek kodlayarak yapabiliriz fakat MultiScaleImage varken aslnda herey ok daha kolay ilerliyor. Deep Zoom Composer MultiScaleImage kontrol ierisinde gsterilecek resimlerin farkl detaylarda gsterilebilmesi ve kullanc resme zoom yaptka yeni detaylarn yklenerek ekranda gsterilebilmesi iin arkaplanda resimlerin biraz detayl bir yapda hazrlanm olmas gerekiyor. Bu ilemleri otomatik olarak yapabilecek bir uygulama olan Deep Zoom Composer' aadaki adresten bilgisayarnza indirip kurabilirsiniz. http://www.microsoft.com/downloads/details.aspx?FamilyID=457b17b7-52bf-4bda-87a3fa8a4673f8bf&DisplayLang=en Yklemeyi yapp yeni bir DeepZoom projesi yarattnzda programn arayzndeki "Add Image" dmesi ile projeye istediiniz kadar resim ekleyebilirsiniz. Eklediiniz bu resimleri "Compose" sekmesinde sahneye srkleyerek istediiniz ekilde resimleri i ie veya st ste koyabilirsiniz. Resimleri ufaltabilir veya bytebilirsiniz. Unutmayn ki burada bir resmi dierine gre ok ufak yerletirseniz de kullanc birazdan hazrlayacamz uygulamada zoom yaparak tm detaylar grebilecek. Yani bir insan resmi koyup gznn iine de ufack grnecek ekilde aslnda 5MB'lk kocaman bir fotoraf yerletirebilirsiniz. Kullanc resmi ilk atnda bu fotoraf insann gznn iinde ufack olduu iin tamamen yklenmeyecek ve sadece gzkt kadar istemciye gnderilecektir. Oysa kullanc zoom yaparak gzn iine girip byk fotoraf grmeye baladnda ise detaylar yklenerek fotorafnz tm znrl ile net bir ekilde gzkecektir. DeepZoom Composer'n kullanm ile ilgili detayl bilgiyi sevgili Turhal Temizer'in yazsndan edinebilirsiniz.

144

DeepZoom Composer ierisinde fotoraflarmz. Biz uygulamamzda yukardaki gibi fotoraflar sahneye ekleyip sa tu ile gelen menden de tm fotoraflar "Arrange to Grid" diyerek bir tablo ierisindeymi gibi hizalatalm. Bylece tm fotoraflar yan yana ve alt alta sralanacaktr. Daha nce de bahsettiim gibi isterseniz fotoraflar st ste yerletirme ve farkl tasarmlar yapma ansnz da var. rnein bir mekann duvarndaki reklam ayr bir detayl fotoraf olarak koyabilirsiniz. Bylece kullanc mekan fotorafndaki duvarda yer alan reklama zoom yaptnda aslnda daha detayl farkl bir grsel yklenmeye balayacak ve normalde elde edilemeyen bir detay gsterimi yaplabilecektir. Son olarak DeepZoom Composer ierisinde "Export" blmne geerek artk fotoraflarmzn gerekli ktlarn almak istiyoruz. Export esnasnda zellikle "Output Type" olarak "Export Images" seeneini iaretlemeyi unutmayn. Normalde DeepZoomComposer isterseniz size hazr bir Silverlight projesi de yaratabiliyor fakat bu yazmzda biz kendi uygulamamz hazrlayacamz iin sadece fotoraflarn dzenlenerek gerekli arivin oluturulmasn istiyoruz.

145

DeepZoom Composer arivimiz. Yukarda da grdnz zere gerekli dosyalar bizim iin hazrlanm. Buradaki XML dosyalarn tek tek inceleyebilirsiniz. Aslnda her bir dosya ayr birer XML dosyasna ynlendiriyor bizi. Arive eklediimiz her resim iin ayrca birer XML dosyas yaratlyor ve bu dosyalar ierisinde resimlerle ilgili konum bilgisi gibi detaylar yer alyor. Ayrca her resmimizin farkl boyutlarda kopyalar da klasrler ierisine kopyalanm durumda. Hatta ok byk resimler paralara blnerek ayr ayr dosyalar olarak da kaydedilmi. MultiScaleImage kontrolnn de gc zaten buradan geliyor. Kaynaktaki farkl boyuttaki ve paralardaki fotoraflar gerek zamanl olarak birletirebiliyor ve otomatik olarak ekranda gzken detaya uygun hedef dosyalar istemciye yklyor. Tm gei efektlerini de tabi ki otomatik olarak yapyor. Peki artk kaynak dosyalarmz hazr olduuna gre uygulamamz da hazrlamaya balayalm. Silverlight projemizi yaratalm... Yeni bir Silverlight projesi yaratarak hemen ierisine bir MultiScaleImage kontrol yerletiriyoruz. imdilik tasarm anlamnda farkl birey yapmayacaz. Uygulamamzn XAML kodu aadaki gibi basit bir ekilde sonlanyor. <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 adn verdiim MultiScaleImage kontrolmz programlamaya balayacaz. lk olarak yapmak istediimiz ilemleri bir sralayalm;

146

Fotoraf arivimizi kontrole ykleyeceiz. Fare ile fotoraf arivi ierisinde gezilebilmesini salayacaz Farenin roller' ile zoom ve zoom out yaplabilmesini salayacaz Artistik hareketler yapacaz

Listemizdeki tek tek yaparak ilerleyelim. lk olarak fotoraf arivimizi dorudan kontrolmze balayalm. [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)); Grdnz zere dorudan DeepZoom kontrolmn Source zelliini deitiriyorum ve yarattmz yeni bir DeepZoomImageTileSource nesnesini kendisine atyoruz. Bu esnada bir nceki admda DeepZoom Composer'n bizim iin yaratt arivden dzc_output.xml dosyasn kaynak olarak gsteriyoruz. DeepZoom Composer'n yaratt GeneratedImages klasrn doru olarak alabilmesi iin XAP dosyanz ile ayn konuma kopyalamanz gerekecektir. Fotoraf arivini gezelim. Sra geldi fare ile fotoraflarn arasndaki gezintimize balamaya. Aslnda yapacamz ilem klasik bir Srkle&Brak ileminden farkl deil. Fakat bu sefer srkleyip braktracamz ey aslnda MultiScaleImage kontrolnn ViewPortOrigin'i. Yani bizim bu arive MultiScaleImage aracl ile bak noktamz deitreceiz. [VB] Dim Tasiniyor = False Dim FareKonum As Point Dim DeepZoomOrigin As Point [C#] bool Tasiniyor = false; Point FareKonum; Point DeepZoomOrigin; Srkle ve brak ilemi ncesinde ihtiyacmz olacak global deikenlerimizi yukardaki gibi yaratalm. Sonrasnda toplam farkl event iin kod yazmamz gerekiyor. MouseLeftButtonDown, MouseMove ve MouseLeftButtonUp durumlarnda srkleme ilemini balatp durdurmaya karar vereceiz. [VB]

147

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; } Kullanc fare ile sahneye tkladnda hemen tanma ilemini balattmz iin global Tasiniyor deikenini True yapyoruz. Bylece ileride yazacamz MouseMove kodu durumdan haberdar olabilecek. Bir sonraki admda farenin pozisyonunu ve sonrasnda da DeepZoom kontrolnn o anki orijin noktasn kenara not alyoruz. Bu bilgileri ileriki hesaplamalarmzda kullanacaz. [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;

148

} else { FareKonum = e.GetPosition(this); } } Sahnenin MouseMove durumunda ilk olarak bir tama ilemi olup olmadn kontrol ediyoruz. Eer tama ilemi yoksa FareKonum adndaki ve farenin mevcut konumunu saklayan deikeni yeniliyoruz. Bunu yapmamzn nedeni ileride yazacamz zoom ilemleri. Zoom ilemini yaparken farenin konumuna hep ihtiyacmz olacak. Burada srekli gncel konumu FareKonum'a aktarmak gerekiyor. Eer tama ilemi yaplyorsa bu sefer de DeepZoom kontrolmzn ViewPortOrigin'ini uygun ekilde ayarlamamz gerek. Bu amala kodumuzda yeni bir Point deikeni tanmlayarak farenin mevcut konumu, eski konumu ve eski orijin noktas arasnda 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 tuu brakldnda da tama ilemini sonlandryoruz. Bylece artk fotoraf arivi ierisinde kullanclar rahatlkla gezebilecektir. Sra geldi zoom meselesine. Fare ile Zoom-In ve Zoom-Out Fare ile zoom ilemleri iin farenin roller'n kullanacaz. Detaylar iin Silverlight 2.0 ierisinde fare roller' kullanmayla ilgili buradaki makleyi inceleyebilirsiniz. lk olarak DOM zerinden gerekli eventlar Silverlight ile yakalamamz 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#]

149

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 ierisinde aada kodlar yazmamz gerekiyor. Bu kodlarn ok detayna inmeyeceiz nk bir nceki paragrafta bahsettiim makalede zaten bu konu detaylar ile inceleniyor. Bizim iin bu kodda nemli olan ksm Zoom ileminin yapld satrlar. [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#]

150

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 ierisinde tam olarak hangi koordinatlara geldiini buluyoruz. Sonrasnda da ZoomAboutLogicalPoint metodu ile zoom ilemini yapyoruz. Zoom ilemi esnasnda bizden parametre isteniyor, zoom miktar, zoomlanacak noktann X ve Y koordinatlar. Bylece basit bir ekilde zoom ilemini de zm olduk. Atraksyon zaman! Yaplacaklar listemizde son bir e kald :) "Atraksyon". imdi biraz hareketli bireyler yapalm. Eer uygulamann bandan beridir benimle ayn admlar takip ediyorsunuz u an DeepZoom kontrol ierisinde yan yana ve alt alta sral onlarca fotorafnz var demektir. Peki bu fotoraflar rastgele kartran bir dme eklesek? Animasyonlarla fotoraf dmeye her basldnda rastgele olarak yerlerini deitirseler ho olmaz myd? Belki de sizin

151

istediiniz farkl sralara bile gelebilirler. Hemen kollar svayalm ve XAML'mza basit bir dme 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> Artk uygulamamzn XAML kodu yukardaki ekilde olacak. Dmeye tklandnda DeepZoom kontrol ierisindeki tm resimleri alarak srasn kartrmamz sonra da animasyonlarla yeni konumlara yerletirmemiz gerek. lk olarak resimleri kartracak olan kodu yazalm. [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 ierisinde tm resimler birer MultiScaleSubImage olarak bulunuyor. DeepZoom ierisinden tm listeyi alp ierisindeki her resmi listeden kartp yeni bir rastgele indeks ile ekliyoruz. Bylece her seferinde sralamay rastgele deitirmi olduk. Sra geldi bu sralama ile resimleri sahnedeki yeni konumlarna birer animasyon ile gndermeye. [VB]

152

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; } } } Yukardaki kodumuzun orta ksmnda birazdan her resmi farkl bir konuma animasyon ile gnderen kodu yazacaz. Fakat onun ncesinde kodun ana yapsn bir inceleyelim. Resimler yan yana ve alt alta sralayacamz iin aslnda bir Grid yapsnda grsellik yaratm olacaz. Kodumuzda KolonSayisi ve SatirSayisi deikenleri ka kolon ve satrlk bir sralama yaplacan belirliyor. ToplamEklenen deikeni ise o ana kadar ka fotoraf eklediimizi hafzada tutacak, bylece dng ierisinde eklenen toplam fotoraf says elimizdeki fotoraf saysna ularsa dngden kacaz. imdi gelelim fotoraflar yeni konumlarna gnderecek animasyonlar yaratacak kodumuza.

153

[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 yaratalm 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 yaratalm 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);

154

Anim.Begin(); Kodumuz biraz uzun gibi gzkse de aslnda znde yaptmz ey ok basit. lk olarak dngmzle oluturduumuz ToplamEklenen says zerinden o anki resmi FotoList ierisinden bir deikene alyoruz. MevcutKonum ve HedefKonum deikenlerimiz ise fotorafn u anki ve animasyonun sonundaki konumlarn saklyor. Yeni konum hesaplarken kolon ve satr aras mesafelerle saylar arparak yeni konumu rahatlkla hesaplayabiliyoruz. Artk hedeflediimiz konum da belli olduuna gre geriye kald eldeki fotoraf hedef konuma tayacak animasyonu yaratmak. Animasyon yapacamz ey fotorafn ViewportOrigin zellii ve bu zellii Point tipinde. Bu nedenle PointAnimationUsingKeyFrame kullanarak hedef KeyFrame'i yaratacaz. Kodumuzda baktmzda KeyFrame adndaki deikenimiz 1 saniye sonra ViewPortOrigin deerini deitiriyor. Ayrca animasyonu ivme vermek iin bir de KeySpline kullanyoruz. Tm bu nesnelerin birbirlerine eklenme ekilleri XAML'da bir StoryBoard yaratmaktan farkl deil. Kodumuzun en sonunda artk animasyonumuzu altrmak iin Begin metodunu arabiliriz. Herey bitti Uygulamamz bitti. Artk istediimiz kadar fotoraflarmz arasnda geebilir, zoom yapabilir hatta resimleri bir dme ile animasyonlu bir ekilde kartrabiliriz. Uygulamann tam kodunu aada 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 'Kaynamz balayalm DeepZoom.Source = New DeepZoomImageTileSource(New Uri("NewFolder1/dzc_output.xml", UriKind.Relative)) 'MouseWheel balants yapalm 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

155

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)

156

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 yaratalm 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()

157

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++)

158

{ 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 yaratalm 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);

159

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) { //Kaynamz balayalm DeepZoom.Source = new DeepZoomImageTileSource(new Uri("NewFolder1/dzc_output.xml", UriKind.Relative)); //MouseWheel balants yapalm 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"); }

160

//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.
DaronYNDEM

161

Silverlight 2.0 ierisinde Open File Dialog kullanm Silverlight 2.0 Beta 2 ierisinden normal artlarda uygulamann alt bilgisayardaki dosyalara ulama ansnz olmaz. Bu durum aslnda ok normal bir durum nk Silverlight tamamen internet taraycs ierisinde alyor ve darya karak sisteme ulamas byk bir gvenlik a olurdu. Oysa bizim baz durumlarda Silverlight tarafna sistemimizdeki bir dosyay aktarmak isteyebiliriz. rnein sistemdeki bir video dosyasn kullancnn web sitesindeki Silverlight ile aarak oynatmasn isteyebiliriz. zellikle bu Silverlight uygulamasnn Macintosh tarafnda da alacan dnrsek aslnda Mac iin basit bir WMV Player bile yapm oluyoruz. Peki sistemdeki dosyalara nasl ulaacaz? Tabi ki "Open File Dialog" aracl ile. Uygulamamz tasarlayalm. lk olarak istemci tarafndaki video dosyalarn oynatacak olan uygulamamzn ana ekran tasarmn yapalm. Sahnede ad Video olan bir MediaElement ve bir de Button bulunacak. Dmeye basldnda Open File Dialog aracl ile istemcide video dosyalarndan birini alacaz. <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 Dmemize basldnda ilk olarak yeni bir Open File Dialog yaratacaz sonrasnda da nesnemizin zelliklerini tanmlayacaz. [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();

162

Kod ierisinde Open File Dialog'un ilk olarak Filter zelliini tanmlyoruz. Aslnda buradaki kullanm Windows Forms'daki kullanm ile neredeyse ayn. Bizim rneimizdeki filtrede kullancya sadece WMV dosyalarn setiriyoruz. Bir sonraki admda Open File Dialog nesnemizin Multiselect zelliinide False yaparak bir defada sadece bir dosya seilebilmesini de saladktan sonra artk Dialog'u ekranda gstermek iin ShowDialog metodunu arabiliriz. [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); } Kullanc Open File Dialog'u kapattktan sonra herhangi bir dosyann seilip seilmediini SelectedFile zellii zerinden kontrol ederek eer dosya seilmi ise OpenRead metodu ile dosyay okuyabiliyoruz. Biz okuduumuz dosyay MediaElement'in Source'una aktaracamz iin ilk olarak aktarma sonras hemen video oynatlsn diye MediaElement'in AutoPlay zelliini True yapyoruz. Son olarak da SetSource metoduna elimizdeki dosyay aktaryoruz. Bylece artk video dosyas MediaElement ierisinde oynatlyor olacak. Unutmayn videoyu sunucuya almadk, hala tamamen istemci tarafnda alyoruz. Birden ok dosya okuyalm Open File Dialog'un MultiSelect zellii True olduunda birden ok dosya seilerek ilem yaplabiliyor. Bu konudaki rneimizde sahnede bir TextBox ve bir dme bulunacak. Dmeye tklandnda sistemden kullanclarn istedikleri kadar fazla sayda TXT dosyas seebilecekler. Bu dosyalarn hepsinin ieriini arka arkaya TextBox ierisine yerletireceiz. [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#]

163

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; } } Yukardaki kod ierisinde her zamanki gibi Open File Dialog nesnemizi oluturarak uygun filtreyi tanmlyoruz. Dikkat etmemiz gereken nokta Multiselect zelliinin True olarak ayarlanm olmas. Dosyalar seildikten sonra SelectedFiles listesinden her bir dosyay tek tek alarak OpenText metoduyla dosya ierisindeki yazy okuyarak txtMetin adndaki TextBox nesnemize aktaryoruz. Hepinize kolay gelsin.
DaronYNDEM

164

Silverlight 2.0 ierisinde ProgressBar kullanm. .NET Framework'n ufak bir paketini ierse de Silverlight ile web taraycs ierisinde byk mucizeler yaratmak mmkn. .NET'in JavaScript gibi scripting dillerine kyasla ilemci kullanmndaki hakimiyetini de dndmzde istemci tarafnda yapacamz ilemlerin younluun artaca kesin. Tm bu ilemler sresince tabi ki kullanclar da bilgilendirmemiz gerekiyor. AJAX ile az ok web tarafnda da altmz "Loading" GIF'lerinin yerine Silverlight tarafnda RC0 ile beraber artk ProgressBar kontrolmz 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' yukardaki XAML kodu ile uygulamanza ekleyebilirsiniz. Aslnda Silverlight ierisinde ProgressBar'n Winforms'daki muadilinden ilk bakta pek bir fark yok. ProgressBar'n Value zellii o anki deeri, Maximum zellii ise alabilecei en yksek deeri tanmlyor. Gelin ufak bir rnek yapmak iin bir DispatcherTimer kullanalm. Timer'mzn iki saniyede bir ProgressBar' biraz ilerletsin. Bylece ilem yaplyormu 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

165

End Class Yukardaki kod ile Progress adndaki ProgressBar'mz oynattmzda aadaki grnt ile karlayoruz.

ProgressBar i banda. Eer gerekten yaplacak ilemin ne kadar srecei bilmiyorsanz ve bir ekilde bu bilgiyi kullancya gsterme ansnz yoksa bu sefer de ilemin srdne dair bir gsterge olarak ProgressBar' kullanmak iin IsIndeterminate zelliini True olarak ayarlayabilirsiniz. <ProgressBar Height="28" VerticalAlignment="Top" Margin="40,58,29,0" x:Name="Progress" IsIndeterminate="True"/> Byle bir durumda ProgressBar ierisinde srekli olarak ayn animasyon altrlacaktr.

ProgressBar sonsuz dngde! ProgressBar'n grselliini deitirmek iin Foreground ve Background zelliklerinden faydalanabilirsiniz. Foreground zellii ProgressBar ierisinde dolu ksmlar etkilerken Background ise ProgressBar'n bo olan ksmlarn etkileyecektir. <ProgressBar x:Name="Progress"> <ProgressBar.Background> <ImageBrush ImageSource="Garden.jpg"/> </ProgressBar.Background> </ProgressBar>

166

rnein yukardaki kod ile aadaki ekilde bir ProgressBar'n fonuna bir fotoraf yerletirebilirsiniz. Hatta Background iin bir ImageBrush yerine VideoBrush kullanarak farkl uygulamalar da oluturulabilir. Burada zellikle Indeterminate ile ilgili dikkat etmek gerek. Indeterminate aktif hale geldiinde Silverlight ierisinde ProgressBar'n ForeGround'u ile tm kontrol kaplanyor ve zerinden beyaz dikey Gradient'lar animasyon ile geiriliyor. Bu sistem ancak ProgressBar'n ControlTemplate'i zelletirilebilirse deitirilebiliyor aksi halde tm standart ProgressBar kontrolleri bu ekilde alyor. Hepinize kolay gelsin.
DaronYNDEM

167

Silverlight 2.0 ierisinde sa tu mensn deitirmek. Silverlight uygulamalarnda sa tu uygulamaya tkladmzda karmza Silverlight'a ait zel "Silverlight Configuration" mens gelir. Bu menden kullanclarn Silverlight uygulamas ile ilgili ayarlar yapabilecekleri bir arayze ulalr. Fakat baz durumlarda farenin sa tuunu biz de kullanmak isteyebiliriz. Bu ister global anlamda tm sayfay kapsayacak ekilde olsun ister belirli Silverlight kontrolleri iin olsun istersek sa tu ile gelen meny deitirme ansmz var. Menmz ve animasyonlar hazrlayalm. Silverlight uygulamamzda sa tu ile tklandnda gsterilmek zere hzlca bir men hazrlayalm. Menmzde birden ok dme bulunacak. Dmeleri dikey olarak sahnede sralamak iin Menu'ye ait kk element olarak bir StackPanel kullanacaz. <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> Yukardaki XAML kodu ierisinde Menu1 adnda bir StackPanel bulunuyor. StackPanel ierisinde tm dmeler dikey olarak hizalanacak. Bu StackPanel'i duruma gre sahnede gsterecek veya saklayacak olan animasyonlarmz da hazrlayalm. Animasyonlar basit bir ekilde StackPanel'in Opacity zelliini deitirecekler. <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> Sra kodlamada... Uygulayacamz taktik aslnda ok basit; Silverlight uygulamasnn ierisinde bulunduu sayfann oncontextmenu event'n yakalayarak normal alma eklini iptal edip men gsterme ilemini biz stleneceiz. lk olarak sz konusu event' uygulama alnda yakalayalm. [VB]

168

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 ierisindeki SagTus adndaki event-handlermz da hemen yazalm. [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 alyoruz ve sz konusu konuma Menu1 adndaki StackPanel'imizi tayoruz. Bizim rneimizdeki Silverlight uygulamasnn kk elementi bir Canvas olduu iin tama ilemini StackPanel'in Canvas.Left ve Canvas.Top zelliklerini deitirerek halledebiliriz. Bir sonraki admda meny grnr hale getirecek olan MenuGel animasyonunu altrp, args zerinden PreventDefault metodunu altrarak sz konusu event-handler'n tarayc tarafndan deerlendirilmesini engelliyoruz. Bylece tarayc bu event altnda herhangi bir men gstermeyecek. [VB] Private Sub Page_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Me.MouseLeftButtonDown

169

MenuGit.Begin() End Sub [C#] void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { MenuGit.Begin(); } Son olarak uygulamann herhangi bir yerine tklandnda meny saklayacak olan MenuGit animasyonunu altryoruz. Bylece istediimiz gibi sa tu ile gelecek olan meny ayarlayabilir, tasarmn deitirebiliriz. Hepinize kolay gelsin.
DaronYNDEM

170

Silverlight 2.0 ierisinde ScrollViewer kullanm. Herhangi bir ierii Silverlight 2.0 arayzlerinde gstermek istediinizde zellikle veri balanabilir ou kontroln kendi ierisinde "ScrollBar" (Kaydrma ubuklar) ierdiini grebilirsiniz. Fakat baz durumlarda bu hazr kontrolleri kullanmadnzda veya scrollbar zellii bulunmayan baz yap ta niteliinde kontrolleri beraber kullanmak istediiniz ayrca bir ScrollBar'a ihtiyacnz olabilir. Bu gibi durumlarda bize scrollbar zellikleri ekleme konusunda ScrollViewer kontrol yardmc oluyor. Yapacamz ilk rnekte 1024*768 piksel byklnde bir resmi uygulamamza ekleyeceiz. Fakat biz bu resim nesnesini tam ekran gstermek istemiyoruz. Uygulamamz ierisinde ufak bir karede gstererek insanlarn istiyorlarsa ScrollBar'lar aracl ile resmi gezmesini istiyoruz. Bu durumda aslnda yapmamz gereken ok basit. Aadaki XAML kodunu yaratacak ekilde Image nesnemizi bir ScrollViewer ierisine yerletirmemiz 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> Grdnz gibi ScrollViewer nesnemizin ierisinde kocaman bir resim var. ScrollViewer ierisine programatik olarak farkl nesnelerin de yerletirilebiliyor olabilirdi. O nedenle biz ScrollViewer'a ait HorizontalScrollBarVisibility ve VerticalScrollBarVisibility zelliklerini de Auto yaparak ScrollBar'larn sadece gerektiinde gzkmesini saladk. Zaten varsaylan ayarlar ile maalesef yatay ScrollBar gsterilmiyor o nedenle her halkarda bu ayarlar deitirmek art.

171

ScrollViewer kontrol i banda. Kullanmn ne kadar basit olduunu sanrm daha da anlatmaya gerek yok. Gelin biraz daha kark bir rnee doru yola kalm. Varsayalm ki ScrollViewer ile beraber gelen kaydrma ubuklar yerine kendi oluturduunuz baz dmeleri kullanarak kaydrma ilemi yaptrmak istiyorsunuz, bu durumda ne yapabilirdik? lk olarak rneimizin grsel ksmn hazrlayarak uygulamamza iki dme ekleyelim. Bu dmeler rahatlkla farkl grsellikler atanarak daha anlaml hale getirilebilir. Ben odak noktamz kaybetmeme adna dmelerin grsel zellikleri ile ilgilenmeyeceim. <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">

172

<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="Aa" x:Name="Asagi"/> </Grid> </UserControl> Kodumuz ierisinde nemli birka nokta var. Bunlardan ilki ScrollViewer kontrolmzn VerticalScrollBarVisibility ve HorizontalScrollBarVisibility zelliklerinin Hidden olarak ayarlanm olmas gerektii. Eer bu zellikleri Disable olarak ayarlarsanz maalesef birazdan yapacamz ekilde ScrollViewer'n kaydrma zelliklerinden faydalanamayz. Oysa biz iimizi olabildiince basite indirgemek ve kolaylatrmak istiyoruz. O nedenle bu zellikler Hidden olmas ve ScrollViewer'dan faydalanmamz art. Bu haldeyken zaten ScrollBar'lar hibir ekilde gzkmeyecektir. Sahnemizde ayrca iki adet de dme var. Bu dmelere her basldnda bir miktar scroll yaptrmak istiyoruz. Aslnda bizim rneimizde hem yatay hem de dikey kaydrma ubuklar gerektii iin toplam drt dme gerekirdi. Fakat ben imdilik sadece dikey kaydrma ubuunu simle edeceim, ayn sistemi yatay iin kullanmak size kalyor. 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 dmelerimize yukardaki ekilde kodlarmz yazdmzda dmelere her basldnda ScrollViewer ierisindeki resim 10 piksel yukar veya aaya doru kayyor. Kodumuzu incelediimizde basit bir IF kontrol ile ScrollViewer'n ykseklik olarak kaydrlabilip kaydrlamayacan reniyoruz eer ScrollableHeight sfrdan byk ise demek ki kaydrma ilemi yapabiliriz. Kaydrma ilemini yapabilmek iin mevcut VerticalOffset zerinden konumu alarak zerine 10 piksel ekleyip veya kartp bu konuma scroll edilebilmesi iin de ScrollToVerticalOffset metodunu kullanyoruz. Bu metod alm olduu Offset deerine scroll ediyor. Daha kaygan bir Scroll olmaz m? Yukardaki rneimizi denediinizde dmeye her bastmzda 10 piksellik bir kayma greceksiniz. Bu durum sizi de benim gibi rahatsz ettiyse daha ho bir zme doru ilerleyebiliriz. Rahatszlk yaratan aslnda iki konu var, birincisi kullanc kaydrma ilemine

173

devam etmek iin milyonlarca kez dmeye tklamak zorunda. Bu hi de ho bir durum deil. Oysa biz dmeye tkland an yakalayp kullanc dmeyi brakana kadar kaydrmaya devam etsek sper olurdu. Dmeye fare ile tkland ve brakld anlar yakalamak iin rahatlkla MouseLeftButtonDown ve MouseLeftButtonUp eventlarn kullanabiliriz. Tek yapmamz gereken bu arada srekli kaydrma ilemi yapmak. Hatta bu kaydrma ilemini de 20 milisaniyede 1 piksel eklinde yaparsak aslnda ok daha ho bir kaydrma efekti yaratm oluruz. Peki tm bunlar nasl yapacaz. Silverlight 2.0 Beta 1 ile beraber gelen DispatchTimer nesnesini kullanacaz. Bu aslnda bizim bildiimiz Winforms'daki Timer'dan pek farkl deil. Esasen tek fark istemci tarafnda farkl bir Threat ierisinde alyormu gibi davranmas. Dim Timer As Windows.Threading.DispatcherTimer lk olarak yukardaki ekilde Timer deikenimizi global olarak tanmladk. Global tanmlamamzn nedeni hem MouseLeftButtonDown hem de MouseLeftButtonUp durumlarnda bu Timer'a bavuracak olmamz. Aslnda yapacamz esas ilemi Timer' MouseLeftButtonDown durumunda yani kullanc dmeye basnda balatmak ve MouseLeftButtonUp durumunda ise yani kullanc dmeyi braktnda 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 Yukardaki kodumuzu dmemizin MouseLeftButtonDown durumuna yazyoruz. Kullanc dmeye tklad anda global deikenimize yeni bir DispatchTimer nesnesi aktararak Interval deerini 20 milisaniye olarak dzenliyoruz. Byleceher 20 milisaniyede bir bir sonraki admda DispatchTimer nesnesine baladmz Tick event-handlar altrlyor olacak. Tm ayarlarmz tamamladktan sonra DispatchTimer'n Start metodu ile ilemi balatyoruz. Sub TimerTick(ByVal sender As Object, ByVal e As EventArgs) Scroll.ScrollToVerticalOffset(Scroll.VerticalOffset + 1) End Sub Timer'n her Tick durumunda daha nce kullandmz kodu kullanarak kaydrma ilemi yapyoruz. Bu sefer Tick durumlar 20 milisaniyede bir olaca iin sadece 1 piksellik bir kayma yaratacaz. Private Sub Asagi_MouseLeftButtonUp(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles Asagi.MouseLeftButtonUp Timer.Stop() End Sub Son olarak dmenin MouseLeftButtonUp durumunda ise Timer'mz durdurarak kayma ilemini sonlandryoruz. Uygulamamz hem Asagi hem de Yukari dmeleri iin tamamladmzda kodumuz aadaki ekilde sonulanyor.

174

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 Yukardaki kod ierisinde MouseLeftButtonDown ve MouseLeftButtonUp eventhandlerlarnn sadece birer kere bulunduu dikkatinizi ekecektir. Sz konusu eventhandlerlar her iki dmeye de balam durumdayz. Aslnda her iki dmenin de sadece uygun zamanlarda Timer nesnesini balatmas ve sonlandrma yeterli. nemli olan Timer'n Tick durumunda ieriini yukar veya aaya kaydrlacana karar verebiliyor olmak. Bunun iin de ben rneimde Yukari dmesinin IsFocused zelliinden faydalandm. Eer bir dmeye baslm ise doal olarak sz konusu dme Focus alm demektir. Bylece o an iin hangi dmeye baslmakta olduunu yakalayp one gre ilem yaplabilir. Hepinize kolay gelsin.
DaronYNDEM

Silverlight 2.0 ierisinde Silverlight Toolkit ve TreeView kullanm

175

Silverlight 2.0 ile beraber gelen kontrol says 1.0'a kyasla ciddi miktarda artt. Fakat hala eksikler var! te bu eksikleri Silverlight srmleri arasnda doldurabilmek adna yeni bir proje CodePlex zerinde yaynda. Proje aslnda uzun sredir gelitiriliyor. Fakat daha yeni yeni stabil kontroller sunmaya balad. Aslnda eski AJAX Control Toolkit'e benzetebileceimiz bir yapda ilerleyen Silverlight Toolkit unutmamak gerek ki dorudan Microsoft tarafndan gelitirilmiyor, tamamen ak kaynak kodlar ile gnll programclar tarafndan ilerletilen bu projede baz kontroller stabil olarak iaretlenmiken bazlar ise hala "Preview" konumundalar. te bu ktphane ierisinde stabil olarak iaretlenmi olan kontrollerden belki de en acil ihtiya duyacamz TreeView kontroln bu yazmzda inceleyeceiz. Nasl yklenir? Silverlight Toolkit ierisinde kontrollerden herhangi birini kullanabilmek iin ilk olarak tabi ki sz konusu ktphaneyi CodePlex zerinden indirmeliyiz. Hemen aadaki adresten son paketi indirebilirsiniz; http://www.codeplex.com/Silverlight/Release/ProjectReleases.aspx?ReleaseId=18804 Paketi bilgisayarnza indirdiinizde Binaries klasr ierisinde bulunan Microsoft.Windows.Controls.dll dosyasn yeni yarattnz bir Silverlight projesine Visual Studio ierisinde referans olarak eklemeniz gerekiyor. Paket ierisinde bulunan dier DLL'lere ve dosyalara ileriki makalelerimizde deineceiz. Unutmayn, referans ekleme ilemini dorudan Silverlight projenize yapmanz gerek. Silverlight projenizle ayn Solution ierisinde bulunan ASP.NET proje ile herhangi bir ilikimiz yok. Bu ilemi tamamladktan sonra artk Expression Blend tarafna geerek kontrollerimizi kullanmaya balayabiliriz. Eer Expression Blend ile deil de Visual Studio tarafnda XAML kodlarn yazmak isterseniz tek tek XAML ierisinde NameSpace tanmlarn yapmanz gerekecektir. Expression Blend ile projemizi atktan sonra "Asset Library"e gidip "Custom Controls" tabna getiimizde TreeView kontrol karmza kyor.

176

TreeView kontrol Expression Blend ierisinde karmza kyor! TreeView kontroln Blend ierisinde projenizde herhangi bir XAML dosyasna eklediinizde XAML koduna dnp bakarsanz aadaki ekilde gerekli NameSpace tanmlarnn da yaplm olduunu greceksiniz. Eer Blend kullanmasaydk bu ilemleri Visual Studio ierisinde elle yapmamz 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="clrnamespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls" > <Grid x:Name="LayoutRoot" Background="White"> <controls:TreeView Margin="74,43,133,137"/> </Grid> </UserControl> Nasl kullanlr? Bir TreeView aslnda birden ok TreeViewItem ierir. sterseniz bu TreeViewItem'lar dorudan Expression Blend ierisinde srkle & brak teknii ile TreeView ierisine yerletirebileceiniz gibi isterseniz dorudan kod ile databind ilemleri de yapabilirsiniz. [XAML]

177

<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> Yukardaki kod ierisinde birden ok TreeViewItem ieren bir TreeView gryorsunuz. TreeView altnda toplam adet TreeViewItem varken son TreeViewItem ierisinde bir tane daha TreeViewItem var. Bylece i ie alarak devam eden sonsz dngde bir aa yaps oluturmak mmkn. TreeViewItem'larn Header zelliine gzkecek metin deerini girebileceiniz gibi aslnda farkl Silverlight kontrollerini de Header ierisine koyma ansnz 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> Yukardaki kod ierisinde de grebileceiniz gibi TreeViewItem'lardan birinin Header'nda bir Image nesnesi, yani fotoraf var. Siz uygulamalarnzda farkl fantaziler yaparak isterseniz MediaElement aracl ile video bile koyabilir veya belki de TreeView ierisine bir DataGrid veya Calendar bile koyabilirsiniz. Gelelim tm bu ilemlerin kod ile nasl yapldna. Varsayalm elimizde TreeView'de gstermek istediimiz bir veri var. lk olarak bu veriyi uygun ekilde dzenlememiz gerek. Bizim rneimizde Fiyati ve Adi gibi zelliklere sahip bir snf kullanalm. Her bir TreeViewItem bu snf zerinden oluturulacak. [VB] Class Urun Private PAdi As String Public Property Adi() As String Get

178

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>(); } } Grdnz gibi snfmzn Adi ve Fiyati zellikleri haricinde bir de List tipinden Liste adnda Property'si var. Bunun nedeni aslnda ok basit. Her bir TreeViewItem'n kendi iinde birden ok TreeViewItem olabilir demitik. Bizim her bir rnmzn iin de bu ekilde

179

birden ok rn saklanabiliyor olacak. Verimizi bu ekilde retip TreeView'e DataBind ettiimizde TreeView geri kalan halledecek. Gelin imdi de bizim iin deneme amal olarak geici veri yn yaratacak bir kod yazalm. [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 = "rn" & x, .Fiyati = Rnd() * 1000} For y As Integer = 0 To 5 BirUrun.Liste.Add(New Urun With {.Adi = "rn" & 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 = "rn" + x.ToString(), Fiyati = RastGele.Next(0,1000) }; for (int y = 0; y <= 5; y++) { BirUrun.Liste.Add(new Urun { Adi = "rn" + y.ToString(), Fiyati = RastGele.Next(0, 1000) }); } Liste.Add(BirUrun); } return Liste; } Kodumuz ierisinde toplam 10 adet ierisinde 5'er rn bulunan rn yaratlyor. imdi tm bu listeyi alarak dorudan TreeView'n ItemsSource zelliine aktaracaz. Siz rneklerinizde farkl snflar ve farkl veri kaynaklar kullanabilirsiniz. zellikle LINQ2SQL veya Data Services kullandnz dnrsek zaten elinize bu ekilde hazr 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#]

180

public Page() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Page_Loaded); } void Page_Loaded(object sender, RoutedEventArgs e) { Agac.ItemsSource = Veriyarat(); } Veri balantmz yaptk. Fakat bu TreeViewItem'lar nasl yaratlacak? Fiyati ve Adi adndaki zelliklerin iindeki deerler nerede gsterilecek? te bu noktada XAML tarafna geerek bir ItemTemplate dzenlememiz gerekiyor. Bylece TreeView kendisine balanan veriye gre TreeViewItem'lar yaratrken nasl bir grsellikten yola kacan ve bu grsellik ierisinde gelen veriden hangi deerlerin nerelere yerletirileceini 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> Yukardaki XAML kodu ile aslnda uygulamamz sonlandrm olduk. Peki neler yaptk? lk olarak TreeView'n ItemTemplate'i ierisinde yine Toolkit ierisinden gelen HierarchicalDataTemplate nesnesini yerletirdik. Bu nesne bizim kod tarafnda yarattmz nested yapy alglayarak i ie TreeViewItem'larn yaratlmasn salayacak fakat DataBind yaptmz snflarn hangi Property'sinin baka nested TreeViewItem'larn verilerini sakladn anlayabilmesi iin sz konusu Property'nin adn vermemiz lazm. Hatrlarsanz bizde Urun snfnn Liste adnda bir property'si vard ve tm alt eleri o saklyordu. Biz de burada HierarchicalDataTemplate 'e ItemsSource olarak Liste'yi Bind ediyoruz. Geri kalan kendisi halledecektir. HierarchicalDataTemplate ierisinde dorudan her bir TreeViewItem'n Header bilgisini girer gibi istediiniz Silverlight kontrollerini kullanabiliyorsunuz. Burada yapacanz tasarm her TreeViewItem iin kullanlacaktr. Tabi bunu yaparken Binding'lerimizi de unutmuyoruz

181

ve yerine gre Fiyati ve Adi zelliklerini istediimiz kontrollerin istediimiz zelliklerine Bind ediyoruz. Bizim rneimizde bir StackPanel ierisinde Fiyati ve Adi zelliklerini gsterecek iki farkl TextBlock bulunuyor.

DataBind TreeView rneimiz bitti. Tm verimizi baladmza gre yeri geldiinde seili eyi nasl yakalarz? Her bir TreeView'n kendi SelectedItemChanged event' var. Bu event altnda sz konusu TreeView'n SelectedItem zelliinden seili eyi alabilirsiniz. En nemlisi SelectedItem size aslnda DataBind esnasnda balanan verinin ierisinde bulunan nesneyi dndryor. Yani bizim rneimizde SelectedItem' aldmda elimize Urun tipinden bir nesne gelecek. Gnl daha ne ister? :) Hepinize kolay gelsin.
DaronYNDEM

182

Silverlight 2.0 ierisinde Toolkit'den ViewBox kullanm. WPF'den Silverlight dnyasna geince eksiini hissettiimiz kontrollerin Silverlight Toolkit projesi ile salanmaya alldna dair daha nceki yazlarmda ufak ipular vermitim. Bu sefer de yine Toolkit ierisinde ViewBox kontroln inceleyeceiz. ViewBox hali hazrda WPF ierisinde bulunan bir Layout kontrol. Silverlight tarafnda ise herhangi bir muadilinin olmamas baz durumlarda ciddi sknt yaratabiliyor. Peki nedir ViewBox? ster WPF ister Silverlight tarafnda olun sahnenin plann Layout kontrolleri dediimiz kontroller ile dzenlemek durumundasnz. Bu kontrollerin her birinin birbirinden farkl zellikleri var. Tm bu zellikleri gz nnde aldmzda ViewBox'n esiz olduu nokta ierisindeki tm nesneleri vektrel olarak grsel anlamda tekrar boyutlandrabiliyor olmas. Birka grsel rnek ile konuyu netletirelim. Not: Silverlight Toolkit'i kullanabilmeniz iin CodePlex zerindeki adresten ktphaneyi indirerek ierisindeki Microsoft.Windows.Controls.dll dosyasn projenize referans olarak eklemelisiniz.

183

Grid ierisinde 5 farkl Ellipse'in deien durumlar. Yukardaki gibi bir Grid ierisinde bulunan nesneler Grid'in kenarlarndan olan uzaklarna ve farkl hizalama bilgilerine gre konumlandrlrlar. Bu nedenle Grid'in boyutu deitiinde nesnelerin kenarlara olan uzaklklarn sabit tutabilmek adna nesneler garip ekillerde boyutlandrlr. Oysa biz bu Grid'in boyutlandrrken iindeki grsellii dorudan ayn ekilde bytmesini istiyorduk hem de vektrel olarak. Maalesef Silverlight 2.0 ile beraber hali hazrda gelen ve bu ilevsellii salayacak hibir Layout kontrol yok! Tabi bu durum "Byle bir Layout kontrol yazlamaz" anlamna gelmiyor :) Nitekim yazmlar ve Silverlight Toolkit ierisinden de biz ViewBox kontroln alp kullanabileceiz. ViewBox kontrolmz kullanalm. Silverlight Toolkit'i projenize referans olarak aldktan sonra Expression Blend ierisinde dorudan "Asset Library"'de "Custom Controls" tabnda "ViewBox" kontroln bulabilirsiniz. Bir nceki blmdeki grsel rneimizde kullandmz Grid'i gelin bir ViewBox ierisine yerletirelim.

184

[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="clrnamespace: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> Yukardaki kod ierisinde de grebildiiniz zere elimizdeki Grid'i dorudan alp bir ViewBox ierisinde yerletirdik. Bylece artk ViewBox' tekrar boyutlandrdmzda ierisinde tm grseller vektrel olarak bir btn eklinde kabul edilecek ve o ekilde tekrar boyutlandrlacak.

185

ViewBox gzellii. Grdnz gibi grselde hibir deiiklik yok. Elimizdeki izim vektrel olduu iin bydnde de herhangi bir grsel bozulma olmuyor. Tabi ViewBox' her durumda kullanmak da doru olmayacaktr. rnein Silverlight ekrannzda bir Button varsa (veya herhangi bir kontrol) ve bu kontroln dinamik olarak boyutlandrlmasn istiyorsanz ViewBox yerine Grid'i tercih etmelisiniz. nk Grid Button'un Height ve Width gibi zellikleri zerinden Button'a boyut verirken ViewBox dorudan Button'un grsellii zerinden vektrel olarak bytecektir.

186

ViewBox ve Grid fark. ViewBox zellikleri... Bir ViewBox kontrol ierisinde grsellerin nasl boyutlandrlaca ile ilgili verebileceimiz kararlar var. Bunlardan ilki Strech zellii. Gelin Strech zelliine verebileceimiz deerler arasndaki farklara bir rnek ile bakalm.

ViewBox'n Strech zellikleri arasndaki farklar. Farklar sanrm grselde ak bir ekilde belli oluyor. None deerini verdiimiz Strech zellii ViewBox ierisindeki grsellerin boyutlandrlmamasn salyor. Uniform deeri en/boy orann koruyarak ViewBox'n ierisinde tam sacak ekilde grseli bytrken UniformToFill ise yine en/boy orann korusa da bu sefer ya eni ya da boyu her ekilde ViewBox'n iine en byk deeri ile yerletiriyor. Strech zelliine dorudan Fill deerini

187

verirseniz bu sefer grselin en/boy oran korunmadan tamamen ViewBox'n ierisine yaylyor. Ayrca isterseniz ViewBox'n VerticalAlignment ve HorizontalAlignment zellikleri ile de UniForm modunda ViewBox ierisindeki grselin nasl hizalanacana karar verebilirsiniz. StretchDirection zellii. u ana kadar ViewBox ierisinde grsellerin srekli bydn grdk fakat isterseniz ViewBox'n boyutunu ufaltarak ayn ekilde elinizdeki grseli kltebilirsiniz de. Baz durumlarda ise ViewBox ierisindeki grselin sadece gerektiinde bytlmesini veya sadece kltlmesini isteyebilirsiniz. Bu gibi durumlarda gerekli snrlamalar yapmak iin dorudan StretchDirection zelliini kullanabilirsiniz. Eer StretchDirection deeri UpOnly olursa ViewBox ierisindeki grsel gerektiinde sadece bytlecektir. ViewBox kendi iindeki grselden daha fazla ufaltlrsa iindeki grseli kesinlikle ufaltmayacaktr. Ayn ekilde DownOnly zellii de ViewBox'n kendi ierisindeki grseli gerektiinde sadece ufaltmasn salayacaktr. StretchDirection zelliinin varsaylan deeri Both olarak geldii iin normal artlarda hem ufaltma hem de bytme yapar. Hepinize kolay gelsin.
DaronYNDEM

188

Silverlight 2.0 ierisinde Toolkit'ten Label kontrolnn kullanm. Silverlight ilk kt gnlerde en ok ardmz noktalar biri "Label" adnda bir kontroln bulunmamasyd. levsellik olarak ayn zm sunan TextBlock kontroln ok ksa bir srede kefetmi olsak da neden isminin deitiini pek anlayalamtk. Bugnlerde Silverlight Toolkit paketi ile beraber zel bir Label kontrol geldi. Nedir TextBlock ile Label'n fark? Aslnda kaba tanm ile TextBlock kontrol Label'n yap tadr. Bir Label kontrol ControlTemplating desteklerken TextBlock desteklemez. Zaten Label Template'leri olutururken biz de TextBlock'lardan faydalanacaz. zetle Label'lar gelimi TextBlock kontrolleridir de diyebiliriz. Sz daha ok uzatmadan gelin neler yapabildiimize gz atalm. Not: Silverlight Toolkit'i kullanabilmeniz iin CodePlex zerindeki adresten ktphaneyi indirerek ierisindeki Microsoft.Windows.Controls.dll dosyasn projenize referans olarak eklemelisiniz. Bir Label kontroln Silverlight Toolkit'in referans alnm olduu herhangi bir projede rahatlkla kullanabilirsiniz. Expression Blend ierisinde "Asset Library" ksmnda "Custom Controls" sekmesinde Label kontroln bulabilirsiniz. TextBlock'larda da oluu gibi herhangi bir Label ierisine yaz yazmak iin Content zelliinden 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="clrnamespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"> <Grid x:Name="LayoutRoot" Background="White"> <controls:Label HorizontalAlignment="Left" VerticalAlignment="Top" Content="Deneme Amal Metin"/> </Grid> </UserControl> Basit bir ekilde Label kontrolnn kullanmna dair yukardaki XAML kodunu inceleyebilirsiniz. Bir TextBlock ile Label kontroln birbirinden ayran zelliklerden ilki Label kontrolnn BorderBrush alabiliyor olmas. Hatta sadece bu kadarla kalmayp bir Label'n hangi kenarlarnda Border bulunacana da karar verebiliyorsunuz.

189

Label kontrolnn BorderBrush ayarlar. Ayn ekilde isterseniz bir Label iin Background da belirleyebilirsiniz. Fakat makalemizin bandan beridir bahsettiimiz Label'n en nemli zellii aslnda ControlTemplating'e olanak tanmas. Gelin imdi Expression Blend ierisinde Label kontrolmze sa tklayarak gelen menden "Edit Control Parts / Create Empty" komutunu verelim. Bylece hali hazrda sahnede olan Label'n grsellii yok varsaylarak bizim Label kontrolnn yapsn tekrar tasarlayabilmemiz salanacak. Bunun iin ilk aamada karnza gelen pencerede bu ablona bir de isim vermeniz gerek. Unutmayn hazrlanan ablonlar sonrasnda birden ok Label'a linklenerek merkezi bir yerden kullanlabilir.

190

Label kontrol iin yeni bir ControlTemplate yaratyoruz. ControlTemplate'imizi yarattktan sonra Blend bizi otomatik olarak Template tasarmna gtrecektir. Bu sahnede otomatik olarak gelen Grid nesnesini bir Canvas'a evireceiz. Bu seimi tamamen rnein kolay ilerlemesi iin yapyoruz. Siz kendi tasarmlarnzda farkl Layout kontrolleri tabi ki kullanabilirsiniz.

ControlTemplate tasarmmz bitmek zere. Tasarmmzda Canvas'n ierisinde bir Rectangle koyarak Fill zelliine de Radial bir GradientBrush atadk. Rectangle'n nnde de bir TextBlock koyuyoruz. Label ierisinde metni gsterecek olan bu TextBlock kontrol olacak. Label kontrolnn Content zelliine verilen deerlerin otomatik olarak ablon ierisinde bu TextBlock'un Content'ine aktarlmasn salamalyz. Bunu da ancak TemplateBinding ile yapabiliriz.

191

Blend arayznden TemplateBinding ayarlarmz yapyoruz. Blend'in arayznde ablonumuzu tasarlarken TextBlock kontrolmz setikten sonra ekrann sanda kalan "Properties" sekmesinden sz konusu TextBlock'un Content zelliini ayarladmz yerin hemen yanndaki ufak kareye tklyoruz. Gelen menden "Template Binding" komutunu verdikten sonra Blend bize ana kontroln hangi zelliinin ablondaki bahsi geen zellie balanacan soruyor. Tabi biz de hemen Content zelliini seiyoruz. Bylece Label kontrolnn Content zelliini ablonun iindeki TextBlock'un Content zelliine balam olduk.

192

Template tasarm modundan kalm. Artk tasarmmz tamamladmzda gre ablon tasarm modundan kp ana uygulamaya geri dnebiliriz. Artk Label kontrolnn Content'ini deitirdiinizde ayarladnz grsellik iindeki Textblock'a yerletiini grebilirsiniz. En gzel de yeni bir Label eklediinizde ayn ablonu kullanmasn salayabilirsiniz.

Hazrladmz ablonu istediimiz Label kontrolnde kullanabiliriz. Uygulamanza yeni bir Label ekledikten sonra hazrladnz ablonu bu Label zerinde de kullanmak istiyorsanz dorudan sz konusu Label'a sa tu ile tklayarak gelen mennden "Edit Control Parts / Apply Resource" diyerek ablonunuzu ad ile seebilirsiniz. Bylece

193

geri dnp bu ablonda bir deiiklik yaptnzda birden ok Label'da deiiklik yapm olacaksnz. Merkezi ynetim :) Yaptmz tm ilemlerin sonucunda aadaki XAML kodu yaratlyor. [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="clrnamespace: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> Yukardaki kodda zellikle nemli olan birka nokta var. lk olarak nasl olmu da Label'mz UserControl.Resources altndaki DenemeSablon adl ablona balanm? TemplateBinding'in kodu nasl yazlm? Tm bunlarn cevaplarn kod ierisinde kaln yazl blmlerde bulabilirsiniz. Label'a DataBinding nasl yaplr? Bir Label'e neden DataBind yapmak isteyelim? Sonuta sadece Text gstermeyecek mi? Ve bu Text'in deime ans da yok ki TwoWayBinding vs gereksin? Tm bu sorularn cevab aslnda yukardaki ControlTemplating ile de alakal. Bir Label dnn ki kendisine Bind edilmi nesneye gre ekil alabiliyor? Ne dersiniz? Bir nceki rneimizden devam edelim. Varsayalm ki Label'mzda bir rnn adn gstereceiz fakat rnn sat miktarna gre de Label'n arkasnda Gradient'n (Aslnda

194

Rectangle) effaflamasn veya grnr olmasn istiyoruz. Bunun iin ilk olarak gelin kontrolmzn tasarmn biraz deitirelim.

DataBind yapacamz Label kontrolnn ablonunu biraz deitirdik. Sadece renklerde biraz deiiklik yaptk. Bylece arkadaki Rectangle tamamen effaf olsa da yaz grnebilecek. imdi geelim kod tarafna ve bu Label'a nasl veri balarz ona bakalm. lk olarak Label'a balayacam Urun'mzn bir snf olarak programatik anlamda tanmlamamz 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

195

{ public string Adi { get; set; } public double Satis { get; set; } } Grdnz zere Urun snfmzn iki Property'si var. Bunlardan ilki rnn ismini saklayacak olan Adi, dieri ise Satis miktar. zellikle Satis Property'sinin Double olarak tanmlandna dikkat edelim. Herhangi bir Convertor kullanmadan bu Property'si Bind edeceimiz iin Opacity ile uyumlu ekilde 1 ile 0 arasnda Double deerler tamal. [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 rn ad", .Satis = 0.5} End Sub [C#] private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e) { Etiket.DataContext = new Urun { Adi = "Bir rn ad", Satis = 0.5 }; } Kodumuzda basit bir ekilde yeni bir rn yaratarak Etiket adndaki Label kontrolmze DataContext zellii zerinden balyoruz. Peki Adi ve Satis Property'leri Label ierisinde neleri etkileyecek? te bunun iin ayrca XAML tarafnda ayarlar yapmamz gerek.

Rectangle'n Opacity'sinin DataBinding ayarlarn yapyoruz. Blend tarafnda Label kontrolnn ablonuna tekrar geri dnyoruz. Daha nce yarattmz ControlTemplate'i aarak zerinde deiiklikler yapmamz gerekiyor. lk olarak ablon ierisinde Rectangle' seerek Properties tabndan Opacity'sinin yannda ufak kareye

196

tklyoruz ve gelen menden "Custom Expression" komutunu seiyoruz. Bylece artk binding ile ilgili ayar dorudan el ile yazacaz.

DataBinding iin Custom Expression yazyoruz. Yazdmz Custom Expression ile artk Label kendi iindeki Rectangle'n Opacity deerinin kendisine verilen datadan geleceini ve balanmas gereken Property'nin adnn da Satis olduunu biliyoru. Ayn ilemi ControlTemplate ierisindeki TextBlock iin de yaparak bu sefer TextBlock'un Content zelliini Adi Property'sine {Binding Adi} Custom Expression' ile balamamz gerek. Tm bu ilemleri yaptktan sonra uygulamay altrdnzda baladnz verideki rn adnn TextBlock ierisine yerletiini ve gelen sat bilgisine gre de arkadaki Rectangle'n effaflnn belirlendiini grebilirsiniz. Bylece gelen veriye gre grselliini deitiren bir Label tasarlam olduk. Hepinize kolay gelsin.
DaronYNDEM

197

Silverlight 2.0 ierisinde ToolTip Kontrol ve Tooltip ablonlar zellikle Windows uygulamalarnda "eriilebilirlik" asndan ok nemli olan noktalardan biri de "pucu" balonlardr. "Tooltip" olarak geen bu sistem sayesinde herhangi bir kontroln veya nesnenin zerinde fare ile belirli bir sre durduunuzda gerekli aklama metni gsterilir. Bylece kullanc ufak yardm ynergeleri ile ynlendirilebilir. Silverlight 2.0 Beta 2 iin Tooltip ilevselliini otomatik olarak salayan bir TooltipService snfmz 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 dme"></ToolTip> </ToolTipService.ToolTip> </Button> </Grid> </UserControl> Yukardaki kod ierisinde bir dmeye ToolTipService ekleyerek service de bir ToolTip kontrol aktaryoruz. ToolTip kontrolmzn Content zelliine bir metin aktararak ip ucu olarak bu metnin gsterilmesini salyoruz. Bu ekilde istediiniz Silverlight kontrolne ToolTipService ekleyebilirsiniz.

Basit bir Tooltip. Eer Tooltip'in grnmn deitirmek isterseniz Background, FontSize, FontWeight, Foreground gibi birok zellie sahipsiniz. sterseniz fon rengi gibi zelliklere farkl Brush yaplar 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"

198

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 dme"> <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> Grld zere rahatlkla Tooltip'in grsellii deitirilebiliyor. Bir Tooltip'in fonuna VideoBrush yerletirmeye sizin hayallerinize brakyorum. Tooltip'e ait VerticalOffset ve HorizontalOffset zellikleri ile Tooltip'in fareden ne kadar uzakta gzkeceini de ayarlayabilirsiniz.

zelletirilmi Tooltip Biraz daha ileri giderek ToolTip'in Content zelliine istersek farkl Silverlight kontrolleri de yerletirebiliriz. Content ierisine sadece bir Silverlight kontrol yerletirebilirsiniz fakat bu kontroln ierisinde baka kontroller bulunabilir, yani Canvas veya Grid gibi Container

199

kontrollerini kullanarak farkl grsel emalar yaratabilirsiniz. Aadaki kod ierisinde biraz olay abartarak ToolTip ierisine bir video yerletirdik. <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 ierisinde stream video! zel Tooltip! Tooltip kontrolnn ierisinde gsterilecek Content'i deitirmenin yan sra tamamen Tooltip'in grsel durumunu da deitirebiliriz. rnein yuvarlak bir Tooltip yaplabilir. Bunun iin ilk olarak Tooltip kontrolnn varsaylan Template yapsn MSDN zerinden almamz gerekiyor. Adres u ekilde; http://msdn.microsoft.com/enus/library/cc296244(VS.95).aspx Elimizdeki Template ierisindeki ControlTemplate taglar arasndaki herey bizim Tooltip'in grnt ablonunu oluturuyor. Buradaki Binding'lere dokunmamaya alyoruz. zellikle

200

ContentPresenter' silmememiz gerekiyor nk ToolTip'in Content'na verilen ierik Template ierisinde buraya yerletiriliyor olacak. Gelin farkl bir ey yapalm ve kendi iine konan metni Scrollbar ile gsterebilen bir Tooltip oluturalm. Bunun iin hemen ControlTemplate'i dzenlememiz 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}"

201

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 aklama metni burada olabilirdi."> </ToolTip> </ToolTipService.ToolTip> </Button> </Grid> </UserControl> Yukardaki kodumuz ierisinde ControlTemplate'in dorudan iine bir ScrollViewer yerletirdik ve Template ierisinde ContentPresenter' da ScrollViewer'n Content deerine aktardk. Bylece bu ToolTip kontrolne aktarlan tm Content bir ScrollViewer ierisinde gsterilecek.

Custom Tooltip Siz de bu ekilde farkl ToolTip kontrolleri tasarlayarak uygulamalarnza kullanabilirsiniz.

202

Silverlight 2.0 ierisinde VisualStateManager kullanm. Bugne kadar Silverlight ierisinde herhangi bir dme veya farkl bir kontroln deiik durumlarnda ayr ekiller almas iin maalesef birbirinden bamsz animasyonlar hazrlayarak tek tek gerekli eventlar ile koddan eletirmemiz gerekiyordu. rnein bir dmenin zerine gelindiinde krmz olmas ve bunu ufak bir animasyonla yapmas iin ilk nce animasyonumuzu hazrlyor sonra da dmenin MouseOver event'na event-handlar kodumuzu balayarak animasyonu elle altryorduk. Bu ekilde ok sayda proje yapld. Oysa artk Silverlight 2.0 Beta 2 ile beraber karmza yepyeni bir sistem geliyor : VisualStateManager! Artk bir nesnenin farkl durumlarnda nasl gzkeceini nceden tanmlanm durumlar iin Expression Blend 2.5 arayznden ayarlayabiliyorsunuz. Silverlight bununla kalmayp bu farkl durumlar arasnda gei efektlerini kendisi otomatik olarak yaratarak otomatik olarak oynatabiliyor. Gelin biraz iin iine girip nasl yapldna gz atalm. Animasyonlu bir Button... Expression Blend 2.5 ierisinde sahneye bir Button yerletiriyoruz. Hedefimiz bu Button'un farkl durumlarda fon rengini deitirmek. rnein fare ile zerine geldiimizde dme krmz olsun. Peki bunu Expression Blend 2.5 ierisinde nasl yapacaz?

Dmemizi Template'ini dzenliyoruz.

203

lk olarak sahnedeki dmemizin "Template"'ini dzenlememiz lazm. Dmemizin zaten hali hazrda bir tasarm ve animasyonlar var. Bunlar projenizi altrdnzda grebilirsiniz. Dmenin zerine geldiinizde rengi deiecektir. Biz tamamen sfrdan bir dme tasarlamayacamz iin "Edit Control Parts" mensnden "Edit a Copy" seeneini kullanarak var olan tasarmn bir kopyasn alarak yola devam edeceiz. Eer sfrdan bir dme tasarlamak isterseniz bu ekranda "Create Empty" demeniz gerekecektir.

Dme Template'imize bir isim verelim. Dmemizin "Template"'ini yaratrken Expression Blend bize minik bir soru soruyor. ablonumuz bir "Resource" olarak yaratlacak ve projemizde istediimiz bir isimle istediimiz bir yere konabilecek. Bu ekranda eer "Application" seeneini seersen hazrlayacamz ablonla ilgili tm zellikleri tanmlayan XAML kodu projenin ierisinde App.XAML dosyas ierisinde saklanacaktr. Bylece ablonumuz ayn projedeki tm Page'lerde kullanlabilecek. Eer varsaylan ayar olan "This document" seeneini tercih ederseniz ablonla ilgili XAML kodlar ierisinde altnz Page.XAML dosyasna kaydedilecektir. Bu durumda bu ablonu dier Silverlight sayfalarnzda kullanmanz daha zor olacaktr. Son bir seenek ise harici bir Resource.xaml dosyasnda tm kaynaklar (ablonlar) saklamak olabilir. "Resource dictionary" seenei zerinden yeni bir XAML dosyas yaratarak saklayacanz ablonlarnz bylece birden fazla projede kullanabilirsiniz. Biz imdilik "This document" diyerek ablonumuza isim olarak da "DugmeStil" deerini verelim.

204

Dmemizin farkl durumlarnda tasarm deiiklikleri yapacaz. Yukardaki ekran grntsnde de inceleyebileceiz zere dmemizin ablonuna girdiimiz anda dmemizle ilgili farkl durumlarn listelendii bir "Interaction" penceresi Expression Blend ierisine ekleniyor. Buradan herhangi bir durumu fare ile setikten sonra dme zerinde yapmak istediiniz grsel deiiklikleri gerekletirebilirsiniz.

Dmemizin fon glge rengini deitiriyoruz.

205

Biz rneimizde dmenin zerindeki mavi glgenin rengini deitirmeye alalm. Standart bir dmenin fare ile zerine geldiinde alt tarafa doru ek mavi bir glge geliyor. Expression Blend ierisinde baktmzda bu glge "Background" ad verilen bir Rectangle ile salanm. Sz konusu Rectangle'n Fill rengi aadaki gibi DataBound gzkyor.

DataBound grsel deeri lokal bir deere aktaryoruz. Yukardaki grselde Rectangle'n Fill deerinin tanmland blgenin turuncu bir izgi ile evrelendii grebilirsiniz. Bu durum sz konusu zelliin bir sistem deikenine bal olduu anlamna geliyor. Biz bu deeri deitirmek istediimiz iin Fill zelliinde deerin bir kopyasn almak amacyla "Fill"'in hemen yanndaki ufak kareye tklayp gelen mennden "Convert to Local Value" diyoruz. Artk sz konusu deer bizim ablon ierisine tand, bylece zerinde istediimiz deiiklii yapp glgeyi krmz hale getirebiliriz. Renk paletinden yeni bir renk semeniz yeterli.

206

Transition efektlerini ve sreleri ayarlayalm. Normal artlarda bir dmenin zerine geldiinde yeni grsel duruma gei esnasnda bir animasyon altrlyor, fakat fareyi dmenin zerinden ektiinizde normal haline "annda" geiyor yani herhangi bir animasyon altrlmyor. MouseOver durumundan Normal'e geite de bir animasyon altrlmasn istiyorsanz hemen Blend arayznde "MouseOver" durumunun yanndaki oka tklayarak gelen menden "Mousevoer > Normal" seeneini seerek bu gei esnasnda da bir animasyon yaratlmasn istediinizi belirtebilirsiniz. Bylece krmz hale geite ve eski hale dnte birer animasyon oynatlarak geiler salanacaktr. Bu animasyonlarn srelerini de hemen yanlarndaki 0.2s deerlerini dzenleyerek deitirebilirsiniz. Dikkat dikkat! "MouseOver" veya "MouseLeave" gibi durumlarda grsel deiiklikler yaratrken aklnzda olmas gereken ufak bir ipucu var. Animasyon uygulayacanz nesnelerin her durumda sahnede yer almas gerekiyor. Yani sadece MouseOver durumunda gzkecek olan bir Rectangle'n Normal durumdan MouseOver duruma bir animasyonda kullanlmas mmkn olmaz. Grnmezden grnre doru bir animasyon tasarlayacak olsanz da hedef nesnenin hem balang hem de son durumlarnda sahnede bulunmas gerekiyor. Tek yapacanz balang noktasnda sz konusu nesneyi grnmez ayarlamaktr.

207

ablon dzenleme modundan geri kalm. Arka planda neler oluyor? Maalesef Expression Blend'in yaratm olduu tm XAML kodunu burada yaptrmayacaz, yaklak 180 satrlk bir kod sz konusu. Onun yerine zellikle bizim yaptmz ilemleri ilgili ksmn 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.Co lor)"> <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 ierisinde de grebileceiniz zere MouseOver durumu ierisinde toplam iki adet animasyon var. Bunlardan biri Background'u dieri de BackgroundGradient'i deitiriyor.

208

Ad Background olan animasyon bizim biraz nce Blend arayznden hazrladmz animasyonun ta kendisi. Peki bu animasyon ne zaman nasl altrlacak? te tm bunlara VisualStateGroup.Transitions taglar arasndaki bilgiler karar veriyor. Ka saniyede hangi durumdan hangi duruma gre animasyonlar oynatlaca dorudan bu taglar arasnda belirlenmi durumda. Oynatlacak animasyonlar da zaten her durumun ismiyle ilikilendirilmi ekilde kod ierisinde duruyor. Koddan geileri altrmak istersek? Baz durumlarda hazrlanan bu animasyonlar kod ile de altrmak isteyebilirsiniz. rnein kullancnn tklamas gereken bir dme vardr, fakat tklamyordur :) bu durumda sanki MouseOver olmu gibi bir dmeyi parlatp sndrmek ho olabilir. [VB] VisualStateManager.GoToState(Dugme, "MouseOver", true) [C#] VisualStateManager.GoToState(Dugme, "MouseOver", true); Yukardaki kod ile Dugme adndaki dmemizin MouseOver durmuna gemesini ve arada gerekli animasyonun da oynatlmasn salam oluyoruz. Eer son Boolean parametreyi False olarak verirseniz gei animasyonu oynatlmakszn sz konusu duruma geilecektir. Hepinize kolay gelsin.
DaronYNDEM

209

Silverlight 2.0 ierisinden Download penceresi atrmak. Silverlight 2.0 Beta 2 ierisinde istemci makinedeki herhangi bir dosyaya ulamakla ilgili rneklerimizde Open File Dialog nesnesini detaylar ile incelemitik. Tam ztt bir senaryoda da kullancya sistemine kaydedebilecei bir dosya vermek isteyebiliriz. Bu gibi bir zm iin maalesef Save File Dialog gibi bir kontrole sahip deiliz. O nedenle biraz farkl bir taktik uygulayarak kullancya vermek istediimiz dosyay ilk olarak sunucuya gndererek kaydedeceiz sonrasnda da sunucudan dosyay tekrar istemcinin alarak kaydedebilmesini salayacaz. Bu senaryo ilk bakta ok sama gibi gzkse de aslnda dosya yaratma ilemini sunucu tarafnda yaparsanz herhangi bir performans sorunu olmayacaktr. Gnl isterdi ki dosyay tamamen istemcide Silverlight ile yaratarak kullancya verebilelim. Fakat maalesef imdilik en azndan Beta 2 ierisinde byle bir ansmz yok. Peki hereyi yaptk, dosyamz Silverlight 2.0 Beta 2 ile yarattk, sunucuya bir web servisi aracl ile gnderdik ve kaydettik. Bundan sonrasnda bu dosyay Silverlight ierisinden istemcideki kullancya nasl vereceiz. Kullanacamz taktik aslnda epeyce basit. Tm tarayclarda kullancy dosya downloadu iin dosyann bulunduu adrese ynlendirirseniz hemen "Download" penceresi alacaktr. Kullancnn ierisinde bulunduu web sayfas hala grntlenmeye devam edecektir. Yani aslnda siz kullancy baka bir adrese ynlendiriyor olsanz da sz konusu adreste bir sayfa olmad iin grntde bir deiiklik olmayacak ve hedef adresteki dosyann download ilemi balayacaktr. Biz de Silverlight tarafndan bu taktikten faydalanacaz ve sayfann adresini kullancnn indirmesini istedii adres ile deitirerek taraycnn "Save File Dialog" amasn salayacaz. [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 kullancy ynlendirmek istediimiz adresi oluturmamz gerek. Bunun iin Uri snfndaki TryCreate metodunu kullanacaz. Bu metod bizden bir base Uri ve Relative Uri alarak ikisini birletirebiliyor. Base Url iin ierisinde bulunduumuz sayfann adresini System.Windows.Browser.HtmlPage.Document.DocumentUri ile veriyoruz, relative Uri iin yeni bir Uri deikeni yaratp download edilecek olan dosyann adn veriyoruz. Son olarak da almak sonucun aktarlaca yeni Uri deikenimizi referans olarak aktaryoruz. [VB] CType(System.Windows.Browser.HtmlPage.Document.GetProperty("location"), System.Windows.Browser.ScriptObject).SetProperty("href", Adres.ToString) [C#]

210

((System.Windows.Browser.ScriptObject)System.Windows.Browser.HtmlPage.Document.Ge tProperty("location")).SetProperty("href", Adres.ToString()); Simdi yapmamz gereken ise sayfann adresini bir nceki admda elde ettiimiz adres ile deitirmek. lk olarak System.Windows.Browser.HtmlPage.Document.GetProperty ile sayfadaki dokmann location zelliini alyoruz. Sonrasnda da dokman bir ScriptObject'e cast ederek SetProperty ile href zelliini deitiriyoruz. Aslnda bunu biraz JavaScript'teki document.location.href zelliine benzetebilirsiniz. Artk kodumuzu altrdmzda Silverlight ierisinde herhangi bir dmeye basldnda otomatik olarak taraycnn "Save File Dialog" penceresi alacak ve kullanc istedii dosyay Silverlight tarafndan indirebilecek. Hepinize kolay gelsin.
DaronYNDEM

211

Silverlight 2.0 iin zel n ykleme ekranlar gelitirmek. (PreLoader) Silverlight 2.0 uygulamalar hazrladnzda sunucu tarafna ykleme ilemini yaptnz gibi XAP dosyanzn byklne gre Silverlight Runtime tarafndan otomatik olarak bir n ykleme sistemi gsterilecektir. Kullanclar sitenizi ziyaret ettiinde XAP dosyasnn istemciye inme srecini gsteren bu ykleme gstergelerini isterseniz rahatlkla zelletirebilir ve deitirebilirsiniz. Tabi tm bunlar XAP dosyanz dnda daha XAP dosyas yklenmeden bir ekilde yine Silverlight ile yapabiliyor olmamz gerek.

Silverlight ile beraber gelen standart n ykleme animasyonu. Aslnda bu ykleme ekrann deitirirken belki de eski Silverlight 1.0 gnlerini biraz hatrlayacaksnz. XAP dosyas yklenmeden nce bu ekilde bir ykleme animasyonu gsterebilmemiz iin animasyonu oluturacak ayr bir XAML ve download durumunu kontrol edecek ayr bir JavaScript koduna ihtiyacmz var. Grsel ksm halledelim... lk olarak n ykleme ilemini gsterecek olan animasyonu ve grsel eleri dzenleyelim. Tm bu grsel elerin tabi ki XAP dosyas dnda olmas gerek. Bu durumda tek bir alternatif kalyor, o da hazrlayacamz tm XAML kodunun harici bir dosya olarak sunucuda tutulmas. Eer Visual Studio ile bir Silverlight projesi yarattysanz byk ihtimal ile yannda bir de ASP.NET siteniz olacaktr. te tam da o ASP.NET sitesine bir XAML dosyas eklemeliyiz. Bunu ister Visual Studio ierisinde yapn ister Expression Blend ierisinde, nemli olan projeleri kartrmayarak XAML dosyasn kesinlikle web sitesinde tarafnda bir dosya olarak yaratmanz. Maalesef bu noktadan sonra Expression Blend bize pek yardmc olamayacak nk Web sitesindeki XAML dosyasnn tam olarak ne tr bir projeye ait olduunu alglayamayacak. O nedenle ou kodu elle yazmak zorunda kalacaz. [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="Ykleniyor..."/> </StackPanel> Yukardaki kodumuz bizim nykleme ekrannn tasarm olacak. Tasarm olduka basit; bir StackPanel ierisinde TextBlock ile Rectangle kullanarak ii zyoruz. Tabi siz rneklerinizde farkl tasarmlar kullanabilirsiniz. Bizim rneimizde ekranda srekli

212

"Ykleniyor..." yazacak ve yannda da 0 pikselden 100 piksele doru genileyecek olan bir Rectangle yer alacak. Bylece kullancya standart grselden farkl bir ekilde XAP dosyasnn yklenmesine ait sreci gstermi olacaz. Bu kod ierisinde en nemli nokta Rectangle nesnesinin adnn Progress olmas. leriki aamalarda yazacamz JavaScript kodlar ile bu nesneyi bularak gerekli deiiklikleri yapacaz. Ortam hazrlayalm... Silverlight uygulamamz sayfaya yerletirdiimiz OBJECT taglar ierisinde baz ek parametreler tanmlamamz gerekiyor. Bylece Silverlight Runtime XAP dosyasnn indirirken nerede ve nasl bir progress gstermesi gerektiini bilebilecek. Gelin uygun bir OBJECT tagna gz atalm. [XAML] <object id="SL" data="data:application/x-silverlight-2," type="application/x-silverlight2" 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> Grdnz zere kod ierisinde kaln olarak yazl farkl nokta var. Bunlardan birincisi OBJECT taglarna vermi olduumuz ID olan SL ismi. OBJECT taglarmz bu ekilde isimlendirmek zorundayz nk birazdan JavaScript ile bu OBJECT taglarna yani Silverlight uygulamamza ulamamz gerekecek. Son olarak ayarlamamz gereken iki tane de parametre bulunuyor. Bu parametrelerden ilki XAP dosyas yklenmeden nce ve yklenirken gsterilecek olan XAML dosyamzn tam yolu olacak. splashscreensource adndaki bu parametreye biz rneimizde basit bir ekilde Scene1.xaml deerini verdik. Bu dosya ierisinde bir nceki admda yazdmz ve ierisinde Progress Rectangle'nn bulunduu XAML yer alyor. Son olarak onSourceDownloadProgressChanged event'na da yine ayn isimde bir JavaScript event-listener ekleyerek XAP dosyasnn download durumu ile ilgili deiiklikleri takip edebiliyoruz. Gelelim yazacamz bu JavaScript event-listener koduna... Biraz da JavaScript...

213

Bir nceki admda hazrladmz OBJECT tagnn parametrelerinden birinde onSourceDownloadProgressChanged adnda bir event-listener tanmlamtk. Bu eventlistener ierisinde ilk olarak sayfamzdaki OBJECT tagn ve ierisindeki Silverlight uygulamamz bulmamz gerekiyor. Bu yap Silverlight 1.0 gnlerinden hatrladmz bir yap. Aadaki kodumuzda SL adn verdiimiz OBJECT taglarn bulduktan sonra ieriine bakarak findName ile Progress adndaki Rectangle'mz 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 sz konusu Rectangle'n geniliini elimizdeki ykleme durumuna gre deitireceiz. Ykleme durumunu bize 1 zerinden decimal olarak verecek olan ey tarayc tipine gre ya bir Property ya da bir metod olaca iin bir IF kontrol ile onu de kontrol ederek gerekli ilemi yapyoruz. Artk Silverlight Runtime ile beraber gelen n ykleme animasyonlarndan kurtulabilir ve kendi zgr iradeniz ile :) kendi tasarmlarnz kullanabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

214

Silverlight 2.0 ile Analog Saat Uygulamas Silverlight 2.0 Beta 2 kullanarak analog bir saat gsterimi yapacamz bu yaz ierisinde StoryBoard kullanmn ve StoryBoard'larn belirli zamanlara zel olarak konumlandrlmasn inceleyeceiz. Gelin ilk olarak iin grsel tarafn halledelim ve Expression Blend 2.5 ile bir saat grseli yaratalm. Saatimizde toplam adet dikdrtgene ihtiyacmz var. Bu dikdrtgenler saatin akrep, yelkovan ve saniye gstergesini temsil edecek. Ayrca saatin ana gvdesini oluturacak bir de Ellipse kullanacaz. <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 animasyonlarmz hazrlamaya balayalm. Saniyeyi gsterecek olan saat kolunun toplam 60 saniye ierisinde 360 derece dnmesi gerekiyor. Buna uygun animasyon yaratmadan nce tm dikdrtgenlerimizin merkez noktasn saatin ortasna gelecek ekilde dzenleyelim. Bylece dikdrtgenler saatin merkez noktasn etrafnda dnecektir. <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"/>

215

<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> Uygulamamzn XAML kodunun son hali yukardaki ekilde. Hemen saniye koluna ait animasyonu hazrlayalm. SaniyeAnim adn vererek yeni bir StoryBoard yaratyoruz ve sz konusu StoryBoard'un 60. saniyesinde saniye adndaki dikdrtgeni dn asn 360 derece olarak tanmlyoruz. <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> Yukardaki animasyon ierisinde de grdnz zere ilk olarak animasyonun RepeatBehavior zelliine Forever deerini vererek animasyonun srekli tekrar edeceini belirtiyoruz. Sonrasnda Saniye dikdrtgenini hedef alan animasyon dikdrtgenin dn asn bir dakika iinde 360 dereceye getiriyor. Saniye kolu iin yaptmz animasyonlarla ayn mantkta dakika ve saat kollar iin de animasyonlar dzenleyeceiz. Dakika kolu iin dzenlediimiz animasyon dakika kolunu 60 dakika ierisinde 360 derece dndrecek. <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 iin dzenleyeceimiz animasyonda da saat kolunu 12 saat ierisinde 360 derece dndreceiz. <Storyboard x:Name="SaatAnim" RepeatBehavior="Forever"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Saat"

216

Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].( RotateTransform.Angle)"> <SplineDoubleKeyFrame KeyTime="12:00:00" Value="360"/> </DoubleAnimationUsingKeyFrames> </Storyboard> Tm bu animasyonlar altnda saatimiz doru bir ekilde iliyor olacak. Fakat esas mesele Silverlight uygulamas ilk aldnda tm saat kollarn doru balang noktalarna getirmek. Bunu yapabilmek iin StoryBoard'larn Seek metodundan faydalanacaz. Seek metodu ile istediimiz bir StoryBoard'u kendi iinde istediimiz zaman aralna 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)) Yukardaki kodun banda tm animasyonlarmz hemen balatyoruz sonra da her animasyonu uygun balang noktasna getirmek iin Seek metodunu kullanyoruz. Seek metoduna verdiimiz TimeSpan parametresini yaratrken her bir kola uygun deerleri aktaryoruz. Saniye koluna sadece ierisinde bulunduumuz zamann saniyesini, dakika koluna dakikay ve saat koluna da saat bilgisini veriyoruz ve animasyonlarmz o konumdan gelerek oynamaya devam ediyor. Saat uygulamamz tamamladk, hepinize kolay gelsin.
DaronYNDEM

217

Silverlight 2.0 ile Oyun Programlama'ya Giri Silverlight 2.0 ile beraber .NET programlama geldiinde gre hemen aklmza gelen konulardan biri de "Oyun Programlama" oluyor. Silverlight ierisinde var olan StoryBoard yapsn kullanarak oyun programlamaya altnz noktada ise "Bu i byle olmaz" diyerek brakacanz kesin. Maalesef StoryBoard yaps ou ii kolaylatrsa da ve oyun programlama ierisinde belirli bir yeri olsa da iin tamamn halletmek iin yeterli deil. Oyun programlamada ou zaman kare kare izim yapabilmemiz ve nesnelerin koordinatlar ile tek tek ilgilenebilmemiz gerekir. Daha net bir tanmla aslnda ekranda izimi bizim kod ile yaptrmamz gerekir. Bu noktada Silverlight 2.0 Beta 1 ile beraber gelen DispatcherTimer nesnesini kullanarak bu makalemizde ufak bir rnek yapacaz. Hedefimiz uygulamamzda bir kare ierisine bir top yerletirerek bu topun kare ierisinde duvarlara arparak srekli gezmesini salamak. "Bu ne biim oyun?" diyebilirsiniz. Tabi ki makale sonunda elimizde hazr bir oyun olmayacak, amacmz oyun programlamada kullanlan yapnn bir modelini yaratmak. lk olarak gelin uygulamamzn grsel ksmn tamamlayalm. Yarattmz yeni Silverlight 2.0 uygulamasna bir Ellipse yerletirerek en st sol keye konumlandralm. Ellipse'in ad Top olsun. lemleri tamamladmzda elde edeceimiz XAML aadaki 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 hazr olduuna gre artk arkaplana geip programlamaya balayabiliriz. Uygulamamzda kullanlmak zere toplam drt adet global deiken tanmlayacaz. Dim Konum As New System.Windows.Media.TranslateTransform() Dim Timer As New System.Windows.Threading.DispatcherTimer Dim XDegisim = 5 Dim YDegisim = 5 Bu deikenlerden ilki olan Konum bizim iin srekli olarak topun ekrann sol st kesinden ne kadar sada ve aada olacan saklayacak. Konum deikeninin tipi TranslateTransform eklinde. Bu deiken tipi herhangi bir nesnesinin RenderTransform grubuna aktardmzda nesnenin X ve Y koordinatlarnda yer deitirmesini salyor. Eer Expression Blend 2.5 ierisinde bir nesne yaratr ve herhangi bir animasyon ile konumunu deitirirseniz nesnenizin XAML kodunun aadaki hale geldiini grebilirsiniz.

218

<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 iin yaratt Rectangle koduna da baktmzda aslnda yapy anlayabiliyoruz.Rectangle ierisine yerletirilen bir RenderTransform yapsndaki TransformGroup ierisinde TranslateTransform nesnesi yer alyor. Bu nesnenin X ve Y zellikleri de Rectangle'n ne kadar yer deitireceine karar veriyor. Biz bu ayn yapy kendi Top nesnemiz iin programatik olarak kullanacaz. imdi tanmladmz global deikenlere geri dnelim. Dim Konum As New System.Windows.Media.TranslateTransform() Dim Timer As New System.Windows.Threading.DispatcherTimer Dim XDegisim = 5 Dim YDegisim = 5 kinci deikenimiz bir DispatcherTimer tipinde bir Timer nesnesi. Bu nesne aslnda Windows programlamadan bildiimiz Timer'dan farkl deil. Bu Timer'n da bir Tick durumu ve Interval'i var. Biz rneimizde Interval'i ok dk vererek ekranda izim yapmak iin bu nesneyi kullanacaz. Dier iki global deikenimizin aslnda Top'umuzun bir defada ne kadar yer deitireceine karar veriyor. Bu deerleri byterek topun hzn arttrabilir veya tam tersine azaltarak topunu hzn da yavalatabilirsiniz. Timer.Interval = New TimeSpan(0, 0, 0, 0, 15) AddHandler Timer.Tick, AddressOf Timer_Tick Timer.Start() Silverlight uygulamamz sayfada ilk aldnda hemen Timer nesnemizin Interval'ini 15 milisaniye olarak ayarlyoruz. Her 15 milisaniyede bir ekrandaki Top'un yeni konumunu belirleyeceiz bylece animasyon oluturmu olacaz. Doal olarak Timer nesnemizin Tick durumunu da yakalamamz lazm. Onun iin bir de event-handler tanmyoruz. Event-Handler kodumuza birazdan bakacaz. Son olarak Timer'n Start metodu ile sayac balatyoruz. Sra geldi Timer'n her bir Tick durumunda topun yeni pozisyonunu ayarlamaya. Aslnda kullanacamz kod ok basit. Konum.X += XDegisim Konum.Y += YDegisim

219

Top.RenderTransform = Konum Global deikenimiz olan Konum deikeninin X ve Y deerlerine deiim miktarlarn ekleyerek Top'un RenderTransform'una eitleyerek Top'un yeni konumunu almasn salyoruz. Fakat ortada bir sorun var; Top'un duvarlardan sekmesi lazm. Kabaca baktmzda aslnda yapmamz gereken drt kontrol var. Eer top alt kenara arptysa artk XDegisim miktar 5 deil de -5 olmal. Bylece top tekrar yukarya doru gitmeye balamal. Ayn ekilde her kenar iin bu kontroln yaplmas lazm. Eer top sa kenara arptysa artk YDegisim miktar 5 deil de -5 olmal. Tm bu kontrolleri yaptmzda aadaki 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 srasyla incelersek; ilkinde eer topun konumu sahnemizdeki ana Canvas'mz olan LayoutRoot'un geniliinden Top'un geniliini de kararak aldmz koordinata ulam ise hemen XDegisim miktarn - hale getiriyoruz. Bylece Top geri gitmeye balayacak. Ayn ekilde ikinci IF kontrolnde de Y ynnde ayn kontrol yapyoruz. Tabi bir de iin dier taraf var, yani deiim miktar eksi iken top ekrann stne veya soluna doru gidecek. Bu durumda da nc ve drdnc IF kontrolmz ile Top bu pozisyonlara gelmi ise deiim miktarlarnn mutlak deerini alarak pozitif hale eviriyoruz. Bu hali ile uygulamamz altrdmzda topumuzun duvarlardan sekerek sonsuza dek gezecektir. Kodumuzun son hali aadaki 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

220

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 sayfann genelinde MouseLeftButtonDown durumunu yakalayarak Silverlight uygulamasna tklandnda Timer'n durdurulabilerek tekrar balatlabilmesi iin gerekli kodu da yazarsak rneimiz artk tamamlanm demektir. Artk farkl animasyon yapmak, farkl koordinat kontrolleri yapmak hatta matematiksel koordinat hesaplamalarn ortaokula dnp biraz da trigonometri ekleyerek lise bilgisi ile de vektrel hesaplamalara evirmek tamamen size kalm. Hepinize kolay gelsin.
DaronYNDEM

221

Silverlight 2.0 ile Powerpoint dosyalarnn Thumbnail'lerini gstermek. Her programcnn hayatnda en az birka defe Office dosya formatlar ile ilgilendii projeler olmutur. Bu durum ister yeni bir Word dosyas yaratmak olsun, ister bir Excel dosyasndan veri ekmek olsun OpenXML ncesinde ciddi skntlar ektiimiz bir gerek. En basit bir sebep olarak binary formatl dokmanlar ile uramak zorunda kaldmz syleyebiliriz. Office 2007 ile beraber tantmz ve sonlarna X harfleri eklenen dosya uzantlar aslnda OpenXML'in geldiinin bir iaretiydi. yi ki geldin diyerek yava yava konumuza gei yapalm. Daha nceki yazlarmda Silverlight 2.0 ile istemci tarafndaki dosyalara OpenFileDialog ile ulaabildiimizi grmtk. Yine ayn sistemi kullanarak bu sefer amacmz bir Powerpoint dosyasn aarak sz konusu dosyann Thumbnail grntsn Silverlight ierisinde gstermek. Aslnda ok anslyz, neden mi? nk OpenXML var. OpenXML'in bize faydas ne? OpenXML formatndaki her dosya aslnda bir ZIP dosyasdr. Eer dosyann uzantsn ZIP olarak deitirirseniz aslnda ierisine girerek tm detaylar grebilirsiniz.

OpenXML dosyalarnn iinde herey XML formatnda, ak seik karmzda. Yukardaki basit bir Powerpoint dosyasnn ierii grebilirsiniz. Grdnz zere aslnda her ey ayr ayr XML dosyalar eklinde kaydedilmi. Yani bir Office 2007 dosyas yaratmak znde XML'ler yaratarak ZIP'lemekten farkl deil. Hele bir de bu dosyalar aarak

222

programlarnzda gstermek istiyorsanz LINQ2XML'in gcnden de faydalanarak ok hzl zmler gelitirmeniz mmkn. Konumuza dnersek; bize Powerpoint dosyasnn Thumbnail'i lazmd. Bunun iin XML'ler ierisinde ilk slayt ile ilgili bilgileri alarak gerekli izimleri hazrlayabiliriz fakat buna gerek yok. nk her PowerPoint dosyas zaten iletim sisteminde gsterilecek olan Thumbnail'i kendi iinde barndrr. OpenXML format sa olsun, dosyamzn iini biraz kartrdmzda gryoruz ki ZIP dosyas ierisinde docProps adndaki bir klasrn iinde thumbnail.jpeg adnda bir JPG dosyas bulunuyor. te bu dosya bizim Silverlight tarafnda gstereceimiz thumbnail grselini ieriyor. ZIP'ten resmi nasl alacaz? Yine daha nceki bir yazmda bir ZIP dosyalarn Silverlight tarafnda aabilmenin yollarna deinmitik. Hatta daha da ileri giderek Silverlight 2.0 XAP dosyalar da birer ZIP dosyas olduu iin onlar amtk. imdi ise sra baka bir ZIP dosyas amaya geldi, Powerpoint dosyalar. lk olarak Powerpoint dosyasn aarak Thumbnail'i gsterecek olan uygulamamzn tasarmn basit bir ekilde yapalm. Sahnede bir dme ve bir de Image nesnesi olsun. Dmeye basnda kullancdan bilgisayarndan bir Powerpoint dosyas semesini isteyelim ve sonrasnda da seili dosyann Thumbnail'ini Image nesnesi ierisinde gsterelim. <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> Sra geldi gerekli ilemleri sras 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();

223

lk olarak yukardaki ekilde Silverlight tarafnda kullancdan bilgisayarndan bir Powerpoint dosyas semesini isteyelim. Sonrasnda bize dosyann Stream'i gelecek ve biz de ierisinden istediimiz JPEG dosyasn almaya alacaz. Kodumuz ierisinde istemcideki dosyalara ulamak iin bir OpenFileDialog kullanyor, filtresini de sadece PPTX'leri gsterecek ekilde ayarlyoruz. [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 yapsn kullanacaz ve sanki harici bir kaynak aarm gibi ZIP dosyasn atracaz. Sonuta hedefin bir Powerpoint dosyas olup olmad nemli deil. Bizim istediimiz ZIP dosyasndaki docProps klasrnde bir dosyay almak. Kullandmz taktik daha nceleri Silverlight 2.0 XAP dosyalarndan dosya almak iin kullandmz taktik ile birebir ayn. StreamResource olarak OpenFileDialog'dan gelen dosyann ierisinde JPEG dosyasn alyor ve GetResourceStream ile de dosyay ekiyoruz. ektiimiz dosyay daha nce Foto adnda tanmladmz BitmapImage deikenine SetSource ile atayarak sonunda da delimizdeki resmi sahnedeki Image nesnesine aktaryoruz. Bylece Powerpoint dosyasnda Thumbnail'i bularak Silverlight 2.0 ierisinde ok kolay bir ekilde gsterebildik. Bu ayn taktii ASP.NET ile de kullanarak gerektiinde sunucu tarafl olarak Powerpoint dosyalarnda Thumbnail'ler yaratmak OpenXML sayesinde ocuk oyuncana dnm durumda. Hepinize kolay gelsin.
DaronYNDEM

224

Silverlight 2.0 ile Twitter ve TwitXR Combo Widget Bugn sizlerle yeni bir ak kaynak kodlu Silverlight 2.0 uygulamam paylaacam. Hatrlarsanz bundan aylar nce Silverlight 1.0 ile bir Twitter Widget hazrlam ve sizlerle kaynak kodlarn paylamtm. imdi de 2.0 ile yeni bir Widget hazrladm. Bu sefer Widget'n TwitXR destei gibi ilgin zellikleri var Bir Widget hikayesi... Silverlight 2.0 ile gelitirme yapmann 1.0'a kyasla ok sayda avantaj var fakat unutmayalm ki artk .NET tarafndayz ve JavaScript ile olduu kadar low level kod yazmyoruz. Ne demek istediimi makale boyunca daha net anlayacanzdan eminim. Peki size neler anlatacam? Uygulamann iindeki kodlarn aklamalarn zaten kodlar ierisindeki yorum satrlarnda bulabilirsiniz. Yorum satrlarn ngilizce yazdm nk uygulamay yurt d ile de paylaacam. nemli olan ve benim zellikle deinmek istediim noktalar bir Widget hazrlarken karlatm duruma zel sorunlarla ilgili. Gelin daha fazla konumak yerine sorunlara el atalm. Twitter API samal! Twitter'n ok gzel bir XML API yaps var. Sorunlardan ilki bu API iin ister Flash ister Silverlight hi fark etmez ClientAccessPolicy dosyas konmam, yani Cross-DomainRequest yasak! Durum byle olunca sunucu tarafnda bir proxy oluturarak veriyi kendi sunucunuzaalp kendi Widget'nza aktarmanz gerekiyor, ama bunu da yapamyoruz nk yle bir samalk mevcut; istemci bana bir saatte 70 request snr var. Eeee? Tm requestleri benim Web Server'm yapacak sonuta tm ziyaretiler iin, 70 kesinlikle kabul edilebilir bir snr deil. Byk ihtimal ile Windows uygulamalar falan dnlm. Sonu olarak Silverlight 1.0 Widget'da kullandmz Remote Script Injection ile CrossDomain-Reqest taktiini Silverlight 2.0 da da kullanmamz gerek. Dinamik olarak sayfaya bir script tag ekleyip twitter sitesinden JavaScript alp sitemizde altryorduk. Parametre olarak da bizim istediimiz veriler geliyordu. te sorular; Silverlight 2.0 ile dinamik Script taglar sayfaya nasl 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) Yukardaki kod ile rahatlkla dinamik olarak bir Script tag yaratp zelliklerini de ayarlayp ierisinde bulunduumuz sayfann Body'sine ekleyebiliyoruz. Bylece uzaktaki dosya arlacaktr. Twitter adresinin iindeki parametrelerin konumuzla imdilik alakas yok. Ama bu adres zerinden gnderdiimiz callback parametresi Twitter'dan data gelince sayfamzda

225

altrlacak olan JavaScript'in ta kendisi. Peki bu durumda data gelince arlan JavaScript'ten bizim Silverlight 2.0'n nasl haberi olacak? JavaScript'ten Silverlight 2.0 fonksiyonlar nasl arlr? Buyurun makalemi okuyun : http://daron.yondem.com/tr/PermaLink.aspx?guid=a1426eb07120-4a66-9d5c-de5027fd59ed imdi veri geldi elimize ama gelen veri JSON! Bunu nasl olacak da anlalabilir bir hale evireceiz ve .NET nesneleri eklinde kullanabileceiz? JSON verisi Silverlight 2.0'a nasl alnr? Buyurun bir makale daha: http://daron.yondem.com/tr/PermaLink.aspx?guid=457fbb28-892e4a37-b7d3-cb297d97020b Ama ben yukardaki makalede anlatlan yapmadm, JSON'dan ekmek istediim veri belli olduu iin ve twitter'n JSON format basit olduu iin dorudan aadaki kod ile gelen her JavaScript nesnesine ScriptObject muamelesi yaptm. 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 Yukarda JSON deikeninin ierisinde dorudan JavaScript tarafndan gelen JSON objesi bulunuyor. GetProperty metodu ile herhangi bir diziden istediimiz eyi ve zelliklerini tek tek alabiliyorum. Bir sonraki sorunumuz hangi Twitter hesabndan veri ekeceimiz Widget' kullananlarn nasl karar verebilecei. Bunun iin Silverlight 2.0'n sayfaya yerletirildii Object taglarnn parametrelerini kullanacaz. Parametreli Silverlight 2.0 dosyalar kullanm nasl olur? Buyurun size bir makale : http://daron.yondem.com/tr/PermaLink.aspx?guid=4834596e-b5ec450f-8e3c-cfba929d958e Twitter'dan data alma ileminin Widget'n bulunduu sayfa tamamen yklendikten sonra balasn istiyoruz. Bun durum data yklendikten sonra DOM'a ulayor olmamzdan kaynaklanyor, eer sayfa tam yklenmemise daha DOM listeleri sabitlenmemi olabilir. HTML / DOM eventlarn Silverlight 2.0 ile nasl yakalarm? 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

226

Private Sub DocLoaded(ByVal sender As Object, ByVal e As EventArgs) End Sub Yukardaki kod ile yaratm olduunuz bir event-handler nasl sayfann eventlarn veya bulduunuz herhangi bir HTML nesnesinin eventlarna ekleyebileceinizi grebilirsiniz. Kullanm ekli epey basit. Bir sonraki admda bir TextBlock ierisine farkl formatlarda yaz eklemek istiyoruz. Bunda zor ne var? diyebilirsiniz :) Ama bir TextBlock'un Text zelliine baktnzda String tipinde olduunu gryorsunuz. Peki buna nasl bir formatlama bilgisi aktarabiliriz ki? Aktaramayz :) Aslnda TextBlock'un bir de Inlines diye bir dizisi var. Bunun ierisinde satr ii Item'lar saklanyor. Eer Inlines ile ilgili bir ayarlama yaplmamsa ve dorudan Text zellii set edilmi ise arkaplanda otomatik olarak bir Inline Item yaratlarak bu diziye ekleniyor. Tm bunlar programatik olarak da yaplabilir. Bir TextBlock'un iindeki belirli bir metnin rengi programatik olarak nasl deitirilir? 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) Yukardaki kod ierisinde Current deikeni aslnda bir TextBlock. Bu TextBlock ierisinde URL'i alp URL'den ncesini ayr bir Run olarak, URL'i ayr bir Run olarak, kalan da ayr bir Run olarak TextBlock'un Inlines dizisine ekliyoruz. Bylece her bir Run iin grsel olarak farkl ayarlar yapabiliyoruz. Yazmn en banda TwitXR destei derken ne demek istediimi biraz anlatym. Twitter ile TwitXR beraber alan sitelerdir aslnda. TwitXR zerine yolladnz bir resim ve yaz otomatik olarak Twitter'a da aktarlr. Bizim Widget Twitter'dan Post'lar alrken kontrol edecek eer o Post TwitXR'dan gelmise uygun fotoraf da bularak gsterecek. Tm bu hikayede benim istediim nokta TwitXR'dan alnan resim istemciye yklenirken yklemenin

227

durumundan haberdar olmakt. Yani resmi istedim ama tam olarak yklendi mi yoksa indiriliyor mu? Remote Image yklerken Progress gstermek! Bandan beridir Remote-Request'e izin verilmiyor ve Policy dosyalar yok diyoruz! Bu durumda benim normal bir WebClient snf ile resmi indirmem ve sonra gelen Stream'i Image nesnesine balayp sahneye koyma ansm yok. Mecburen Image' dorudan Image nesnesine balamak zorundaym, ancak bu ekilde remote resim alabiliyorum. Ama bunu yaparken de zaten Imaging.BitmapImage snfn kullanmak zorundaym ve bu snfn 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 Yukardaki kod ierisinde PhotoDownload adndaki BitmapImage'e fotorafn URL'ini veriyorum ve sonra da Photo adnda Image UIElement nesneme Source olarak veriyorum. Bylece Silverlight resmi BitmapImage ile indirerek Image nesnesine balayp gstermeye alyor. Bu esnada BitmapImage'n DownloadProgress'i alyor. lgin bir ekilde bu Progress event' ierisindeki Progress zellii 1 ile 0 arasnda olmas gerekirken ya 0 ya da 100 dndryor. Normalde 0 = indirilemedi ve 1 = indirildi anlamna gelmeliydi. Sanrm bu bir BUG :) Her neyse bir iimizi imdilik halletik. Unutmayn buradaki Progress WebClient'taki biri Double deil, Integer. Yani aslnda bir Progress deil de Status deeri veriyor. effaf uygulama ve Overlay Sorunu Aslnda 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 gzkmesini deil ayn anda o effafln arkasndaki HTML'in de kullanlabilir olmasn istiyorum. te bu olmuyor! Hedefim Widget ierisinde herhangi bir Post'un fare ile zerine gelince yana doru sayfann zerine taacak ekilde uygulamann genilemesi ve orada da postun fotosunun gzkmesi. Tabi tm uygulama gelimeyecek sadece fotorafn gzkecei bir ksm alacak. effaf fon

228

kullanldnda grsel olarak bir sorun yok gibi gzkse de bir bakyorsunuz ki effaf olmasna ramen uygulama alannz fotorafn gsterilecei yerleri de kapsad yani sayfaya tat iin o ksmlardaki HTML kontrolleri almyor. Bu konu maalesef Flash'ta daha iyi zlm durumda, Flash'ta effaf olan yerler gerekten effaf :( Peki nasl zeriz, dinamik olarak Silverlight uygulamasnn sayfadaki kaplad alan yine kodlarmz ile dzenlememiz gerek. Silverlight'n OBJECT taglarna bir ID deeri vererek bunun zerinden OBJECT'in geniliini deitirebiliriz. HtmlPage.Document.GetElementById("TwitterSLWidget").SetAttribute("width", "360px") Bu kod ile kullandmz OBJECT taglar aadaki 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="textdecoration: none;"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" /> </a> </object> Widget' nasl kullanrz? Birazdan kaynak kodlar ile beraber Widget' sizinle paylaacam. Ama onun ncesinde hemen Widget' nasl kullanrz ona bakalm. <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" />

229

<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="textdecoration: none;"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" /> </a> </object></div> Yukardaki HTML kodunu sayfanza yerletirmeniz gerekiyor. zellikle koyu olan yerlere dikkat. daronyondem yerine kendi Twitter ve TwitXT hesaplarnzn adlarn yazmanz gerek. count ksmna da ko Post gzksn istiyorsanz onu yazabilirsiniz. OBJECT ve DIV taglarnn ID'leri ok nemli. Bu ID'ler kodlarda kullanlyor, eer deitirirseniz kodlar da tekrar dzenleyip XAP dosyasn Compile etmeniz gerekecektir. function TwitterIncData(object) { document.getElementById("TwitterSLWidget").Content.Page.IncData(object); } Son olarak yukardaki kodu da sayfanzda uygun bir JavaScript dosyasna veya taglar arasnda koymanz ve XAP dosyasn sunucuya kopyalamanz yeterli olacaktr. Kaynak Kodlar Tm projenin kaynak kodlarn aadaki adresten indirebilirsiniz. Proje epey kark oldu, zellikle Remote Script Injection kullandmz iin Cross-Browser uyumluluu konusunda skntlar var. Dier yandan Overlay konusunda da farkl tarayclarda sorunlar var. O nedenle imdilik ben ancak IE 7 destei sunabiliyorum, uraacak pek zaman olmad. Eer siz uygulamay dier tarayclar da destekleyecek ekilde modifiye ederseniz beni haberdar etmeniz yeterli. Bylece mini bir ak kaynak projesi olmu olur. Makaledeki tm kodlar VB :) nk uygulamadan kesip yaptrdm. Uygulamay da malum VB ile yazdm :) C#'clara selamlar :)
DaronYNDEM

230

Silverlight 2.0 ItemsControl ve ObservableCollection ile DataBinding ASP.NET kullanrken en sevdiim kontrol Repeater kontroldr. Bana hereyi istediim gibi esnek bir ekilde dzenleme ans tanr. Ayn mantkla Silverlight 2.0 Beta 1 tarafna getiimizde karmzda ItemsControl kyor. ItemsControl'e baladnz herhangi bir veri ierisindeki her Item'n nasl gzkecei ayn Repeater ierisinde olduu gibi bir ItemTemplate aracl ile karar verebiliyorsunuz. Ayrca tm bu Item'larn nasl bir kontrol ierisinde ekrana yerletirileceini de belirleme ansnz var. znde ItemsControl tek bana herhangi bir grsellik barndrmyor, hereyi sizin tek tek ayarlam olmanz art. rneimizde elimizde bulunan bir rn listesini ItemsControl'e balayarak rnlerin isimleri ile sat grafiklerini gstereceiz. Bunu yaparken de Silverlight 2.0 ile beraber gelen DataBinding sistemini kullanacaz. lk olarak gelin code-behind tarafndan balayalm ve rn listemizi yaratacamz rn tipini tanmlayalm. 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 Grdnz gibi aslnda klasik bir .NET snfndan farkl deil. Her zamanki gibi Urun snfmz / tipini yarattk ve bu snf zerinde bir liste reterek ItemsControl'e balayacaz.

231

Normal artlarda olsa belki bir Generic.List kullanrdk oysa Silverlight 2.0 ile beraber bir ObservableCollection kullanacaz. Bunun tabi ki mantkl bir nedeni var. ObservableCollection yaplar Silverlight 2.0 tarafnda DataBind ilemleri iin kullanldklarnda Public bir ObservableCollection listesi bir defa herhangi bir kontrole balandktan sonra srekli organik bir ba ierisinde kalyor. Bylece eldeki liste zerinde herhangi bir deiiklik kod tarafnda yapldnda otomatik olarak sonu grsel elere de yansyor. Biz de bu nedenle rneimizde ObservableCollection listesi kullanacaz, bylece kod tarafnda listede bir deiiklik yaptmzda sonu dorudan grsel olarak ItemsControl'e yansyacak. 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 Grdnz gibi aslnda ObservableCollection'larn normal Generic.List'lerden kullanm asndan pek bir fark yok. Biz rneimizde rastgele rnler ve sat rakamlar yaratarak rettiimiz listeyi, adn UrunlerControl olarak koyduumuz ItemsControl nesnesine ItemsSource zellii zerinden balyoruz. Gelelim XAML kodumuza... <ItemsControl Margin="27,8,44,8" x:Name="UrunlerControl"> <ItemsControl.ItemTemplate> <DataTemplate> Her bir yaratlan enin grsel tanm buraya gelir. </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> Tm yaratlan elerin ierisine yerletirilecei ortam tanmlar. </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> Yukardaki ItemsControl ierisinde toplamda iki farkl Template bulunuyor. Bunlardan ilki ItemTemplate ierisinde DataTemplate. ItemsControl'e baladmz verideki her biri Urun iin bir adet DataTemplate oluturulacaktr. Bu sistemi ASP.NET'teki Repeater ierisinde ItemTemplate yapsna benzetebiliriz. Tm bu yaratlan DataTemplate'lar ise ItemsPanel ierisinde ItemsPanelTemplate'ta tanmlanm grsel yapnn ierisine oturtulacaktr. ItemsControl'un kendine ait bir grsel yaps olmad iin aslnda ItemsPanelTemplate bu yapy oluturuyor olacak. Biz rneimizde ana yap olarak bir StackPanel kullanacaz ve ItemsPanelTemplate ierisinde iindeki nesneleri dikey hizalamaya ayarlanm bir StackPanel bulunacak.

232

<ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical"></StackPanel> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> Dier yandan retilecek olan her biri Urun'un grsellii iin de DataTemplate ierisinde bir TextBlock bir de Rectangle kullanacaz. DataTemplate ierisine sadece bir element yerletirebildiimiz iin bir ContainerElement olarak yine StackPanel kullanacaz. Bu sefer her bir Urun iin oluturulacak olan StackPanel'ler kendi ilerindeki nesneleri yatay olarak hizalayacaklar. Bylece StackPanel'ler ierisindeki TextBlock ve Rectangle'lar yan yana duracaklar. <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock/> <Rectangle Height="30" Fill="#FFFF0000"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> Amacmz TextBlock ierisinde rnn adn gsterirken rn sat rakamna gre Rectangle'n da geniliini ayarlayarak geniliine gre rnlerin yannda bir sat grafii gstermek. Bu durumda hemen Silverlight 2.0'a zel DataBind sistemini kullanarak TextBlock'un Text zelliini ItemsControl'a aktarlan verilerin Adi zelliine, Rectangle'n Width zelliini de Satis deerine balamamz gerekiyor. <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Adi}"/> <Rectangle Height="30" Width="{Binding Satis}" Fill="#FFFF0000"/> </StackPanel> imiz tamamland. Artk uygulamamz altracak sonucu grebiliriz. Fakat onun ncesinde gelin srekli rnlerin listesini deitiren bir de Dme ekleyelim uygulamamza ve elimizdeki ObservableCollection yapsndaki rn listesini srekli deitirsin. Dmemizin arkaplandaki koduna aadaki satrlar yazmamz yeterli olacaktr. 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 Yukardaki kod ierisinde ObservableCollection listemizi temizliyor ve tekrar rnler ekliyoruz. Herhangi bir ekilde tekrar DataBind ilemi yapmasak da sz konusu ilemlerin sonucu ItemsControl'n grsel arayzne yansyor.

233

Uygulamamzn tam XAML kodunu aada 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 ksmndaki 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

234

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 aslnda WPF tarafndan tandk olsa da Cross-Platform olarak istemci tarafnda bu ilemleri yapabiliyor olmak gerekten heyecan verici. Hepinize kolay gelsin.
DaronYNDEM

Silverlight 2.0 kontrolleri yaratmann yolu.

235

Silverlight 2.0 ierisinde kullandmz standart kontrollerin yan sra istersek kendi kontrollerimizi de hazrlama ansmz var. Daha nceleri ister ASP.NET ister Windows uygulamalarndan alk olduumuz bu uygulama ile hazrladnz size zel kontrolleri farkl projelerde rahatlkla kullanma ansna sahip olabilirsiniz. Bu yazmzda deneme amal olarak Silverlight 2.0 ile beraber gelen Button kontroln baz alp gelitirerek yeni bir kontrol oluturacaz. Yaratacamz yeni TimeOutButton kontrol kullancndan bir TimeOut deeri alacak. Milisaniye cinsinden verilen bu sre sonunda Button kullanlamaz hale gelecek. Bu esnada Button'un zerinde srekli ka saniye kald da yazlacak. Kullanclarn belirli bir srede bir ilemi tamamlamasn istiyorsanz bu gibi bir Button iinizi grebilir. Gelin hemen ie koyulalm. alma ortammz hazrlayalm. Kontrolmz gelitirirken srekli test etmek isteyeceiz. O nedenle ilk olarak salkl bir alma ortam hazrlamamz lazm. Yeni bir Silverlight projesi yarattnzda Visual Studio ierisinde Solution iinde bir ASP.NET ve bir de Silverlight projeniz bulunur. Solution dosyasna bir proje daha ekleyeceiz. Solution Explorer ierisinde solution dosyasna sa tu ile tkladktan sonra "Add / New Project" diyerek "Silverlight Class Library" seeneini iaretlemeniz yeterli olacaktr. Bylece yeni kontrolmz oluturmak iin kodlarmz yazacamz ortam gelitirdik. Solution' Compile ettiimizde Silverlight projemize otomatik olarak bu kontrol projemizin de eklenmesi gerekiyor. O nedenle hemen Silverlight projesine sa tu ile tklayarak gelen menden "Add Reference" komutunu verin ve karnza gelen pencereden de "Projects" tabna geerek Class Library projenizi sein. Bylece artk F5'e bastnzda her ey otomatik olarak yaplacaktr ve kontrolnz kullanlr ekilde inceleyebileceksiniz. Tabi testlere gemeden nce biraz kod yazmamz gerekiyor ;) Kontrolmz hazrlayalm. Class Library ierisinde kod dosyamzda dmemizin adn tayan bir Class bulunuyor. Bu Class' biz rneimizde standart Silverlight Button kontrolnden inherit edeceiz. Bylece yeni ve gelimi bir Button yaratrken her eye sfrdan balamayacaz, Silverlight ierisinde hazr Button kontroln alarak zerine yeni ilevsellikler ekleyeceiz. [VB] Public Class TimeOutButton Inherits Button End Class [C#] namespace TimeOutBtn { public class TimeOutButton : Button { }

236

} Bir sonraki admda hemen kontrolmze yeni bir Property tanmlayalm. Property'miz sayesinde kullanclarn dmenin ne kadar sre aktif kalacan tanmlayabilecekler. [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; } Dmemiz ilk olarak sayfada gzktnde hemen ilemlere balamamz gerekiyor. lk olarak dmenin iin saya bilgisi yazacak yeni bir kontrol eklememiz art. Dmenin Content zellii duruma gre dorudan bir String olabilir veya Content ierisinde farkl Silverlight nesneleri bulunabilir. Tm bunlar gz nnde bulundurmak zorundayz. [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;

237

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 ierisinde ilk olarak bir StackPanel yaratyoruz. StackPanel'in zelliklerini ayarladktan sonra hemen dmemize atanm Content'i kontrol ediyoruz. Amacmz Content ierisinde her ne varsa hepsini StackPanel iine eklemek. Sonrasnda bizim kalan saniye miktarn gstereceimiz TextBlock'u da yine StackPanel ierisine ekleyerek StackPanel'i de dmenin Content'i yapacaz. Bylece bu TimeOutButton kontroln kullananlar dmenin Content'ine ne koyarlarsa koysunlar kalan saniye miktar srekli bu Content'in ierisinde gsterilecek. Eer dmeye atanm Content String tipindeyse bu String'i alp yeni bir TextBlock yaratarak ierisine yerletiriyoruz. TextBlock'umuzu da StackPanel iine koyuyoruz. Eer Content String deilse demek ki kullanc dmenin Content'ine bir Silverlight nesnesi koymu. Bu durumda sz konusu nesneyi alp dorudan StackPanel iine koyabiliriz. Son olarak kodumuzda gzkmeyen fakat uygulamamzda global bir deiken olarak yarattmz MyBox adndaki TextBlock'u da StackPanel'e ekliyoruz ve StackPanel'i de dmenin Content'i yapyoruz. MyBox kontroln global yaratmamzn nedeni ileriki admlarda MyBox'n ieriine srekli kalan saniye miktarn yazdracak olmamz. [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 deikenimiz arasnda bir de DispatcherTimer bulunuyor. Bu Timer ile kalan saniye miktarn srekli hesaplayp kontrol ederek dmenin iine yazdracaz. [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

238

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 sreyi PTimeOut adndaki private deikenimizde saklayacaz. Eer kalan sre sfrn altnda ise hemen Timer'mz durduruyor ve kalan sreyi gsteren TextBlock'umuz olan MyBox' sahneden kaldrp dmeyi de pasif hale getiriyoruz. Kalan sre sfrdan byk olduu srece MyBox TextBlock ierisine gerekli uyary yazdrp kalan sreyi Timer'n Intervali kadar azaltyoruz.

Expression Blend ierisinde hazrladmz yeni kontrol Artk kontrolmz hazr. Projemizi Blend ile atmzda Asset Library ierisinde Custom Controls tabnda kontrolmz grebiliyoruz. Sahneye bir TimeOutButton ekleyip TimeOut zelliini de ayarladktan sonra kontrolmz kullanabiliriz. <UserControl x:Class="SilverlightApplication47.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

239

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300" xmlns:TimeOutBtn="clrnamespace: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. Uygulamann tam kodunu aada 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

240

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;

241

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."; } } } }
DaronYNDEM

242

Silverlight 2.0 Plug-In Alglama ve OBJECT Tag Silverlight 2.0 Beta 2 ile beraber 1.0 srmne gre uygulamalarn datm sistemi deiti ve karmza XAP dosyalar kt. Bu dosyalar standart HTML veya herhangi bir sunucu tarafl programlama altyapsnda kullanmann yolu da aslnda eskiden Flash tarafnda alk olduumuz Object taglarna dnt. Bu durumun tabi ki gzel yanlar var, Silverlight 1.0'da olduu gibi harici JavaScript dosyalarna (Silverlight.js) ve DIV elementlerine vs ihtiyacmz olmuyor. imdi gelin beraber Silverlight 2.0 uygulamalarn sayfalarmza yerletirirken kullanacamz OBJECT taglar ile gelen yenilikleri inceleyelim. Yeni bir Silverlight 2.0 projesi Visual Studio 2008 ierisinde yeni bir Silverlight 2.0 projesi yarattmzda bizim iin test amal olarak rnek bir de HTML dosyas hazrlanyor. Bu dosya ierisinde bir Silverlight uygulamasnn gsterimi iin 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 dta silverlightControlHost adnda bir DIV elementi bulunuyor. Aslnda byle elementin bulunmasna hi gerek yok, sadece CSS ile Silverlight uygulamasnn boyutu ayarlanabilsin diye yerletirilmi bu DIV elementinin baka herhangi bir ilevsellii olmad iin rahatlkla koddan kaldrlabilir. Esas OBJECT tagmza getiimizde karmza drt farkl zellik kyor. Bunlardan Data zellii OBJECT taglarnn farkl tarayclarda farkl ilevselliklerle karlamasndan dolay yerletirilmi. Data zellii olmayan OBJECT taglar baz tarayclarda sorun kartabiliyor. TYPE zellii taraycya Silverlight Plug-In'in bu OBJECT tagndan sorumlu olduu bilgisini verirken width ve height ise uygulamann sayfadaki boyutunu belirtiyor. <param name="source" value="ClientBin/SilverlightApplication56.xap"/> <param name="onerror" value="onSilverlightError" /> <param name="background" value="white" /> OBJECT taglar arasnda baz parametreler var. Bu parametreler uygulamann zelliklerine gre deiecektir, hatta burada tanmlanmam olan baz farkl parametreler de kullanmak mmkn. Mevcut parametreler arasnda Source parametresi istemciye yklenecek olan XAP

243

dosyasnn adresini tarken onerror parametresi ise hata durumunda istemci tarafnda altrlacak olan JavaScript metodunun adn saklyor. <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 aslnda istemcide Silverlight Runtime ykl olmadnda gsterilecek olan ierii tanmlyor. Grdnz gibi basit bir ekilde "Get Microsoft Silverlight" logosu gsterilerek microsoft.com'da bir web sayfasna ynlendirilmi. Artk SL 1.0'da olduu gibi Silverlight Plug-In'in hangi srmnn veya hangi platforma zel yklemesinin yaplacana JavaScript ile istemci tarafnda karar vermiyoruz. Herhangi bir ekilde ykleme gerektiinde dorudan Microsoft sitesine ynlendirme yaparak tm ii Microsoft'a brakyoruz. Bu biz yazlm gelitiriciler iin ok daha rahat bir sistem. Eer isterseniz yukardaki HTML kodunu deitirerek Silverlight RunTime ykl olmadnda ekranda gsterilecek ierii farkl bir ekilde tanmlayabilirsiniz. nemli olan tek nokta herhangi bir ekilde bir link ile kullanclar doru adrese ynlendirerek Microsoft sitesinden RunTime paketini indirmelerine olanak tanmak. <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 Ykle" style="borderstyle: none"/> </a> </object> <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe> </div> rnein yukardaki kod ierisindeki HTML sayesinde eer istemci tarafnda Silverlight Runtime ykl deil ise silverlightyok.jpg adnda bir resim gsteriliyor ve tklandnda RunTime yklenmek zere Microsoft web sitesine ynlendiriliyor. <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe> Bu da nesi? Bu tamamen Safari tarafnda bir nbellekleme sorununu gidermek iin yerletirilmi normalde kullanlmayan bir IFRAME. Safari taraycsnda bir sayfada eer bir IFRAME varsa sayfa hibir ekilde nbellee alnmyor. Bunlarn haricinde Visual Studio'da yaratlan sayfa iinde hata yakalama iin onSilverlightError adnda bir JavaScript fonksiyonu ve errorLocation adnda bir DIV

244

elementi bulunuyor. Bahsi geen bu JavaScript fonksiyonu herhangi bir hata durumunda hata mesajn alarak errorLocation ierisine yazdrmakla sorumlu. Hepinize kolay gelsin.
DaronYNDEM

245

Silverlight 2.0 PopUp Kontrol Silverlight 2.0 Beta 1 ile gelen yeni Silverlight kontrollerinden biri olan PopUp kontrol ile beraber Silverlight uygulamalar ierisinde dahili PopUp sistemleri oluturabiliyoruz. zellikle farkl Silverlight kullanc kontrollerinin bulunduu projelerde farkl arayzler aras geileri salamak iin PopUp kontrolleri byk kolaylk salyor. Hemen bir PopUp kontrol rnei yapmak iin yeni bir Silverlight 2.0 Beta 1 projesi yaratarak uygulamamzn ana XAML' olan Page.XAML ierisine bir dme yerletiriyoruz. Sz konusu dmeye basldnda PopUp kontrol alacak. [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> Uygulamamzn ana sayfasn yukardaki ekilde tasarladktan sonra sra geldi PopUp kontrol ierisinde kullanacamz zel kullanc kontroln (User Control) hazrlamaya. Sz konusu User Control ierisinde de PopUp' kapatacak olan bir dme 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>

246

stteki ekli ile UserControl'mz de tamamladktan sonra artk XAML dosyalarmz ve tasarmlarn bitirdiimize gre Visual Studio ile kod yazma ksmna geebiliriz. lk olarak ana XAML dosyamzdaki Dugme'mizin arkasna PopUp kontroln yaratarak ekrana getirecek olan kodu yazalm. Dim PopupKontrol As New System.Windows.Controls.Primitives.Popup PopupKontrol.Child = New UserControl1 PopupKontrol.IsOpen = True Kodumuzun ilk satrnda System.Windows.Controls.Primitives NameSpace'i altnda yer alan PopUp snfn kullanarak yeni bir PopUp kontrol yaratyoruz. Bir sonraki satrda ise UserControl olarak hazrladmz ve ad UserControl1 olan kontrolmzden bir kopya yaratarak PopUp kontrolnn Child zelliine eitliyoruz. lemleri tamamladktan sonra artk PopUp kontrolmz ekrana getirebileceimize gre IsOpen zelliine True deerini vererek ilerleyebiliriz. PopUp kontrolmz ekranda gsterildiine gre sra geldi PopUp kontrolndeki UserControl1 ierisindeki dmeye basldnda sz konusu PopUp' ekrandan kaldrmaya. Me.Visibility = Windows.Visibility.Collapsed Yukardaki kod ile basit bir ekilde UserControl ierisindeki Dme'nin Click durumunda UserControl'mz grnmez hali getirerek sahneden kaldryoruz. Silverlight uygulamamznda code-behind dosyalarnn son hali aadaki 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

247

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.
DaronYNDEM

248

Silverlight 2.0 RC0 ierisinde ComboBox kullanm. Silverlight 2.0 RC0 ile gelen yeni kontrollerden biri de ComboBox kontrol. Bu yazmzda Combobox'n kullanmna, grsel dzenlemelerin nasl yapldnda gz atacaz. lk olarak yeni bir Silverlight projesi yaratalm ve Expression Blend 2 ierisinden Asslet Library'de bir Combobox bularak sahneye yerletirelim. <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> Yukardaki XAML kodu sahnede bo bir Combobox yaratacaktk. Combobox ierisine 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 Seenek"></ComboBoxItem> <ComboBoxItem Content="kinci Seenek"></ComboBoxItem> <ComboBoxItem Content="Son Seenek"></ComboBoxItem> </ComboBox.Items> </ComboBox> Her ComboBoxItem'n ayrca bir de IsSelected zellii var. Bylece uygulama ilk altrldnda ve ComboBox sahneye ilk geldiinde hangi Item'n seili olacana karar verebilirsiniz. <ComboBox HorizontalAlignment="Left" VerticalAlignment="Top" Width="157" Margin="38,43,0,0"> <ComboBox.Items> <ComboBoxItem IsSelected="True" Content="lk Seenek"></ComboBoxItem> <ComboBoxItem Content="kinci Seenek"></ComboBoxItem> <ComboBoxItem Content="Son Seenek"></ComboBoxItem> </ComboBox.Items>

249

</ComboBox> Tabi ou zaman bizler uygulamalarmzda bu ekilde seenekleri XAML kodu ierisine gmmeyeceiz. Genelde bir veri kaynamz olacak ve veri kaynandaki listelerin ComboBox ierisinde gsterilmesini tercih edeceiz. Bu durumda gelin imdi de ComboBox'a nasl veri balayabileceimizi inceleyelim. lk olarak Urun adnda snfmz tanmlayalm ve bu snf zerinden rneimizde kullanacamz geici 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;

250

public int Fiyat { get { return PFiyat; } set { PFiyat = value; } } } Uygulamamz ilk altrldnda yukarda tanmladmz Urun snfndan nesneler yaratarak bir List deikenine ekleyeceiz. Sonra da bu listeyi ComboboxUrunler adn verdiimiz Combobox'mza balayacaz. [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 = "rn Adi1", .Fiyat = 1000}) Urunler.Add(New Urun With {.Adi = "rn Adi2", .Fiyat = 2000}) Urunler.Add(New Urun With {.Adi = "rn Adi3", .Fiyat = 3000}) Urunler.Add(New Urun With {.Adi = "rn 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 = "rn Adi1", Fiyat = 1000 }); Urunler.Add(new Urun { Adi = "rn Adi2", Fiyat = 2000 }); Urunler.Add(new Urun { Adi = "rn Adi3", Fiyat = 3000 }); Urunler.Add(new Urun { Adi = "rn Adi4", Fiyat = 4000 }); comboboxUrunler.DisplayMemberPath = "Adi"; comboboxUrunler.ItemsSource = Urunler; } Combobox'n ItemsSource zelliine aktardmz liste otomatik olarak Combobox'n ierisine tm elerin yerletirilmesini salayacaktr fakat bizim yarattmz Urun snfnn hangi zelliinin Combobox ierisinde gsterileceini belirlememiz gerekiyor. Bunun iin ComboBox'n DisplayMemberPath zelliine istediimiz Urun snfnn bir zelliinin adn atyoruz. Bylece ComboBox kendisine atanan dizideki her enin sz konusu zelliindeki veriyi kullancya gsterecektir. Eer veri balants sonras ComboBox ierisinde seili olacak eyi belirlemek isterseniz kullanabileceiniz iki yntem var. [VB]

251

comboboxUrunler.SelectedItem = (From gelenler In Urunler Where gelenler.Adi = "rn Adi2").SingleOrDefault comboboxUrunler.SelectedIndex = Urunler.IndexOf((From gelenler In Urunler Where gelenler.Adi = "rn Adi2").SingleOrDefault) [C#] comboboxUrunler.SelectedItem = (from gelenler in Urunler where gelenler.Adi == "rn Adi2" select gelenler).SingleOrDefault(); comboboxUrunler.SelectedIndex = Urunler.IndexOf((from gelenler in Urunler where gelenler.Adi == "rn Adi2" select gelenler).SingleOrDefault()); Bunlardan ilki dorudan ComboBox'n SelectedItem zelliini tanmlayarak seili eyi belirlemek. Yukardaki kod ierisinde elimizde diziden istediimiz Item' bir LINQ sorgusu ile bularak sz konusu Item'n SelectedItem olmas gerektiini belirlemi oluyoruz. Bir dier seenek ise dorudan seili olacak Item'In Index numarasn SelectedIndex deerine aktarmak. ComboBox ierisinde kullanc bir Item setiinde ise dorudan ComboBox'n SelectionChanged event' altrlacaktr. Bylece dorudan SelectedItem zellii zerinden seili eyi alabilir ve bu leyle ilgili bilgilere ulaabilirsiniz. Bizim rneimizde seili enin tipinin de Urun olduunu bildiimiz iin dorudan Urun snfna Cast ederek seili eye ait tm bilgilere ulaabiliyoruz. [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.
DaronYNDEM

252

Silverlight 2.0 RC0 ierisinde PasswordBox kullanm. Silverlight 2.0 RC0 ncesinde Silverlight ierisinde zellikle kullanc girilerinde ifrelerin yazlaca bir TextBox oluturmak epey zahmetli bir iti. Bunun iin normal bir TextBox' sahneye yerletiriyor sonra da bu TextBox'a tm karakterleri * olan bir font balyorduk. RC0 ile beraber artk bu ileme zg bir PasswordBox kontrolmz var. Bu yazmzda PasswordBox'n kullanmna hzlca deineceiz.

Expression Blend 2 ierisinde PasswordBox kontrol. Yeni bir Silverlight projesi yarattktan sonra Expression Blend 2 ierisinde Asset Library blmnde PasswordBox' bulabilirsiniz. Tasarm arayznden yukardaki ekilde bir PasswordBox alarak sahneye yerletirdiinizde XAML dosyasnda aadaki gibi bir kod ile karlaacaksnz. <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 ierisinde bulunduu iin Margin'i ayarlanm durumda. Bu ekilde hazrlanan basit bir uygulamay altrdnzda PasswordBox ierisine girdiiniz her karakter bir nokta ile gsterilecektir.

253

PasswordBox'n varsaylan grnm. PasswordBox'n noktalarla doldurduu karakterlerin yerine farkl bir karakter semek iin PasswordBox'n PasswordChar zelliinden faydalanabilirsiniz. Bu zellie aktardnz karakter PasswordBox ierisine yazlan her karakterin gsteriminde kullanlacaktr. <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 yukarda bahsettiimiz tm zelliklere VB veya C# kodunuz ile ulaabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

254

Silverlight 2.0 Uygulamalar Parametre Gnderimi Silverlight 2.0 uygulamalarn web sayfalarmza OBJECT taglar ile koyacamz biliyoruz. Artk Silverlight 1.0'daki gibi JavaScript ile uramak durumunda kalmayacaz. Durum byle olunca tabi ki bu uygulamalara dardan belirli durumlarda parametreler de gndermek gerekecek. rnein bir Video Player hazrladnz ve ayn sayfada birden ok Video gstermek iin kullanacaksnz fakat bu videolar da sunucu tarafndaki veriye bal olacak. Yani zetle Video Player Silverlight uygulamamz bir ASP.NET Repeater ierisindeyse video dosyasnn adn nasl Silverlight uygulamamza aktarrz? Dardan Parametre Gnderimi lk olarak sayfamz ierisinde Object taglar arasnda bir yerlerde parametrelerimizi belirtmemiz lazm. Bunun iin aadaki 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 saysn arttrmak iin yukardaki param tagnn value zelliine birden ok parametre ve deer ifti verebilirsiniz. Tek yapmanz gereken metin=osman,deger=xx eklinde iftleri birbirinden birer virgl ile ayrmak. Eer ASP.NET ile beraber gelecek Silverlight sunucu kontroln kullanarak uygulamanz sayfanza ekliyorsanz bu durumda aadaki 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 ierisinde nasl kullanacaz? Bir nceki blmde verdiimiz parametrelere Silverlight uygulamalar ierisinde Application nesnesinin Startup durumunda eriebiliyoruz. Sz konusu durumu uygulamanzn App.xaml dosyas ierisinde kodlayabiliyorsunuz. Private Sub Application_Startup(ByVal o As Object, ByVal e As StartupEventArgs) Handles Me.Startup e.InitParams("metin") End Sub

255

Yukardaki ekli ile Application nesnesinin Startup durumuna parametre olarak gelen StartupEventArgs zerinden InitParams dizisinde parametrelerimizi bulabiliyoruz. Fakat aslnda bizim esas istediimiz bu parametrelere dorudan uygulamamzn ana XAML dosyalarnda ulaabiliyor olmak. Bunun iin biraz daha uramamz gerekecek. lk olarak gelin ierisinde bir TextBlock olan XAML kodumuza bakalm. Metin parametresi ile Silverlight uygulamasna aktarlan metni bu TextBlock ierisinde gstereceiz. <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> Grld zere ortada ok kark bir durum yok. Sadece bir TextBlock var. Peki nasl olacak da parametrelerimizi sayfamza aktaracaz. Aslnda sayfa dediimiz XAML dosyalar birer Class. Partial Public Class Page Inherits UserControl ......................... End Class Yukardaki kod bizim herhangi bir XAML kodumuzun arkasnda .NET kodunu gsteriyor. Page adnda bir snf tanmlanm ve bu snf aslnda aadaki ekilde XAML kodumuza da balanm 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 aslnda birer snf olarak tanmlanyor. Peki balangta hangi XAML dosyasnn alaca nasl ayarlanyor? Gelin App.XAML ierisindeki orijinal StartUp eventnn koduna bir gz atalm. 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 aldnda bizim Page snfndan bir adet yaratlarak uygulamann ana grseli haline getirilmi. Yani bir XAML dosyasn yklemek iin aslnda sz konusu XAML koduna bal .NET snf kullanlm. Bu durumda biz Page snfmz bir Property eklesek ve bu Property'ye Application Startup'daki parametreleri aktarsak Page snf ierisinden de tm parametrelere ulamaz myz?

256

Kesinlikle ularz. Hatta zerine bir de yeni alternatif bir Constructer yazdk m aslnda iimiz daha da kolaylar. Gelin tek tek bunlar yapalm. 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 Yukardaki grdnz Property'yi Page snf ierisinde kullanacaz. Bu Property aslnda Application Startup'taki tm InitParams'lar tayabilecek. Zaten sz konusu InitParams'n tipine de baktmzda System.Collections.Generic.IDictionary(Of String, String)) ile karlayoruz. Sra 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 Yukardaki kodu da ekledikten sonra artk istersek yeni bir Page snf yaratrken atanacak olan Parametre listesini de verebiliriz. Page snfmzn tam kodu aadaki ekilde sonlanyor. 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()

257

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 snfmzn kendi Property'si olan InitParams zerinden Metin parametresini alarak TextBlock ierisine yazdryoruz. Peki App.xaml'n arkasna ne yazdk? 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 Grdnz gibi Page snfn yaratrken dorudan uygulamaya gelen tm parametrelerin listesini de snfmza aktaryoruz. Bylece artk Page snfnda da sz konusu tm parametrelere ulalabilecek. Hepinize kolay gelsin.
DaronYNDEM

258

Silverlight 2.0 Uygulamalarnda farkl XAML dosyalar kullanmak. Bir Silverlight uygulamasnda birden ok XAML dosyas kullanarak dosyalar arasnda gei yapmak isteyebilirsiniz. Fakat bu noktada maalesef sizi ufak bir sorun bekliyor. Herhangi bir Silverlight uygulamasnn ana grsel elementini maalesef ki deitirme ansnz yok. Ana grsel element olarak bahsettiimiz ey aslnda Silverlight 2.0 uygulamasnn XAML koduna ait "Root Element" oluyor. Sz konusu root element sadece uygulama ilk altrlrken belirlenebiliyor. Peki bu durumda nasl bir zm gelitirebiliriz? Root Elementi bir Container olarak kullansak? Uygulamamzn ana elementini bir Grid yapsak ve ierisinde XAML dosyalarmz birer UserControl olarak yerletirsek, bylece istediimiz zaman Grid ierisindeki elementlerini deitirerek farkl XAML dosyalar ykletemez miyiz? Gzel bir fikre benziyor. Deneyip grelim. lk olarak ierisinde basit bir ekilde iki adet XAML dosyas ieren yeni bir Silverlight 2.0 projesi yaratyoruz. Bu dosyalardan birinde sadece bir TextBlock varken dierinde bir TextBlock ve bir de Button olarak. lk dosyadaki Button'a basldnda ikinci dosyann yklenmesini salayacaz. Gelin nce dosyalarmzn XAML kodlarna hzlca bir gz atalm. [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"

259

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 alacak olan XAML dosyasnn snf App.xaml ile beraber alan code-behind dosyasna belirlenir. Bu dosyay WPF uygulamalarnda app.xaml'a veya ASP.NET uygulamalarndaki Global.asax'a benzetebilirsiniz. App.xaml uygulama ile ilgili global ilemlerin yapld yerdir. lk olarak app.xaml dosyasnn codebehind ksmna geerek uygulamann OnStartUp durumuna zel bir kod yazacaz. 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 Yukardaki kod ierisinde ilk olarak bir Silverlight 2.0 Grid kontrol yaratyoruz. Unutmayn ki WPF'de de oluu gibi Grid kontrolleri birer DataGrid deiller. Grid kontrolleri HTML'deki karl ile table diyebileceimiz container kontrollerinden sadece biri. Yarattmz Grid kontrol ierisine Page.xaml dosyamz yklemek iin Page.xaml'a ait code-behind'daki snfndan bir kopya yaratarak Grid'imizin children listesine ekliyoruz. Son olarak da uygulamamzn ana / root elementini Grid kontrol olarak tanmlyoruz. Bylece bundan sonra ana elementi deitirmeden dorudan Grid ierisindeki kontrolleri deitirerek aslnda tm uygulama arayzn de deitirmi olacaz. Gelelim Page.xaml dosyamzn code-behind ksmna ve bakalm Page.xaml ierisinde bulunan dmemize basldnda nasl olacak da uygulama arayznden page.xaml' kaldrarak page2.xaml' ykleyeceiz. 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 Yapmamz gereken aslnda u an ierisinde olduumuz Page.xaml dosyasnn parent elementini bularak ierisindekileri silmek. Bunun iin Me.Parent ile Gridimizi yakalyoruz ve sonrasnda children.clear ile sayfadaki hereyi siliyoruz. Son olarak da Page2.xaml dosyamdan bir kopya yaratarak ayn Grid'in ierisine ekliyoruz. Bylece Silverlight 2.0 uygulamamzn ierisinde artk baka bir XAML dosyas yklemi olduk.

260

Silverlight 2.0 ve Adaptive Streaming Silverlight dnyasnda 1.0 srm ile balayan video uygulamalarndaki yksek performans gibi avantajlarn yenileri 2.0 srmnde de tabi ki devam ediyor. Bu yenilikler arasnda en ilginlerinden biri Adaptive Streaming. Bugn internet ortamnda video yayn dediimizde en byk sorunlarmzdan biri farkl bant geniliklerine hitap edebilecek ierii oluturmak. Maalesef lkemizde 1 MBit balanty baz alarak ilerlemek zorunda kalsak da aslnda 4 MBit'e kadar ADSL hatlarnn kullananlarn says hi de az deil. Peki tm bu kullanclara en uygun kalitede video yaynn nasl yapabiliriz? Farkl bant geniliklerine farkl kalitelerde video yayn! Bu hi de yabanc olduumuz bir zm deil. Elimizdeki video dosyasn farkl bitrate'lerde encode ederiz ve kullanclara sitemize girdiklerinde farkl seenekler sunarz. Her kullanc kendi balantsna gre istedii kaliteyi seer. Peki ya videoyu seyrederken bant geniliinde deiiklikler olursa? Varsayalm ki kullancmz paylaml internet bulunan bir ortamda ve kiisel olarak elde ettii bant genilii deiebiliyor. Bu durumda ne yapacaz? Tabi ki "Ykleniyor." mesajlar gstereceiz, yapacak pek bir ey yok! Aslnda var! Adaptive Streaming! Brakn yayn ak bant geniliine uysun! Silverlight 2.0 ile beraber kullanabildiimiz Adaptive Streaming teknikleri ile artk videonuzun kalitesi ile kullancnn bant genilii arasnda iliki ile ilgilenmeniz gerekmiyor. Adaptive Streaming otomatik olarak kullancnn bant geniliini alglayarak uygun kalitedeki video dosyasnn sunucudan ekiyor. Hatta bunu sadece video ilk oynatlrken deil video oynatld srece yapyor! Bylece videoyu bata kaliteli bir ekilde izleyen bir kullancnn bant genilii dtnde video duracana ve "ykleniyor" mesajlar gsterileceine videonun daha dk kaliteli srmlerine otomatik gei yaplyor. Tabi ki bu geilerin hepsi otomatik olduu zere video duraksamyor ve kullanclarmz hibir ey hissetmiyor. Peki tm bunlar iin biz ne mi yapyoruz? Hmm bir ka dmeye tklamak. Expression Encoder 2 SP 1 ile gelenler! Adaptive Streaming iin video ierii hazrlamann birka yolu var. Aslnda ilki oturup gerekli dosyalar tek tek encode ederek gerekli manifest XML dosyalarn da elle hazrlamak. Fakat bu zahmete girmek yerine dorudan Expression Encoder 2'yi de kullanabilirsiniz. SP1 ile beraber Expression Encoder'a gerekli Adaptive Streaming ablonlar da eklendi.

261

Adaptive Streaming iin seenekler. Video profili olarak "Adaptive Streaming"i setiinizde varsaylan ayarlar ile drt farkl kalitede videonun encode edilmesi salanacaktr. sterseniz ek kalite sekmeleri tanmlayabilir veya var olanlar deitirebilirsiniz. Tm bu ayarlar tamamladktan sonra sra geliyor Adaptive Streaming iin hangi altyapy kullanacanza.

Adaptive Streaming iin ne kullanalm? Adaptive Streaming ile yayn yapmann birka yolu var ama bunlarn ncesinden u ufak detaylardan bahsedelim. Adaptive Streaming sadece HTTP zerinden alyor. Zaten Silverlight'n MMS zerinden de HTTP protokol ile altn biliyoruz. O nedenle pek bir deiiklik yok fakat ek olarak burada yarattmz tm video dosyalarnn dorudan HTTP

262

zerinden yaynlanmas gerektiini hatrlatmak isterim. Yani dosyalar IIS gibi bir web sunucusunu zerinden sunulmal. Yukardaki ekran grntsnde de grebileceiniz zere Expression Encoder bizden bir seim daha yapmamz istiyor. "Output Mode" olarak kastedilen aslnda Adaptive Streaming iin dosyalarn ve Manifest'lerin nasl hazrlanmas gerektii ile ilgili. Eer "IIS Smooth Streaming"i iaretlerseniz manifest harici bir XML olarak tutuluyor. "ASF" seenei ise duruma gre tek bir dosyada tm farkl streamleri ve manifesti veya her stream iin bir dosya ve dahili manifestleri oluturuyor. Ama tm bunlar kullanabilene kadar yaklak bir alt ay kadar beklemeniz gerekecek :) Bunun nedeni "Smooth Streaming" iin IIS tarafnda ykl olmas gereken HTTP Handler'larn daha Microsoft tarafndan yaynlanmam olmas. "Smooth Streaming" handlerlarnn 2009'un ilk eyreinde yaynlanmas bekleniyor. Tabi MS'ten nce bu konuda baka bir sunucu altyaps iin kendi HTTP Handler'n yazan olmaz ise :) sonuta kodlar ak. Peki ne yapacak Smooth Streaming? IIS tarafnda alacak olan Smooth Streaming altyapsn u an http://www.smoothhd.com/ adresinden test edebilirsiniz. Tabi gerekten HD kalitesine ulaabilmek iin balantnzn kuvvetli olmas art aksi halde sistem dk kaliteye otomatik olarak geecektir. Smooth Streaming sunucu tarafnda video dosyalarn tamamen istek zerine paralara blerek istemciye gnderiyor. Bu paralar ayr ayr 2, 3 saniyelik video dosyalar olarak dnebilirsiniz. Bu paralama sistemi sayesinde internetin doasnda yer alan proxy ve cache mekanizmalarndan otomatik olarak video ierikleri de faydalanm oluyor. stemci tarafndaki tm ilemler ise MediaStreamSource snf ile hallediliyor. Bu snf ile gelen videodan ka karenin eksik olduu ve saniyede ka karenin mevcut internet hatt zerinden alnabildii gerek zamanl olarak kontrol edilerek kaynak deiimi yaplabiliyor. Tm bu ilemleri yapacak olan kodlar ayr bir AdaptiveStream snf olarak Expression Encoder 2 SP1 ile beraber gelen Silverlight 2 video oynatclarna dahil edilmi durumda. sterseniz haricen bu snflar alp kendi yarattnz uygulamalara da ekleyebilirsiniz. imdilik bu kadar, IIS 7 iin "Smooth Streaming" yaynlandnda iin sunucu tarafna da ayr bir yazda deineceiz. Hepinize kolay gelsin.
DaronYNDEM

263

Silverlight 2.0 ve ADO.NET Data Services Silverlight 2.0 tarafnda veritaban eriimi iin mecburen web servisleri kullanmak zorundayz. Durum byle olunca tek tek veritabanndaki ilemler iin ayr web servisleri yazmak bir noktadan sonra ikenceye dnebiliyor. Bugnlerde zellikle LINQ ve Entity Framework ile beraber data layer'larmzda ciddi kolaylklardan faydalanabiliyoruz fakat web servisleri tarafnda geldiinde ise LINQ vs ile gelen nesneleri geri dndren web servislerini tek tek yazmak yine can skc bir hal alyor. Aslnda tm bu sorunlar zebilecek bir altyap .NET Framework ierisinde artk mevcut. ASP.NET Data Services adn verdiimiz altyap ile beraber bir veritabanna eriimi dorudan REST zerinden yapabiliyorsunuz. Peki nasl? lk nce gelin ASP.NET Data Services sonu olarak nasl bir hizmet yaratyor ona bakalm. Bugn herhangi bir veritabanna farkl where sorgular ile select'ler gndermek istesek bu sorgulardaki where cmleciklerini parametreli hale getirmemiz ve bu parametreleri alarak uygun datay dndren web servisleri yazmamz gerekiyor. Ancak bu ekilde Silverlight ile veritabanna eriebiliyoruz. Farkl senaryolardan eer sorgularnzn filtreleme ekilleri deiirse bu sefer tekrar gidip uygun web servisini yazmak zorunda kalyorsunuz. Baka bir seenek olarak where cmleciklerini parametre alan bir servis yazlabilir fakat bu pek gvenli bir manzara olmaz. Tm bu problemleri zmek iin ASP.NET Data Services ile sorgularnz yazabileceiniz zel bir syntax geliyor ve artk URL zerinden sorgu gnderebiliyoruz. http://localhost:4351/WebDataService1.svc/Uruns(2) rnein yukardaki gibi bir adrese gittiimizde veritabanndaki Uruns tablosunda ID'si 2 olan rnn 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" />

264

<content type="application/xml"> <m:properties> <d:ID m:type="Edm.Int32">2</d:ID> <d:Adi>rn2</d:Adi> <d:KategoriID m:type="Edm.Int32">1</d:KategoriID> </m:properties> </content> </entry> Tahmin ettiiniz zere aslnda bizim normal artlarda yazdmz web servisleri de ksmen bu ii yapyor. Yani bize XML ile istediimiz veriyi gnderiyoruz. imdi bir dnelim, bu ekilde esnek olarak URL zerinden farkl sorgular gnderdiimde bana istediim veriyi XML ile sanki web servisinden sonu dnyormu gibi dndren bir sistem aslnda benim Silverlight tarafndan veritabann sorgulamam iin ok daha esnek bir yap olmaz m? Her farkl sorgu iin ayr ayr web servisleri yazmaktan kurtulmaz mym? Evet :) ama da zaten bu. Tabi bu arada bir web servisinin alma eklide ve salad XML'lerin snytax' ile buradaki biraz farkl. Konumuz dnda olsa da aradaki bu farkn bilincinde olmakta fayda var. Yapalm u ii... Gelin hzl bir rnek ile ASP.NET Data Services yapsnn kullanmn ve Silverlight tarafndaki yansmalarn giri seviyesine inceleyerek ilerleyelim. lk olarak yeni bir Silverlight projesi yaratyor ve yanna da gzel bir ASP.NET sitesi alyoruz. ASP.NET sitemize hemen bir ADO.NET Data Service dosyas eklememiz gerekiyor. Bunu ASP.NET sitenize sa tklayarak "Add New Item" diyerek gelen pencereden uygun dosyay seip 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 eklediinizde hemen karnza yukardaki kodlar kacaktr. Koyu ile yazl ksmlar bizim elle eklememiz gerekiyor. DataClasses1DataContext olarak ad geen ey aslnda projemizdeki bir LINQ2SQL Classes dosyas. ADO.NET'in Data Servisleri zerinden hangi Entity'leri yaynlayacan belirlememiz gerek. Bu nedenle aslnda bir data servisi yaratmadan nce ya LINQ2SQL DBML dosyanz hazrlamanz ya da Entity Framework tarafnda Entity'lerinizi hazrlamanz

265

gerekiyor. Yazmzn konusu dnda olduu iin iin bu ksmna imdilik deinmeyeceim. nemli olan yarattnz bu veri kaynann yukardaki ekilde Data Servisi'nize aktarmanz. Bir sonraki admda ise veri kaynandaki hangi Entity'lere ne ekilde eriim haklar vereceiniz. Yani bu data servislerini kullanarak insanlar sadece SELECT mi yapabilecek, yoksa Update veya Delete ilemi de yapabilecekler mi ona karar vermemiz gerekiyor. Bu noktada gvenlik asndan epey dikkatli olmak gerek. Ben imdilik AllRead diyerek sadece SELECT iin veri kaynandaki tm tablolar * iareti ile atm. Silverlight tarafndaki maceralar. Servisimiz hazr olduuna gre artk sra geldi Silverlight tarafnda bu servisi kullanmaya. Balang iin normal bir web servisi kullanmaktan pek farkl olmadn syleyebilirim. Silverlight projemize sa tklayarak "Add Service Reference" diyoruz ve ADO.NET Data Service'imizin SVC dosyasnn adresini veriyoruz. Bylece gerekli istemci tarafl proxy yaratlm oluyor. Her zamanki gibi veri kaynamz kullanmadan nce servis zerinden bir balant kopyas almamz gerekecektir. Normal artlarda Silverlight ile SoapClient snflarndan kopya alrken bu sefer dorudan DataContext alacaz. [VB] Dim Veri As New ServiceReference1.DataClasses1DataContext(New Uri("http://localhost:4351/WebDataService1.svc/")) DataContext'imizi alrken servisimizin tam yolunu da parametre olarak veriyoruz. Bylece artk bu servis zerindeki tm veriye ulaabiliriz. Sra geldi sorgularmz yazmaya. Silverlight tarafnda web servislerinin kullanmnda da olduu zere tm veri trafiinin asenkron ilerleyeceini hatrlarsak aslnda sorgularmz gnderip sonrasnda ayr bir eventlistener ile sonucu alacamz da tahmin etmek zor deil. ADO.NET Data Services sorgularnn URL zerinden farkl bir syntax ile gittiini grmtk fakat elimizde bir DataContext olduuna gre geri gelen IQueryable nesneleri LINQ ile sorgulayabiliyor olmamz gerekir. Sz konusu LINQ sorgular otomatik olarak Data Services tarafna uygun ekilde evrilerek gnderilecektir. Sz 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);

266

Yukardaki kodlar bir sorgunun sunucu tarafna gnderilmesini salayacak olan kodlar. Sorgumuzu ilk satrda standart LINQ sorgusu olarak yazyoruz fakat unutmayn ki burada baz snrlamalar var. ADO.NET Data Services sorgularnda tm keyword'leri kullanmak mmkn olmuyor. O nedenle eer buradaki LINQ sorgularnda Take vs gibi baz keyword'leri kullanrsanz Visual Studio hata verecektir. Yazdmz sorguyu bir DataSerivceQuery deikenine eitliyoruz ve Query nesnemizi yaratrken de geriye ne tr bir nesne dneceini yine servis zerinden gelen nesne tanm ile belirtiyoruz. Artk sorgumuz hazr olduuna gre BeginExecute ile altrabiliriz. Fakat bu noktada da iki parametreye ihtiyacmz var; birincisi bu sorgu tamamlandnda hangi event altrlacak? Yani bir Callback lazm bize. Asenkron bir Callback yaratarak ilerliyoruz. kinci parametre ise sorgunun kendisi. Bylece CallBack altnda buradaki sorgunun state'i de geri dnecek. [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 adndaki asenkron callback'imiz altnda hemen kendisine parametre olarak gelen Result'n iin AsyncState zerinden Sorgu deikenimizi alyoruz. Artk sorgu tamamlandnda gre alma ilemini de sonlandrp sonucu almak gerek. EndExecute metoduna tekrar Callback'e gelen parametreyi verip sonucun bir deikene aktarlmasn salyoruz ve aldmz deiken zerinden istediimiz veriye ulaabiliyoruz. te bu kadar... Data Services yaps ile Silverlight tarafndaki kodlamann ok kolaylatn sylemek pek doru olmaz. Elimizde veriyi salayan hazr bir web servisi olsayd ok daha rahat bir kodlama ortamna sahip olabilirdik fakat Data Services bize web servislerine dokunmadan tek bir altyapya balanarak istediimiz sorgular alma zamannda oluturma ans tanyor. Tabi bu sorgular sadece SELECT sorgular olmak zorunda deil, yeri geldiinde Update, Delete ve Insert de yapabiliriz. Bu makalemizde giri seviyesinde kalacamz iin imdilik dier ilemlere pek dokunmayacaz.

267

Silverlight 2.0 ve JavaScript kardelii Silverlight 2.0 ile beraber istemci tarafnda VB.NET veya C# kullanabileceimizi artk biliyoruz. Durum byle olunca sz konusu .NET dilleri ile Silverlight uygulamasnn dna karak HTML sayfasndaki klasik HTML elementlerine ulamak da byk kolaylklar salayabilir. Bylece aslnda ksmen u an iin istemci tarafndaki JavaScript'in hakimiyetini krmak da mmkn. Tabi bunun tam tersi senaryolarda da JavaScript tarafndan yola karak Silverlight ierisinde .NET metodlarna ulamak isteyebiliriz. HTML elementlerine ulaalm lk olarak Silverlight tarafnda yazdmz kod ile sayfadaki HTML elementlerine nasl ulaabileceimize bir gz atalm. Bunun iin ilk olarak Silverlight 2.0 Beta 1 uygulamas ierisinden dar karak Browser ierisinde HTMLPage'in Document nesnesini yakalamamz 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 deikenimize sayfadaki mevcut HTMLDocument nesnesini aktardktan sonra artk klasik JavaScript metodu gibi GetElementById metodunu kullanabiliyoruz. Silverlight 2.0 animasyonunun bulunduu sayfadaki "icerik" adndaki HTML elementini yakaladktan sonra basit bir ekilde innerHTML zelliine farkl bir metin aktaryoruz. Bu ekilde VB veya C# kodu ile sayfalardaki HTML elementlerine ulalarak farkl ilemler rahatlk istemci tarafnda yaplabilir. Peki ya bir JavaScript kodu altrmak istersek? stemcideki .NET kodunuz ile sayfalarnzda hali hazrda yer alana JavaScript kodlarn birbiri ile konuturabiliyor olmak tabi ki ok nemli. HTML sayfas ierisinde tanmlanm olan herhangi bir JavaScript metodunu dorudan altrmak iin aadaki kodu kullanabilirsiniz. System.Windows.Browser.HtmlPage.Window.CreateInstance("Uyari") Yukardaki kod ierisinde "Uyari" adndaki JavaScript fonksiyonu altrlyor. Eer bu fonksiyon aadaki gibi tanmlanarak bir parametre alsayd daha farkl bir ekilde altrmamz gerekecekti. function Uyari(mesaj) { alert(mesaj); } Yukardaki JavaScript fonksiyonunu Silverlight tarafndan VB veya C# ile altrrken gndereceimiz parametreyi de ek olarak belirtmemiz gerekecek.

268

System.Windows.Browser.HtmlPage.Window.CreateInstance("Uyari", New String("23")) CreateInstance metoduna verdiimiz ilk parametre altrmak istediimiz JavaScript metodunun ad eklinde dzenlenirken verdiimiz dier parametre ise aslnda JavaScript fonksiyonumuza aktarmak istediimiz dier olas tm parametrelerin bir dizisi. JavaScript tarafndan .NET'e yolculuk... .NET tarafnda hazrladmz ve Silverlight ile istemci tarafnda alan bir metodu JavaScript ile kullanabilmemiz iin ilk aamada yapmamz gereken baz ayarlar var. Bunlardan ilki uygulamamz ilk yklendiinde elimizdeki Silverlight sayfasn HTML sayfasna bir "ScriptableObject" olarak tanmlamamz gerektii. Bunu yapmak iin uygulamamzn App.xaml dosyasnn arkasndaki kodlardan faydalanacaz. 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 Grdnz gibi ilk satrda Silverlight uygulamamzda gsterilecek sayfay yaratyoruz ve bir sonraki satrda hemen sz konusu sayfay mevcut HTML sayfamza bir ScriptableObject olarak kaydediyoruz. Sayfay Silverlight uygulamamzn ana grsel esi haline getirerek kullancya gsterilmesini de samalay unutmayalm. Bu ayar tamamladktan sonra sra geldi JavaScript taraf ile paylaacamz fonksiyonumuzu yazmaya. <System.Windows.Browser.ScriptableMember()> _ Public Function Kare(ByVal X As Integer) As Integer Return X ^ 2 End Function Yukardaki rnekte basit fonksiyon kendisine parametre olarak verilen saynn karesini alarak geri dndryor. Bu fonksiyonun JavaScript taraf ile paylalabilmesi iin kesinlikle yukardaki ekilde ScriptableMember olarak iaretlenmi olmas gerekiyor. Son olarak sra geldi bu metodu kullanabilecek olan JavaScript kodunu yazmaya fakat onun ncesinde dikkat etmemiz gereken bir nokta. Sayfamzdaki herhangi bir Silverlight uygulamas ierisindeki bir metodu dardan kullanabilmek iin ilk olarak sz konusu Silverlight uygulamasn bulmamz gerekiyor. Yani Silverlight uygulamamzn 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"/>

269

</a> </object> Yukardaki ekliyle sayfaya yerletirilen bir Silverlight uygulamasna isim vermek iin uygulamaya ait object taglarna bir ID bilgisi atamak yeterli olacaktr. Artk ID bilgisi zerinden Silverlight uygulamamz ulaarak aadaki gibi JavaScript ierisinden .NET metodumuzu altrabiliriz. SL.Content.Page.Kare(2) Hepinize kolay gelsin.
DaronYNDEM

270

Silverlight 2.0 ve JSON Serialize / DeSerialize lemleri Gnmzde ou AJAX uygulamasnda veri transferi iin JSON format kullanlyor. ASP.NET programcl tarafnda biz farknda olmasak da PageMethod'lar, Web Servisleri veya WCF Servisleri sunucudan JavaScript istemciye asenkron (AJAX) veri tarken JSON ile alyor. ASP.NET dndaki dnyaya da baktmzda tabi ki bu kural geerliliini koruyor, rnein bugn twitter.com kendi uygulamalarndan darya asenkron veri aktarrken JSON formatn kullanyor. Peki Silverlight 2.0 ile salt AJAX mantndan kurtularak artk Web Servislerimizi veya WCF servislerimizi dorudan asenkron olarak kullanabildiimize gre karmza eski JSON kaynaklar gelirse ne yapacaz? .NET nesnelerinden JSON oluturmak. Hikayenin tersinden balayalm ve ilk olarak istemci tarafnda JSON verisi nasl yaratrz onu inceleyelim. Zaten genelde harici bir web servisinden JSON verisi alacaksanz byk ihtimal ile elinizdeki hazr bir JSON verisini de web servisine gndermek durumunda kalacaksnz. Bu gibi bir durumda rahatlkla elimizdeki .NET nesnelerini JSON formatna evirebiliyor olmalyz. Silverlight 2.0 Beta 1 ile beraber gelen snflardan system.runtime.serialization.json.datacontractjsonserializer snfn kullanacaz. Bu snf normal artlarda kullanmak isterseniz herhangi bir Silverlight uygulamasnda Intellisense ile bulma ansnz olmayacaktr. Sz konusu snf harici olarak System.ServiceModel.Web.dll dosyas ierisinde kendisini projemize referans olarak almamz bekliyor. Gerekli referans projeye ekledikten sonra rahatlkla JSON ilemlerini tamamen istemci tarafnda yrtebiliyoruz. Uygulamamzda bir rencinin adn ve soyadn tayacak bir Ogrenci snf kullanacaz. JSON ile eviri ilemleri yaparken elimizdeki evireceimiz nesnenin tipinin belirli ekilde tanmlanm olmas gerekiyor. O nedenle hemen aadaki kod ile tipimizi tanmlayalm. 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)

271

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 ilemi tamamladktan sonra uygulamamza adet metin kutusu ve iki de dme yerletirelim. Bu metin kutularndan ikisi rencinin adnn ve soyadnn gzkecei yer, dieri ise yarattmz JSON verisinin yazdrlaca konum olacak. Dmelerimizi de ilemleri yapmak iin kullanacaz. <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 arkasna gerekli kodlar yazarak metin kutular ierisinden rencinin adn ve soyadn alp bir renci nesnesi yaratalm. Sonrasnda da bu nesneyi JSON verisine evirerek Sonuc adndaki metin kutusuna yazdralm. 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 adn verdiim nesne bir DataContractJsonSerializer nesnesi. Bu nesnenin WriteObject metodunu kullanarak elimizdeki uygun bir .NET nesnesini JSON formatna evirebiliyoruz. WriteObject metodu toplamda iki parametre alyor; bunlardan ilki eviri ilemi esnasnda oluan JSON verisinin yazdrlaca Stream nesnesi, dieri ise evrilecek

272

olan nesnenin ta kendisi. Ben bu rnekte bir MemoryStream kullandm. Son olarak eldeki Stream'i de bir metne evirerek Sonuc adndaki metin kutusu ierisine yazdryoruz. Bylece uygulamamzda dinamik olarak JSON yaratma sorununu zm olduk. Tamamen istemci tarafnda rahatlkla yarattmz .NET nesnelerini JSON formatna evirebiliyoruz. imdi de tam tersi bir senaryoya gz atalm. JSON verisinden .NET nesneleri yaratmak Bir nceki blmde kullandmz rnei aynen kullanmaya devam edelim. Bu sefer de tam tersi bir ilem yaparak Sonuc adndaki metin kutusu ierisine yazlan JSON verisini okuyarak ierisinde rencinin adn ve soyadn alp dier metin kutularnn ierisine yerletirelim. 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 yaratyoruz. Bu sefer DataContractJsonSerializer snfnn ReadObject metodunu kullanacaz. ReadObject metodu okuyaca veriyi bir Stream olarak istedii iin Sonuc adndaki metin kutusu ierisindeki metinden ilk nce bir Byte dizisi sonra da bu diziden bir MemoryStream yaratyoruz. Aldmz MemoryStream'i Cevirici nesnemizin ReadObject metoduna verdiimizde sz konusu metod bize bir Object dndryor. Doal olarak JSON verisi ierisindeki nesnenin hangi .NET nesnesine denk geldiini bilme ans yok. O nedenle biz elle casting yaparak aldmz Object tipindeki deikeni Ogrenci tipine deitiriyor ve gerekli verileri alarak dier metin kutularnn ierisine yerletiriyoruz. Her iki uygulamay da bir rnek projede yaptmzda ilk nce metin kutularna veri girerek JSON verisini yaratabiliyor sonrasnda da JSON verisini Sonuc metin kutusunda elle deitirip tekrar dier metin kutularna gncel deerlerin aktarlabilmesi iin DeSerialize ileminin yaplmasn salayabiliyoruz. Uygulamamzn tam kodu aadaki ekilde sonlanyor. 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

273

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.

274

Silverlight 2.0 ve Socket Programlama Mucizesi Socket programlama Silverlight ktndan beri biz yazlm gelitiricilerin en byk hayali ve bu hayal gerek oluyor. Silverlight 2.0 Beta 1 ile beraber Socket Programlama karmzda. Yani artk istemci ile sunucu arasnda TCP/IP ile haberlemek mmkn. Tabi belirli kurallar var; bu kurallardan ilki sunucudaki uygulamann istemci uygulamann yklendii web sitesi ile ayn konumda olmas. Yani sunucu uygulamanzn web siteniz ahmet.com ise ahmet.com'un reverse DNS Look-Up ile bakldnda kan IP adresine sahip sunucuda bulunmas gerekiyor. Bu durumun Silverlight'n Beta 1 sonras srmlerinde policyfile gibi sistemlerde daha esnek hale getirilecei sylentiler arasnda fakat baktmzda u anki hali ile bile sper bir potansiyel sz konusu. Peki nedir bunun avantaj? Diyorum ya, hayalimizdi diye, peken neden? Web sitelerinde gncel bilgi gstermek her zamanki en byk derttir. Bunu yapabilmek iin ok eskilere dndmzde baz meta taglar ile belirli aralkla sayfann refresh atmasn saladmz gnler bile olurdu. IFRAME vs nin gelmesi ile en azndan bunu sayfada ksmi blmlerde uygulayabilir hale geldik. Sonrasnda AJAX geldi ve ok daha sinsi bir ekilde kullanc farknda olmadan belirli aralklarla sunucudan yeni veri talebinde bulunarak sayfa deimeden yeni ierii gsterebildik. Oysa hep bizi rahatsz eden bir nokta vard, o da u; srekli istemciden sunucuya balanarak bir veri deiikliinin olup olmadn kontrol etmek durumunda kalyorduk. Sunucuya "Yeni birey var m?" diye dakikada bir soruyor ve ounda da hsran ile geri dnyordu. Keke sunucu bize bir "Alo" diyebilse ve deiiklik olduunda istemciyi haberdar edebilse? Teknik olarak bu gvenlik sebepleri nedeniyle zaten mmkn deil nk bir istemci bilgisayara dardan ieriye balant kuramazsnz (kuramamanz gerekir). Peki nasl oluyor da Socket Programming bunu ayor? Aslnda amyor, yine istemci sunucuya balanyor fakat sz konusu balant TCP baznda olduu herhangi bir trafie neden olmadan srekli ak tutulabiliyor. Durum byle olunca sunucu kendisine bal istemciye istediinde sz konusu balant zerinden rahatlkla ulaabiliyor. Sunucu tarafndan ie balayalm. lk olarak sunucudaki programmz hazrlayalm. Sz konusu program kendisine gelen tm istekleri karlayarak gerektiinde istemcilere veri gnderecek. Bizim programmz ierisinde bir TextBox bulunacak ve kutu ierisine metin yazldka kendisine bal tm istemcilere bu metin srekli gnderilecek. 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 deikenlerimizi tanmlyoruz. Bunlardan ilki olan Baglilar deikeni sunucuya bal olan istemcilere veri gnderecek olan StreamWriter nesnelerini bir listesini tayacak. Bylece istediimizde bu liste ierisinde gezerek tm bal olan istemcilere veri gnderebileceiz. yeniTR adndaki deikenimizi yeni bir Threat yaratmak ve her yerden kendisine ulaabilmek iin kullanacaz. TCPBaglantilari deikenimiz var olan Threat'n blocklanmas ve tm event-larnn sfrlanmas iin kullanlacak. Dinleyici adndaki deikenimizi ise tm istemcileri dinleyecek olan ve gelen balantlar alglayacak olan

275

TCPListener nesnemizin ta kendisi. Grdnz gibi bu nesneyi tanmlarken iki parametre aktarmz. Bunlardan ilki herhangi bir IP adresi zerinden bu uygulamaya balanlabilecei anlamna gelirken dier ise sadece 4530 portu zerinden balant yaplabilecei anlamna geliyor. Silverlight 2.0 Beta 1 u anda 4502-4532 aralndaki 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 Uygulamamzdaki dmeye basldnda dinleme ilemini balatmak zere yeni bir Thread yaratyoruz. Sz konusu Thread Bekle Sub'na bal. Yarattmz thread'i hemen balatp 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 ierisinde hemen Dinleyici nesnemizi balatyoruz ve ksr bir dngye giriyoruz. Srekli olarak elimizdeki Threadi sfrlayarak Dinleyici'nin BeginAcceptTcpClient metodu ile istemciden bir balant geleceini belirterek WaitOne metodu ile de bekliyoruz. Eer burada bir balant gelir ve baarl veya baarsz ekilde sonulanrsa bu dng baa gelerek tekrar yeni bir balant bekleyecek. BeginAcceptTcpClient ierisinde parametre olarak verdiimiz BaglantiGeliyor event-handlar herhangi bir balant geldiinde altrlacak. 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("Balandnz.") End If End Sub Baglanti geldii anda bekleyen Threat'leri devam ettirmek adna TCPBaglantilari.Set() metodunu aryoruz. Unutmayalm ki programmz ayn anda sadece tek istemcinin balantsn authenticate edebilir, yani dierleri bir nceki istemci balanp balantsn oluturana kadar bekleyecektir. Bu noktada artk istemci balant kurma ilemini tamamlad iin dierlerine yol veriyoruz. Musteri adnda bir TCPClient yarattktan sonra Dinleyici'nin EndAcceptTcpClient metodu ile args parametresi zerinden gelen Request'i alyoruz. Eer

276

Musteri bal ise, yani Connected ise artk sra geldi ona veri gndermeye. Musteri'nin yani TCPClient'n Stream'ini alarak bundan bir StreamWriter oluturuyoruz. Bu Stream zerinden artk istemciye istediimiz veriyi gnderebiliriz. Unutmayn ki uygulamamzda bir TextBox vard ve ierisine birey yazldnda tm bal kullanclara gnderecektik. Bunun iin sonra kullanabilmek adna elimizdeki canl Stream'leri saklamak sorundayz. Global olarak tanmladmz Baglilar adnda Generic.List'e elimizdeki Stream'i aktaryoruz. Bu arada kullancya "Balandnz" diye de bir metin gnderiyoruz. 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 Artk TextBox ierisinde deiiklik olunca bunu istemcilere gndermek ok kolay. Basit bir ekilde Generic.List ierisinde gezin ve her Stream'e elinizdeki veriyi gnderin. stemci tarafnda neler olacak? Silverlight tarafnda ok basit grsellikte bir uygulamamz olacak. Sadece bir TextBlock! Uygulama tarayc ierisinde ilk aldnda sunucuya balanacak ve gelen veriyi srekli olarak sz konusu TextBlock ierisinde gsterecek. <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 yukardaki ekilde dzenledikten sonra hemen code-behind dosyasna geerek balant kodlarmz yazmaya balayalm. 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

277

Silverlight uygulamas ilk yklendiinde hemen bir Socket balants yaratmak iin System.Net.Sockets.Socket zerinden ilerliyoruz. Hat adndaki deikenimizi yaratrken verdiimiz parametrelerden ilki olan InterNetwork bizim balant iin IPv4 kullanacamz ve ikinci parametre de TCP kullanacamz belirtiyor. Asenkron bir alma yaps iin bir de SocketAsyncEventArgs nesnesi yaratarak sz konusu nesneyi Hat adndaki Socket'imize balyoruz. Args'n RemoteEndPoint zellii istemcinin balanaca sunucunun adresini ve port bilgisini ieriyor. Balanti oluturulduunda elimizdeki SocketAsyncEventArgs nesnesi olan Args'n Completed event-handlar alaca iin ona da dinamik bir event-handler olarak Baglandi metodunu atyoruz. Son olarak ConnectAsync diyerek Socket deikenimizin eldeki SocketAsyncEventArgs ile sunucuya balanmasn salyoruz. 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 Artk istemci sunucuya balandnda gre sra geldi kar taraftan yeri geldiinde veriyi almaya. Hatta ilk balant esnasnda hatrlarsanz bizim sunucumuzun "Balandnz" diye bir metin gnderiyordu. Gelen veriyi alabilmek iin ve srekli gelen veriyi dinlemek iin eldeki Socket'i alarak srekli dinleme durumunda olmamz art. Kodumuzdaki event-handler ierisinde e parametresi aslnda bizim bir nceki admda tanmladmz Args adanki SocketAsyncEventArgs'n ta kendisi. SetBuffer ile veriyi nbelleklemek iin kullanacamz ayarlar da bir Byte deikeni zerinden aktardktan sonra ilgin bir ekilde elimizdeki eventhandlerlar deitiyoruz. Bundan sonra Args'n Compeleted durumu yeni bir balant olutuunu deil yeni veri geldiini bildirecei iin farkl bir event-handler balamamz gerekiyor. Baglandi adndaki metodumuzla Args'n ilikisi keserek Geldi adnda farkl bir metoda balyoruz. Son olarak Page.Load'a atadmz ve e.UserToken zerinden alabileceimiz ana Socket deikenimizi de yakalayarak ReceiveAsync metodu ile veri almn balatyoruz. Geldi ve Baglandi metodlar aslnda Silverlight ierisinde ayr bir Thread ierisinde alyor. Bu nedenle tm bu ilemler yaplrken kullancnn uygulama ile olan interaktivitesi kesinlikle kesilmiyor. Tabi ayr bir Thread gibi davranyor olmasn dezavantaj ise birazdan karmza kacak. Ksr dng ierisinde sreki ReceiveAsync ile sunucuyu dinlerken istemci tarafnda grsel arayzde deiiklik yapamayacaz. Bu da bizim sunucudan veri alabilmemizi fakat ekranda gstermememize neden olacak. Tabi demokrasilerde are tkenmez... Delegate Sub MyDelegate(ByVal myArg2 As String) Sub GelGel(ByVal x As String) Metin.Text = x End Sub

278

lk olarak bir Delegate tanmlayacaz, sz konusu delegemiz sadece bir parametre alacak. Ayrca bir de Sub yaratyoruz. Ayn ekilde Sub'da bir metin parametresi alyor ve bizim uygulamamzda ad Metin olan TextBlock ierisine yerletiriyoruz. te bu yap ile biraz nce bahsettiimiz sorundan kurtuluyor olacaz. 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 Aslnda sunucudan gelen veriyi almak ok kolay. Kodumuz ierisindeki ilk satr bu ii hallediyoruz. Esas mesele veriyi aldktan sonra sahnede gstermek. Dispatcher nesnesi belki de Silverlight ierisinde en ilgin yaplardan biri; Dispatcher ile mevcut Thread'i yakalayarak BeginInvoke ile baka bir metod altryoruz. altracamz metodu sunucudan gelen veriyi parametre olarak vereceiz ve sz konusu metod (GelGel) bu veriyi alarak sahnedeki Metin adndaki TextBlock ierisine yerletirecek. BeginInvoke ile ilgili iimizi de tamamladktan sonra artk tekrar sunucunun dinlenmeye balanmas iin elimizdeki Socket'i yakalayarak ReciveAsync metodunu altryoruz. Bu sistem byle sonsuza tek dnecek ve sunucudan gelen veri srekli olarak tm istemcilerde annda gsterilecek. Son olarak hem istemci hem de sunucu uygulamann tam kodunu sizlerle paylamak 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

279

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()

280

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("Balandnz.") 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.
DaronYNDEM

281

Silverlight 2.0 XAP Paketleri ve Kaynak Dosyalar Silverlight 2.0 uygulamalarnda tm uygulamaya ait VB veya C# kodu ile beraber XAML dosyalarnn da birer DLL olarak dzenlendiini ve sonrasnda XAP adnda, znde ZIP dosyalar eklinde paketlenerek istemciye gnderildiini biliyoruz. Durum byle olunca bir Silverlight uygulamas ile beraber sunucudan istemciye farkl kaynaklar gndermeyle ilgili deiik yollar sz konusu oluyor. Bunlardan en basiti tabi ki sunucuda yer alan hali hazrdaki bir dosyay asenkron bir istek ile istemciye tamak. Fakat bu durumda eer istenecek olan veri ok ufaksa aslnda ilk Silverlight uygulamasnn yklenmesinde kullanlan veri transferinde bu ufak dosyalar da ana XAP dosyas ile beraber gnderilebilirdi. Bylece hem toplamda sunucuya gnderilen istek says azalrd hem de XAP dosyalarnn yaps gerei sktrma zelliinden faydalanlm olurdu. Build Action : Resource Visual Studio ierisinde Silverlight projelerinde herhangi bir dosyay setikten sonra "Properties" paneline gz attmzda "Build Action" adnda bir ayar grebilirsiniz. Bu ayar ile sz konusu dosyann ne ekilde sunucudan istemciye gnderileceini ayarlam oluyoruz. Varsaylan ayarlar ile projenize bir resim dosyas eklediinizde Build Action ayar Resource olarak dzenlenmi olacaktr. Bu dosyalar dorudan Silverlight uygulamas iin yaratlacak DLL dosyas ierisine Resource olarak yerletirilecektir. DLL dosyasnn yklenme sresini uzatmamak adna olabildiince ufak ve nemli dosyalar bu ekilde projelere eklemekte fayda var. <Image Source="Foto.jpg"/> Bu ekilde projelere eklenmi dosyalar XAML ierisinde dorudan yukardaki gibi kullanabilirsiniz. Build Action : Content Eer dosyanzn orijinal DLL'i iirmesini istemiyorsanz fakat yine de ayn XAP dosyas ierisinde istemciye gitmesini istiyorsanz. Kullanmanz gereken seenek "Content" seenei. Bu ekilde iaretlenmi dosyalar XAP dosyas ierisine konarak istemciye gnderilir. Eer istemci tarafnda Plug-In hedef dosyay XAP dosyas iinde bulamazsa bu sefer XAP dosyas ile ayn klasrde sunucu zerinden dosyay almaya alyor. <Image Source="/Foto.jpg"/> Normalinden farkl olarak bu sefer tm verilen adreslerin banda bir / yerletirilmesi ve relative konum verilmesi gerekiyor. Her ihtimale kar yine de ok byk dosyalar da bu ekilde kullanmamakta fayda var. nk unutmayn XAP dosyas istemciye tamamen gitmeden uygulamanz almayacaktr. Hepinize kolay gelsin.
DaronYNDEM

282

Silverlight 2.0 XAP Paketleri Silverlight 2.0 (Beta 1) yazlarmn yava yava geleceinden bahsetmitim. te ilki ile karnzdaym. Bu yazda Silverlight 2.0 Beta 1 ile beraber gelen yeni datm eklinden bahsedeceiz. Silverlight 1.0 uygulamalarnda sitenize herhangi bir Silverlight animasyonu yerletirebilmeniz iin epey emek harcayarak birden ok JavaScript dosyasn sayfanza linklemeniz sonrasnda uygun HTML elementlerini ayarlamanz hatta bir de yannda XAML dosyanz koymanz gerekiyordu. Bu durum Silverlight 2.0 ile beraber deiiyor ve karmza XAP uzantl dosyalar geliyor. XAP'n herhangi bir alm yok (en azndan imdilik). XAP dosyalar aslnda znde birer ZIP dosyas. Bu dosyalar ierisinde Silverlight projenize ait DLL'ler bulunuyor. Silverlight 2.0 ile beraber VB veya C# kullanarak kodlama yapabildiimiz iin bu kodlardan DLL dosyalar yaratlyor ve sz konusu DLL'ler XAP dosyas ierisinde istemciye gnderilerek istemci tarafnda Silverlight Run-Time ile altrlyor. Expression Blend ile hazrladnz XAML dosyalar da ayn DLL dosyalar ierisine birer Resource olarak ekleniyor. u an ASP.NET 3.5 Extensions paketi ierisinde yer alan ve ileride ASP.NET'e eklenmesi dnlen kontrollerden biri olan Silverlight kontrol XAP dosyalarn alarak dorudan ASP.NET sayfalarna yerletirilebilecek. rnek bir Silverlight kontrolnn kodunu aada inceleyebilirsiniz. <asp:Silverlight runat="server" PluginBackground="White" Source="animasyon.xap" Version="2.0"> <PluginNotInstalledTemplate> Plug-In Ykl Deil </PluginNotInstalledTemplate> </asp:Silverlight> Grdnz gibi artk bir Silverlight 2.0 animasyonunu herhangi bir ASP.NET sitesine yerletirmek ocuk oyuncana dnm. Tabi "artk"derken bu kullandklarmzn hibirinin daha yaynda olan yazlmlar olmadn da aklda tutmakta fayda var. Fakat gelecein byle olduunu grmek ho. Bir XAP dosyasnda neler var? lk olarak tabi ki bizim yazdmz uygulamann kodlarn ve XAML kaynaklarn ieren DLL dosyamz var. Bu DLL dosyasn De-Compile ettiimizde ierisinde Resource olarak XAML dosyalarmzn var olduunu grebiliyoruz.

283

Silverlight 2.0 DLL dosyas ierisindeki XAML dosyalarmz. Haricen Silverlight 2.0 projemizde kullandmz kontrollere ait DLL dosyalar da yine XAP ierisinde bulunuyor. Silverlight 2.0 ierisinde standart kontroller bile ayr DLL dosyalar olarak geliyor. Bunlarn zamanla Plug-In'e dahil edilip edilmeyecei belli deil fakat Silverlight 2.0 mimarisinde harici DLL dosyalarndan farkl kontroller kullanlabilecei iin bu yap her zaman var olacaktr.

Silverlight 2.0 Beta 1 XAP dosyas ierii. XAP dosyas ierisinde bir de XAML dosyas bulunuyor. Aada ieriini inceleyebileceiniz rnek bir AppManifest.xaml dosyasna baktmzda XAP paketi ierisinde tm DLL'lerin snf isimleri ile ilikilendirildiklerini gryoruz. <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 ierisindeki EntryPointAssembly uygulama ilk altrldnda hangi DLL'in balatlacan belirliyor. Bu haliyle yeni Silverlight 2.0 paketlerine baktmzda olayn epey derlenip toparlandn gryoruz. zellikle Silverlight 1.0 ile ilgili ska akla gelen "kod gvenlii" sorunlar ile ilgili ksmi bir ilerleme var diyebiliriz. En azndan artk XAP (ZIP) dosyasn amanz DLL'i

284

karmanz ve De-Compile etmeniz gerekiyor. Tabi ki tm bunlar mmkn :) fakat biraz daha zametli hale geldi diyebiliriz. Ayrca artk Silverlight uygulamalarnn datm ve paylam ok daha kolay. zellikle bu tip animasyonlar ierik ynetim sistemlerinde kullanmak isteyenler iin SL 2.0 byk kolaylk olacaktr. Hepinize kolay gelsin.
DaronYNDEM

285

Silverlight 2.0'da farenin hareket etmediini anlamak. Bu yazmzda Silverlight 2.0 RC0 ile Silverlight uygulamas ierisinde minik bir ekran koruyucusu yapacaz. Aslnda amacmz ekran korumak deil tabi ki, istediimiz ey kullanc Silverlight uygulamasn kullanmadnda farkl bir ierik gstermek. Bu belki bir reklam, belki farkl bir "Ekrana Geri Dn Kullanc" sesli mesaj veya ok daha farkl bir uyar sistemi olabilir. zellikle veritaban zerinden veri alarak bu veriyi dzenleyen bir Silverlight uygulamasn dnrsek belki de kullanc uzun sre ekran banda deilse verileri sunucuya gndererek kaydetmek iin doru zaman yakalamz demektir. Bu sistemin kullanlabilecei dier rnekleri sizin hayal gcnze brakyorum. Animasyonlarmz hazrlayalm rneimizde grsel olarak herhangi bir ek e yer almayacak. Kullanc fareyi hareket ettirmezse bir sre sonra uygulamann ana Grid'inin rengini siyaha evireceiz. Kullanc fare ile herhangi bir hareket yapt anda ise tekrar sz konusu Grid'i beyaza evireceiz. Siz rneklerinizde ok daha farkl ilemler yapabilirsiniz. imdi gelin bu iki animasyonla beraber oluan XAML kodumuza gz atalm. <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>

286

Grdnz gibi kodumuzda yer alan iki animasyon da LayoutRoot adndaki Grid'in rengini bir saniyede deitirmeyi hedefliyor. Animasyonlardan Geldi adndaki Storyboard Grid'in rengini beyaza alrken, Gitti adndaki ise Siyah'a gtryor. Kullanc fareyi hareket ettirmediinde yani ekran bandan gittiinde Gitti, geri geldiinde ise Geldi animasyonunu oynatacaz. DispatcherTimer yeti imdadmza! Farenin kullanc tarafndan hareket ettirilip ettirilmedii srekli kontrol etmek yerine aslnda bizim ana bir Timer'a ihtiyacmz var. Varsayalm ki be saniye boyunca herhangi bir hareket olmamsa ekran karartacaz. Bu durumda farenin oynatld son harekette bu be saniyelik sayac balatmamz gerek. Biz hangi fare hareketinin son hareket olduunu anlayamayacamz iin aslnda farenin her hareketinde sayacmz balatmalyz fakat sonrasnda eer fare tekrar hareket ettirilirse sayac durdurup batan balatmamz gerek. lk olarak Timer olarak kullanacamz DispathcerTimer' global olarak tanmlayalm. [VB] WithEvents Kontrol As New System.Windows.Threading.DispatcherTimer [C#] System.Windows.Threading.DispatcherTimer Kontrol = new System.Windows.Threading.DispatcherTimer(); Uygulama ilk olarak istemciye yklendiinde hemen elimizdeki Timer'n Interval yani tekrar araln dzenleyerek Timer' balatmamz 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(); } Eer fare hareket etmezse yukardaki Timer sonuna kadar alacak ve doal olarak Timer'n Tick event' altrlacaktr. Fakat bu srete eer fare oynatlrsa bizim bu Timer' durdurup batan balatmamz gerek ki sayacmz da bir anlamda sfrlam olalm. Uygulamamzn MouseMove durumunu yakalamamz yeterli olacaktr.

287

[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(); } Sra geldi Timer'n Tick eventna gerekli kodu yazmaya. Aslnda bu noktada yazacamz tek kod bizim Gitti animasyonunu altracak olan kod olacak. Bylece uygulama kullancnn fareyi be saniyedir oynatmadn alglam ve gerekli ilemi 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 ierisinde ilginizi eken nokta eminim ki Gitmis deikenidir. Gitmis deikeni uygulamamzda global olarak tanmlayacamz bir Boolean deikeni. Bu deikeni ScreenSaver yapmzn alp almadn kontrol etmek iin kullanacaz. Bylece MouseMove durumunda daha nce eer ekran karartlm ise ekran aydnlatabileceiz. 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

288

Geldi.Begin() End If End Sub [C#] void Page_MouseMove(object sender, MouseEventArgs e) { Kontrol.Stop(); Kontrol.Start(); if (Gitmis) { Gitmis = false; Geldi.Begin(); } } Grdnz gibi fare her oynatldnda sayacmz sfrlarken daha nce ekran karartlm m kontrol ediyoruz. Eer karartlm ise hemen aydnlatma ilemini balatyoruz ve tabi ki Gitmis deikenimizi de False olarak ayarlyoruz. Uygulamamzn tam kodu aadaki ekilde sonlanyor; [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

289

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) {

290

Gitmis = false; Geldi.Begin(); } } void Page_Loaded(object sender, RoutedEventArgs e) { Kontrol.Interval = new TimeSpan(0, 0, 5); Kontrol.Start(); } } } Hepinize kolay gelsin.
DaronYNDEM

291

Silverlight ierisinde ClipBoard kullanm Silverlight uygulamalar ierisinden "Clipboard"a ulamak istediinizde maalesef hazr bir altyap ile en azndan imdilik Silverlight 2.0 Beta 2 ierisinde karlamyoruz. Ayn ekilde Silverlight 1.0 ierisinde de bu sorun iin bir zm yok. Fakat zellikle Silverlight 1.0 tarafnda zaten JavaScript'in ana programlama yaps olduunu dnrsek "Acaba tarayc ierisinde JavaScript ile bir zm oluturabilir miyiz?" sorusu akla geliyor. Bu sorunun cevab en azndan Internet Explorer iin "Evet". FireFox varsaylan ayarlar ile bu gibi ilemlere JavaScript tarafnda olanak tanmyor. Silverlight 1.0 ile Clipboard kullanm Yeni bir Silverlight 1.0 projesi yaratarak ierisine bir TextBlock ve Rectangle yerletirelim. Yapacam ilem TextBlock ierisinde yazl metni Rectangle'a basldnda ClipBoard'a tamak 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> Yukardaki kod uygulamamzn grsel arayzn oluturuyor. "Dugme" adndaki Rectangle nesnemizin MouseLeftButtonDown durumunda altrlacak olan kodu birazdan yazacaz. function Kopyala(sender) { window.clipboardData.setData("text", sender.findName("Etiket").Text); } Kodumuz ierisinde kullandmz clipboardData snf ile ilgili detaylara MSDN zerinden ulaabilirsiniz. setData metodu toplamda iki parametre alyor; bunlardan ilki ClipBoard'a kopyalanacak olan verinin tipi, ikincisi ise kopyalanacak olan ieriin ta kendisi. Ayn ekilde isterseniz ClipBoard'dan veri almak iin 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 dorudan elde ettii veriyi dndryor.

292

Peki ya Silverlight 2.0 tarafnda neler yapacaz? Aslnda ok farkl bir ilem yapmayacaz. Silverlight 2.0 Beta 2 tarafnda da imdilik JavaScript'in nimetlerinden faydalanmak zorundayz. O nedenle istemci tarafndaki VB veya C# kodumuz ile sayfann JavaScript tarafndaki zelliklerine ulap yine JavaScript tarafndaki metodlarn altracaz. lk olarak Silverlight 2.0 Beta 2 uygulamamzn arayzn aadaki ekilde dzenleyelim. <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="Yaptr" x:Name="btnYapistir"/> </Grid> </UserControl> Bir TextBox ve iki Button'dan oluan uygulamamzn ilk olarak kopyalama ilemini yapacak olan kodunu yazalm. [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.GetP roperty("clipboardData"); Clipboard.Invoke("setData", "text", txtMetinKutusu.Text).ToString(); } Kodumuz ierisinde ilk olarak taraycnn clipboardData snfn yakalamamz gerekiyor. Bunun iin ierisinde olduumuz taraycnn (Browser) yine mevcut HTML sayfasnn (HtmlPage) ait olduu pencereyi (Window) yakalayp onun zerinden GetProperty ile clipboardData'y alarak ScriptObject tipinde yarattmz Clipboard deikenimize

293

aktaryoruz. Sonrasnda dorudan deikenimiz zerinden Invoke diyerek ayn Reflection yapar gibi setData metodunu altryoruz. Normal artlarda JavaScript tarafna vereceimiz parametreleri de yine Invoke metoduna aktaryoruz. Bylece kopyalama ilemini 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.GetP roperty("clipboardData"); txtMetinKutusu.Text = Clipboard.Invoke("getData", "text").ToString(); } Clipboard'dan veri alrken de ayn ekilde clipboardData nesnemizi yakaladktan sonra bu sefer getData metodunu altryoruz ve geriye dnen deeri de rneimizde TextBox ierisine yazdryoruz. C# kullananlarn haricen aadaki ekilde uygulama balangcnda Event-Handlar balantlarn yapmalar gerekecektir. VB kodlarndaki Handles keyword' ile bu ilem satr iinde yaplabildii iin ek olarak yazmak gerekmiyor. [C#] public Page() { InitializeComponent(); btnKopyala.Click += new RoutedEventHandler(btnKopyala_Click); btnYapistir.Click += new RoutedEventHandler(btnYapistir_Click); } Bylece hem Silverlight 1.0 hem 2.0 ierisinde Clipboard'dan veri alarak veri aktarm yapabildik. Tabi tm bu ilemlerin sadece Internet Explorer ierisine olmas zc. Dier tarayclar iin de geerli olacak ekilde umarz ileride Silverlight Runtime ierisine standart ilevsellikler eklenir. Hepinize kolay gelsin.
DaronYNDEM

294

Silverlight ierisinde sayfa adresine ulamak Bugnlerde bana ska gelen sorulardan biri Silverlight tarafndan uygulamann alt adresin nasl alnaca ile ilgili oluyor. Aslnda basit bir ekilde Silvetlight'tan DOM'a kmanz bunun iin yeterli olacaktr. Peki bunu nasl yaparz? Silverlight ierisinden DOM'a kmak iin yolculuunuzun balayacan namespace System.Windows.Browser namespace'i olacaktr. Bu NameSpace ierisinden ister sayfadaki JavaScript metodlarna ular ister sayfadaki HTML elementlerine ulaabilirsiniz. [C#] MessageBox.Show(System.Windows.Browser.HtmlPage.Document.DocumentUri.Abs oluteUri.ToString()); Yukarda grdnz kod Silverlight uygulamanzn alt sayfann tam yolunu verecektir. DocumentUri zerinden giderek bu adrese ait farkl bilgileri de alabilirsiniz. Hepinize kolay gelsin.
DaronYNDEM

295

Silverlight Runtime ve SDK DLL'leri ve aklamalar Silverlight 2.0 ile beraber artk tm yazdmz kodlarn DLL olarak XAP dosyalar ierisinde istemciye gnderildii bir ortamda harici DLL ktphaneleri de kullanabiliyor olmak byk avantajlar getiriyor. Tabi ki bu avantajlardan rnn kendisi de faydalanyor ve Silverlight 2.0 Beta 2 Runtime ve SDK ile beraber gelen ou harici kontrol normal artlarda Expression Blend 2.5 ierisinde gzkmese de aslnda DLL'ler eklinde bilgisayarlarmzda bulunuyor. Bu yazmzda Silverlight 2.0 Runtime'n ve SDK'nn derinliklerine inip bahsettiimiz DLL'leri inceleyerek neler yapabileceimize gz atacaz. Silverlight Runtime yklemesinde bilgisayarnzda C:\Program Files\Microsoft Silverlight\2.0.30523.6 konumuna yerletirilecek olan DLL'leri sz konusu klasr aarak bir inceleyelim.

Silverlight 2 Beta 2 Runtime DLL'leri. Yukardaki DLL'lere baktmzda zellikle eski VB snflarn desteklemek adna Microsoft.VisualBasic.dll'in Silverlight RunTime ile beraber de datldn gryoruz. Buradaki DLL'lerden bazlarna zellikle eilmek gerekirse dikkati ekenler arasnda System.XML.dll yer alyor. Windows'takine kyasla bu DLL ierisinde artk XSL veya XPath snflar bulunmuyor, tabi ki bunun ok mantkl bir nedeni var; zellikle XPATH yerine artk elimizde XLINQ olduu iin bu snflar muhafaza etmek sama olurdu. System.Core.dll ve System.Xml.Linq.dll ite tam bu noktada yardmmza kouyor ve LINQ'in neredeyse tm zelliklerini Silverlight tarafna tayor. Son olarak System.Windows.Browser.dll ise bir Silverlight uygulamasnn ierisinde bulunduu tarayc ile ilgili ilemler yapabilmesi iin gerekli snflar ieriyor.

296

imdi de gelin SDK ile beraber gelen DLL'lere gz atalm; bunun iin bilgisayarnzda C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client klasrne ufak bir yolculuk yapmanz yeterli olacaktr.

Silverlight 2 SDK paketindeki DLL Ktphanaleri SDK ierisinde DLL'leri RunTime ierisindekilerden daha heyecan verici. lk olarak IronPython ve IronRuby programlama altyapsn sunan DLL'lerini burada bulabiliyoruz. Tm bu DLL'ler arasnda bize DataGrid gibi farkl kontroller sunan DLL'ler ise System.Windows.Controls snfndaki dosyalar. System.Windows.Controls.dll ierisinde standart Silverlight kontrolleri, System.Windows.Controls.Extended.dll ierisinde Calendar, DatePicker, Slider, WatermarkedTextBox gibi kontroller, System.Windows.Controls.Data.dll ierisinde ise daha WPF'de bile olmayan DataGrid bulunuyor. Tm bu DLL ktphaneleri Silverlight uygulamalarnz almas iin hayati nem tarken zellikle ek kontrolleri kullanabilmek adna gerekli DLL'leri projenize referans olarak da eklemeniz gerekecektir. Hepinize kolay gelsin.
DaronYNDEM

297

Silverlight Toolkit ierisinde gelen hazr renk ablonlar (Thema) inceliyoruz. Silverlight Toolkit konusunda yazlarma devam edeceimden bahsetmitim. Bu yazmzda Silverlight Toolkit ile beraber gelen theming (renk ablonlar) yapsna gz atacaz. Hali hazrda Toolkit ile beraber gelen ablonlarn nasl kullanlabildiini inceleyeceiz. Yarattmz yeni bir Silverlight 2.0 projesini Blend 2 ile atktan sonra ilk aamada hemen Silverlight Toolkit ierisindeki gerekli DLL'leri referans almamz gerekiyor. Toolkit paketini bilgisayarnzda atnzda iinde Themes adnda bir klasr olduunu greceksiniz. Bu klasr ierisinde her bir DLL farkl bir renk ablonunu temsil ediyor. sterseniz hepsini referans olarak ekleyebilir veya sadece kullanacaklarnz projenize dahil edebilirsiniz. rneimizde ben hepsini referans olarak alacam ki aradaki farklar grelim.

Blend 2 ierisinde projeye referans eklerken. Themes klasrndeki tm DLL'leri referans olarak aldktan sonra bir de Toolkit paketinin ana klasrndeki Microsoft.Windows.Controls.Theming.dll dosyasn referans olarak almalsnz.

298

Tm hazr Theme'ler kontroller eklinde Asset Library'de. Tm DLL'leri doru ekilde projenize referans olarak eklediinizde Blend 2 ierisinde Asset Library'nin Custom Controls blmnde her bir Thema iin ayr bir kontrol greceksiniz. Bu kontrollerin kullanm biraz garip :) Herhangi bir thema'dan etkilenmesini istediiniz tm kontrolleri bu yukardaki thema kontrolleri ierisine koymanz gerekiyor. Yani aslnda bir anlamda kendileri birer LayoutControl gibi davranyorlar.

Blend ierisinde Theme kontrollerinin yaps. Yukardaki ekran grntsnde grdnz zere ExpressionDarkTheme'den etkilenmesini istediimiz tm kontrolleri bir Canvas ierisinde kendisine teslim etmiiz. Theme kontrolleri aslnda ilerine sadece bir kontrol alabiliyorlar o nedenle Canvas gibi ayr bir LayoutControl daha kullanmamz gerekiyor. Bu yap sayesinde bir uygulamada birden ok ablonu farkl uygulama blmlerinde kullanabilirsiniz. rnein bir Grid'in iki kolonu ierisinde farkl Theme kontrolleri koyarak bu

299

kontrollerin ierisinde sz konusu ablonlardan faydalanabilir ve bu ekilde farkl kombinasyonlar ile de alabilirsiniz.

Toolkit ierisinde hazr renk ablonlar. Yukardaki ablonlar dorudan Toolkit ierisinde hazr olarak gelen ablonlarn rnekleri. Tasarmclarn ne kadar houna gider bilemiyorum :) ama yazlmclarn ok iine yarayacandan eminim. steyenler Toolkit paketi ierisinde Themes/XAML klasrnde bu tasarmlarn XAML kodlarn da bulabilirler. Hepinize kolay gelsin.
DaronYNDEM

300

Silverlight Toolkit'ten WrapPanel'in kullanm. Layout kontrolleri XAML ile arayzler olutururken "olmazsa olmazlar" listemizin en banda geliyor. Silverlight 1.0'daki Canvas kontrolnden sonra 2.0'da birok kontrol yardmmza yetise de maalesef WPF'deki zenginlie ulaamamt. Bu eksiklii Silverlight Toolkit karlyor ve paket ierisindeki WrapPanel ayn WPF ierisindeki ilevsellikleri Silverlight iin de salyor. Silverlight Toolkit DLL'lerinden Microsoft.Windows.Controls.DLL dosyasn Silverlight 2 projenize referans olarak ekledikten sonra WrapPanel kontroln Blend 2 ierisinde Asset Library'de "Custom Controls" tabnda bulabilirsiniz.

Expression Blend 2 ierisinde Silverlight Toolkit'ten WrapPanel. Bu noktadan sonra Blend ierisinde dorudan bir WrapPanel'i sahneye yerletirebilirsiniz. Peki nedir WrapPanel? WrapPanel ierisindeki kontrolleri bir sepete atrlm gibi srekli toplayarak kendi iine sdrmaya alan bir kontroldr. Gelin rnekler ile tam olarak nasl altna gz atalm.

301

WrapPanel ierisinde birden ok nesne. Yukardaki grselde sahnede bir WrapPanel yer alyor. Sz konusu WrapPanel iinde toplam 6 tane Button var. Bu Button'larn konumlar ile ilgili hibir ayar yapmadk. Dmeleri WrapPanel ierisinde attka WrapPanel kendisi ilk bata dmeleri yan yana koymaya balad sonra yer kalmaynca alt satra att ve alt satra dmeler dizmeye balad. te WrapPanel'in mant da budur. erisinde bulunan nesneleri sras ile toparlayarak konumlandrr. [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="clrnamespace: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>

302

rneimizin XAML kodunu da yukarda bulabilirsiniz. Grdnz gibi WrapPanel ierisindeki dmelerin hibirinin konumlandrma bilgisi yok. Dmelerin ierisinde yazlacak yazlar dnda hibir zellikleri set edilmi deil.

WrapPanel'in Orientation zellii Vertical yaplnca... sterseniz bir WrapPanel'in ierisindeki nesnelerin ekrann stne doru deil de soluna doru da toparlanmalarn salayabilirsiniz. Bunun iin WrapPanel'in Orientation zelliini Vertical olarak ayarlamanz yeterli olacaktr. Bylece sralama ilemi dikey olarak yaplacak ve dikey boy doldurulduunda yeni bir kolon yaratlarak 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 ierisinde nesnelerin hizalama ayarlarna dikkat! WrapPanel ierisindeki nesnelerin her biri kendi satr ve stunlar ierisinde hizalandrlabilirler. Stretch modunda olan nesnelerin oluan bir kolon veya stun ierisinde tm nesnelerin en geni veya en yksek olan nesneye uyum salayacaktr. Bu nedenle eer bir satr veya stun ierisinde nesnelerin orijinal byklklerinde kalmalarn istiyorsanz hizalamalarn kesinlikle tek tek ayarlamalsnz.

303

Farkl hizalamalara sahip nesneler! Yukardaki grselde ikinci dmenin dikey hizalamalas deitirilerek kendi zgn boyutunda gsterilmesi salanmtr. Sz konusu dmenin bulunduu satrn yksekliini arttran isen birinci dmedir. [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 kullanlabilir? WrapPanel'in belki de en sk kullanld basit yerlerden biri harici kontrollerdeki dier Layout kontrollerinin yerini alarak farkl grsellikler salama noktasdr. rnein normal artlarda ierisindeki elerin dikey veya yatay olarak tek bir satr veya stunda gsterilebilecei bir ListBox kontrolnn Layout kontroln deitirerek ListBox ierisinde tm nesnelerin ekrana sacak ekilde bir WrapPanel ierisinde toplanmasn salayabilirsiniz.

Standart bir ListBox.

304

Yukarda grdnz standart ListBox ierisinde eler dikey olarak sralanm durumda. Oysa bu elerin uzunluklar ksa ve belki de "Deneme 1" ile "Deneme 2" yan yana konabilirdi. Bylece ok daha fazla e ayn anda ekranda gsterilirken kullancnn ok daha hzl ekilde arad eye ulamas salanabilirdi. Bu detaylarn haricinde grsel olarak da daha gzelbir sonu alabiliriz. Bu durumda bizim yapmamz gereken yukarda hazrladmz standart ListBox'n Layout kontroln deitirmek. Bunun iin Expression Blend ierisinde kontrol seerek sa tu tklayp aadaki grselde grebileceiniz menye doru hzl bir yolculuk yapyoruz.

ListBox'n Layout kontroln deitireceiz. ListBox'n ierisinde normal artlarda bir Grid Layout kontrol bulunuyor. Bu kontrol silerek yerine bir WrapPanel koymamz gerekecek.

305

Grid yerine WrapPanel karnzda. WrapPanel'i koyduktan sonra WrapPanel'in geniliini de ListBox'nzn geniliine eitlemeyi unutmayn. Bunu dinamik arayzlerde LayoutUpdated eventlarnda yapabilir veya XAML tarafnda bir Binding ile zebilirsiniz.

ListBox ierisinde WrapPanel. Yukardaki grselde WrapPanel ile ListBox'n i ortaklnn sonucunu grebilirsiniz. ListBox ierisinde nesneler mmkn olduka yan yana alnarak yukarya doru toplanmlar. Bizim rneimizde nesne says artk az geldii iin ListBox'n scroll barlar da gzkmyor. Hepinize kolay gelsin.
DaronYNDEM

306

Silverlight uygulamalar ve IIS MIME Type ayar. Silverlight uygulamalarnda kullandmz XAML dosyalarnn baz durumlarda IIS tarafndan istemciye gnderilmediinden daha nceki yazlarmda bahsetmitim. Bazen bu durum zellikle sunucu admini (hosting salayc) tarafndan ek cret talebi yapabilmek adna kastl olarak yaplabildii gibi bazen de gerekten ortada bir sorun olabiliyor. Peki nasl dzelteceiz? MIME Type tanm nasl yaplr? Silverlight XAML dosyalarnn IIS tarafndan istemciye sunulabilmesi iin aadaki ekilde gerekli MIME type'larn tanmlanmas gerecektir. Dosya uzants: .xaml MIME type: application/xaml+xml Dosya uzants: .xap MIME type: application/x-silverlight-app XAML' biliyorduk da XAP da nesi? :) XAP u an Silverlight 2.0 Beta 1 ile beraber kullanlan bir dosya uzants. Eer olur ya bir fantezi erevesinde Silverlight 2.0 Beta 1 ile sanal makinenizde gelitirdiiniz bir uygulamay sunucuya koymak isterseniz u an iin XAP dosyalar iin de gerekli MIME Type'lar tanmlamanz gerekecektir. leride Silverlight 2.0'n yayna kacak orijinal srmlerinde bu uzantnn kullanlmaya devam edecei tabi ki garanti deil. Bahsettiimiz teknoloji daha beta aamasnda. Gelelim bu tanmlama iini nasl yapacamza. Sunucuda IIS Manager' atktan sonra MIME Type ayar yapmak istediiniz siteyi seerek sa tu tklayarak gelen menden "Properties" komutunu veriyoruz. Karmza gelen pencereden "HTTP Header" sekmesine geerek en alttaki "MIME Types" dmesine tklyoruz.

307

IIS Manager ierisinde MIME Types seeneini bulduk. "MIME Types" blmne girdikten sonra hemen "New" dmesine tklayarak yeni bir "MIME Type" eklemek zere bir nceki paragraftaki ayarlar buraya aynen yazyoruz ve grdmz tm "OK" dmelerine basarak IIS Manager arayzne geri dnyoruz.

308

Yeni bir MIME Type ekliyoruz. Artk gerekli uzantlar tanmland iin herhangi bir sorun yaamayacaz. Hepinize kolay gelsin.
DaronYNDEM

309

Silverlight 2.0 Beta 2 ile gelen DataGrid yenilikleri Silverlight 2.0 Beta 1 ile beraber gelen DataGrid kontrolnn ana yaplarn daha nce incelemitik. Bu yazmzda da Silverlight 2.0 Beta 2 ile beraber gelen DataGrid yeniliklerine gz atacaz. Sralama lemleri Maalesef Silverlight 2.0 Beta 1 ile beraber gelen DataGrid ierisinde herhangi bir otomatik sralama yaps gelmiyordu. Oysa ou ASP.NET'teki GridView'den de alk olduumuz zere baz durumlarda kolonlarn en st balk ksmlarn tklanabilir hale getirerek kolon ierisindeki veriye gre satrlar sralatabiliyor olmak ok nemli bir ilevsellik. Artk Silverlight 2.0 Beta 2 ile beraber gelen DataGrid ierisinde bu zellii salayan hazr bir yap var. Peki neler yapmamz gerekiyor? Aslnda yapmanz gereken neredeyse hibir ey yok. IList snfndan tretilmi herhangi bir listeyi DataGrid'e baladnzda sralama (sorting) ilemleri otomatik olarak yaplabilecektir. Zaten baktmzda DataGrid'lerimizi bu yapy destekleyen List veya ObservableCollection listeleri balyoruz. Normal artlarda listeleme iin kullanlan veri tklanan kolona bal olan ve DisplayMemberBinding'de gzken veri kayna oluyor. Oysa baz durumlarda bu senaryo da dzgn almayacaktr. rnein normal kolonlar yerine bir TemplateColumn kullanyorsanz DisplayMember olmad iin sralama ilemi de yaplamayacaktr. Bu gibi durumlarda kolonun grsel ksmndan bamsz olarak SortMemberPath zelliini ayarlayarak kolonda ne gzkrse gzksn arka planda sralama ileminin farkl bir kolona veya veriye gre yaplmasn salayabilirsiniz. Grsel Deiiklikler zellikle listeleme ilemini yaptnz kolonlarn balklarnda oklar meydana gelecektir. Bu oklarn tasarmndan tutun, meydana gelme animasyonlarna kadar her eyi tek tek deitirebilirsiniz. Bunun iin MSDN'den aadaki adresi incelemeniz yeterli olacaktr. http://msdn.microsoft.com/tr-tr/library/cc278066(en-us,vs.95).aspx Bu adreste hali hazrda DataGrid ierisinde kullanlan tm kaynaklarn, stillerin ve animasyonlarn kodlar bulunuyor. Bunlar alp zelletirip rahatlkla uygulamanza ekleyebilirsiniz. rnein aada sadece kolonlarn balklarna ait ksmlarn zelletirildii bir XAML kodunu inceleyebilirsiniz. Satr aras yorumlarma zellikle dikkat etmenizde fayda var. <UserControl xmlns:my="clrnamespace: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>

310

<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" />

311

</Storyboard> <!-- Fare zerine gelince alan 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> <!-- Sralama bozulduunda gsterilen 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> <!-- Sralama anndaki 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> <!-- Sralama anndaki 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>

312

</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 iin kolon ad buraya yazlyor Bind edilmi --> <controls:ContentPresenter Margin="3,0,3,0" Content="{TemplateBinding Content}" VerticalAlignment="Center" /> <!-- Sralam oku grseli 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" />

313

</Path.RenderTransform> </Path> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <!-- Stilimizi gride baladk. --> <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 boyutlandrma Yeni bir Silverlight uygulamas yarattnzda sahnede yer alan LayoutRoot aslnda bir Grid nesnesidir. Silverlight 2.0 Beta 1'den farkl olarak Beta 2 ile beraber gelen DataGrid'in kendi ierisindeki veriye gre kendini otomatik boyutlandrma ans var. Varsaylan ayarlar ilebir DataGrid yarattnzda bu zellik ak geliyor. Tabi DataGrid'in istedii kadar byyebilmesi iin uygun kontroller ierisine yerletirilerek herhangi bir ekilde boyutlarnn snrlandrlmam olmas gerekiyor. Programatik olarak bir nesnenin ykseklik veya geniliini otomatik olarak ayarlamak istiyorsanz Double.NaN 'a eitlemeniz yeterli olacaktr. DataGrid'in geniliini otomatik olarak ayarlamann yan sra artk kolonlar da ilerindeki veriye gre otomatik olarak boyutlandrlabiliyorlar. Bu boyutlandrma iin ise 4 farkl teknik kullanlabiliyor. Birincisi "Auto" deerini vererek ilemi tamamen otomatie brakmak, ikincisi SizeToHeader diyerek kolonun kendi bal kadar genileyebilmesini salamak, ncs SizeToCells diyerek kolonun balndan bamsz olarak ieriindeki veri kadar genilemesini salamak ve drdncs de dorudan saysal bir deer vererek kolonun geniliini ayarlamak. Aada rnek bir kullanm grebilirsiniz. <my:DataGrid x:Name="Veri" ColumnHeaderStyle="{StaticResource KolonBasi}" AutoGenerateColumns="False" AlternatingRowBackground="#FFFFFF00" HorizontalGridlinesBrush="#FFD4FF00"

314

RowBackground="#FFE3E3E3"> <my:DataGrid.Columns> <my:DataGridTextColumn Width="SizeToHeader" Header="Adi" DisplayMemberBinding="{Binding Adi}" /> </my:DataGrid.Columns> </my:DataGrid> Ayn ilemi kod ile yaptnzda ise dorudan DataGridLength snf zerinden gerekli seeneklere ulaabiliyorsunuz. Saysal bir deer atayarak kolonun geniliini sabitlemek istediinizde ise maalesef sizi ufak bir sorun bekliyor. Kolon geniliini DataGridLength olarak atamanz lazm, integer veya double kesinlikle kabul edilmiyor. Bu durumda yardmmza DataGridLengthConverter adnda bir snf yetiiyor. [VB] kolon.Width = (New DataGridLengthConverter).ConvertFrom(50) [C#] kolon.Width = (DataGridLength)(new DataGridLengthConverter()).ConvertFrom(100); DataGridLengthConverter snfndaki ConvertFrom metodu ile elimizdeki herhangi bir deikenden DataGridLenght yaratarak kolonlarmzn geniliini kod tarafndan da dzenleyebiliyoruz. Hepinize kolay gelsin.
DaronYNDEM

315

Silverlight ve WPF'de Design Mode ve Init durumunda kodlar sorunsal. WPF veya Silverlight projelerinde Int durumu ile PageLoad veya WindowLoad event'lar arasndaki fark bazen ilk bakta yokmu gibi varsaylarak kodlarn dorudan Init ksmna yazldn ok grdm. Bazen bu durum sorun karmasa da aslnda tam olarak Init durumu bitmedii iin baz kaynaklara veya kontrollere ulamama hatta bu ulap / ulamama durumunun da belli olmamas :) gibi garip hatalar ile karlaabilirsiniz. O nedenle benim genel tavsiyem srekli Loaded event'larnn kullanlmas ve Init'in sadece ek event-listener tanmlamalarnn yaplaca bir konum olarak saklanmas. Bu erevede bir dier sorun ise Init durumuna yazdnz kodlarn aslnda hem Blend hem de Visual Studio tarafndan Design modundayken altrlyor olmas. Eer bu bilgiye sahip deilseniz maalesef ki Init durumunda yaptnz ar bir ilemin bir anda Visual Studio ve Blend'in arayzne de binmesi ve Page.XAML gibi bir dosyay atnz anda yksek ilemci kullanmlar ile karlamanz olas. En basit zm bu kodlar Init'den karmak ve Loaded'a yerletirmek olabilir fakat ya Init'i kesinlikle kullanmanz gerekiyorsa? [C#] if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this) == false) { } te yukardaki gibi bir kontrol ile sz konusu Init kodunun iinde uygulamann DesignMode'da olup olmadn kontrol edebilirsiniz. Bylece eer sayfa Visual Studio veya Blend ile Design modunda alm ise bu IF ierisinde kodlar altrlmayacak. Oysa program F5 ile compile edip altrdnzda ise herhangi bir sorun ile karlaamaycaksnz. Hepinize kolay gelsin.
DaronYNDEM

316

Silverligth 2.0'da uygulama fonunu effaf kullanmak zellikle dikdrtgen kelere sahip olmayan Silverlight uygulamalarnda sayfann fonunun Silverlight'n fonunda da gzkmesini isteyebilirsiniz. Aslnda basit bir ekilde Silverlight 2.0 Beta 2 uygulamasnn fonunu effaf yapabilsek sorunumuz zlm olacaktr. Bunun iin yapmamz gereken ufak bir ka ayar var. Eer bir ASP.NET sayfasnda Silverlight sunucu kontroln kullanyorsanz aadaki ekilde PluginBackground zelliini Transparent ve Windowless zelliini de True olarak ayarlamanz yeterli olacaktr. ASP.NET Silverlight sunucu kontrol gerekli HTML ierii sizin iin retecektir. <asp:Silverlight PluginBackground="Transparent" Windowless="true" ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication29.xap" MinimumVersion="2.0.30523" Width="100%" Height="100%" /> Eer Silverlight uygulamanz ASP.NET d bir sayfada kullanacaksanz bu sefer sz konusu parametreleri OBJECT taglar arasnda 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 tm bunlar yaparken Silverlight uygulamas ierisinde Root grselinizin fonunun da effaf brakldn kontrol etmekte fayda var. Hepinize kolay gelsin.
DaronYNDEM

317

SL 2.0'da ZIP ierisinden asenkron kaynak kullanm. Silverlight 1.0 ierisinde sunucu tarafndan ZIP dosyalar alarak bunlarn ierisindeki dosyalar istemci tarafnda kartarak kullanabiliyor olmak byk avantaj salyordu. zellikle byle bir ilevsellik salamak iin de neredeyse hibir ek kod yazmyor olmamz artc bir kolaylkt. Bu aknlmz almak adna Silverlight 2.0 Beta 1 ierisinde iler biraz daha zorlatrlm durumda. Gelin bir rnek ile ilerleyelim. Sayfamzda iki adet resim gstermek istiyoruz. Bu resimler bir ZIP dosyas ierisinde 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> Yukardaki rnek Silverlight 2.0 Beta 1 projemize ait Page.xaml dosyasnn kodunu inceleyebilirsiniz. Hedefimiz dmeye tklandnda sunucudaki fotolar.zip dosyasn istemciye indirerek ierisindeki iki farkl resmi ekrandaki iki bo Image tagnn ierisine yerletirmek. lk olark sunucudan asenkron bir istek ile veri alabilmek iin bir WebClient nesnesi yaratmamz 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 Yukardaki kodumuz Silverlight uygulamamzda dmeye basldnda alacak olan kodun ta kendisi. lk olarak Talep adnda bir WebClient nesnesi yaratyoruz. Sonrasnda bu WebClient'n OpenReadCompleted durumunda alacak olan VeriGeldi fonksiyonuna ait atamay tamamlyoruz. Bylece sunucudan istediimiz veri istemciye ulatnda birazdan yazacamz VeriGeldi fonksiyonu / event handler' alacak. Son satrda OpenReadAsync metodu ile sunucudan fotolar.zip dosyasn istiyoruz. Sz konusu istei gerekletirirken OpenReadAsync metoduna bir Uri vermemiz gerekiyor bunun iin Relative bir Uri yaratyoruz. Relative yaratmamzn nedeni fotolar.zip dosyasnn Silverlight uygulamasnn alt adres ile ayn konumda bulunacak olmas. Dim GelenVeri As System.IO.Stream = e.Result

318

Dim FotoStream As System.IO.Stream = Application.GetResourceStream(New System.Windows.Resources.StreamResourceInfo(GelenVeri, Nothing), New Uri("creek.jpg", UriKind.Relative)).Stream Artk yava yava VeriGeldi event-handlermzda alacak kodlar yazmaya balayalm. lk satrda sz konusu event-handlermza parametre olarak gelecek olan System.Net.OpenReadCompletedEventArgs tipinde e deikeni zerinden e.Result diyerek sunucudan gelen Stream'i alyoruz. Sonraki satrda iler biraz kark. Elimizdeki Stream'i, yani GelenVeri deikenini bir StreamResourceInfo'ya dntrmemiz gerekiyor. Bunu da Application.GetResourceStream metoduna birinci parametre olarak veriyoruz. Bylece GetResourceStream metodu artk nereden Resource kartacan biliyor. ZIP dosyamzn gelen stream'ini dntrerek GetResourceStream'e verdikten sonra tanmlamamz gereken ikinci parametre ise ZIP dosyas ierisinden hangi dosyay yani Resource'u almak istediimiz. Bunun iin de bir Relative Uri yaratarak GetResourceStream'a metoduna ikinci parametre olarak veriyoruz. Artk GetResourceStream gerekli veriyi kendisine verdiimiz ZIP Stream ierisinden alarak bize yine bir Stream olarak verecektir. FotoStream deikenimizi de bu ekilde yakaladktan sonra artk ilemlere 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 iin Foto adnda bir BitmapImage nesnesi yaratyoruz. Sz konusu nesnenin SetSource metodunu kullanarak dorudan elimizdeki FotoStream'i kendisine aktaryoruz. Artk elimizde bir Foto bulunduuna gre bunu XAML kodumuzdaki Resim1'in Source zelliine aktarabiliriz. Son olarak Resim1'e ait Measure metodunu da ararak grsel anlamda Resim1'in ekranda kaplayaca yer olarak kendisini toparlamasn salamamz gerekiyor. Aksi halde resim yklense de daha nce Resim1'in ii bo olduu ve boyutu ekranda ufak olduu iin gzkmeyecektir. Artk tek yapmamz gereken ayn ilemleri ikinci resim iin de yaparak GelenVeri'den ikinci dosyamz da almak ve Resim2 ierisine yerletirmek. 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

319

Peki bu ZIP dosyas ierisinde sadece resimler mi bulunabilir? Tabi ki hayr. Ayn ZIP dosyas ierisinde bir de deneme.txt adnda metin dosyas bulunduunu varsayalm ve sz konusu dosya ierisinden ufak bir metni alp dmemizin zerine yazdralm. 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 dosyasnda deneme.txt'yi alyoruz. Stream'imizi bir byte dizisine aktardktan sonra her bir byte' tek tek karaktere evirerek bir StringBuilder yardm ile srekli bir metne dntryoruz. Son olarak elimizdeki metni de dmemizin zerine yazdryoruz. Bylece harici bir ZIP dosyasn istemci tarafnda asenkron olarak indirmi ve sonrasnda da dosya ierisindeki iki farkl resmi farkl Image nesnelerine aktarm olduk. Bu kadarla kalmayp ayn ZIP dosyas ierisindeki bir TXT dosyasndan da metin alarak kullandk. Sonu olarak istemci tarafndan sunucuya sadece bir istek yolladk ve tek bir dosya aldk. Ayrca aldmz dosyann sktrlm olduunu da unutmamakta fayda var. Hepinize kolay gelsin.
DaronYNDEM

320

Vista Gradientlar XAML Kodlar zellikle "developer" tabanl olanlar iin hazrlanan bir uygulamann grsel arayzn sslemek hem bir "in ikencesi" oluyor hem de ortaya zaten gzel bir rn de kmyor. Bu gibi durumlarda eer projelerinizde bir tasarmc ile alma ansnz da yoksa en azndan internetteki hazr renk emalarndan faydalanabilir, birbiri ile uyumlu renkler reten web sitelerinden faydalanabilirsiniz. Veya daha da pratik bir yol var, bir yerlerde beendiiniz renkleri "dn" alabilirsiniz :) Peki nerden? Hemen nnzde Windows Vista duruyor, tasarm da hi fena saylmaz :) <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>

321

<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 gradientlarn Silverlight veya WPF ile kullanlabilecek XAML kodlar. Yukardaki rnek Silverlight 1.0 uygulamasnda drt farkl gradient gsterebilmek iin drt adet dikdrtgen kullandm.

Vista Gradientlar

322

SilverlightUserControl'mDesignmodundaBlendiindemi?Yoksagerekhayattam?

Bugn sizlerle ufak fakat bence bir o kadar da deerli bir ip ucu paylaacam. zerinde altmz projelerden birinde hi ho olmayan bir sorun ile karlatk. Aslnda sorunun nedeni Visual Studio ve Expression Blend ierisinde Silverlight projeleri dzenlenirken sz konusu projeler ierisindeki UserControl'lerin PageLoad ve Init kodlarnn tasarm aamasnda da altrlyor olmas. Ne demek istiyorum? rnein Detay adnda bir UserControl hazrladnz ve bunu da Ana adnda bir UserControl'n ierisine yerletirdiniz. Bu yerletirme ilemini de XAML ierisinde namespace tanmlayarak yaptnz ki tasarmc Blend ierisinde sz konusu UserControl' rahatlkla dzenleyebilsin. zetle UserControl'lerinizin XAML kodlar aadaki 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="clrnamespace: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> Grdnz zere dier UserControl' almak zere XAML NameSpace tanm yaplm ve ekrana da Detay adndaki UserControl yerletirilmi. [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>

323

Yukardaki ekli ile tanmladmz Detay adndaki UserControl ierisinde de sadece bir TextBlock bulunuyor. Detay'n kodunda bir ekilde Page.Load durumunda ekrandaki kontrollere veri balarsanz tm bu ilemlerin Expression Blend ierisinde Ana.XAML aldnda altrldn greceksiniz. Sonu itibari ile Ana.XAML ierisine Detay kontroln koyduumuz iin Blend Ana adndaki UserControl ierisinde gstermek zere Detay' altrp dorudan sahneye yerletiriyor. "Ne kadar gzel?" dediinizi duyar gibiyim :) Aslnda durum gerekten ho. Bu sistem sayesinde ana bir kontrole yerletirilmi UserControl'ler kendi Page.Load'lar da altrlarak gerek alr hallerindeki grntleri ile tasarmcya gsteriliyorlar. Fakat ya Page.Load'da alan kod uygulamann bir web sunucu zerinden host edilmi olmasn gerektiriyorsa? te tam da o noktada Blend atlyor :) doal olarak.... Peki ne yapmak gerek? zm basit. Bizim UserControl'lerin kendilerinin Blend'de mi yoksa gerekten alma zamannda da altrldklarn alglamalar ve ona uygun ilem yapmalar gerekiyor. rnein bizim detay adndaki UserControl Blend tarafndan aldnda kendi iindeki TextBlock'e "DENEME" yazarken, gerekten aldnda ise sunucudan veri ekmeli. [VB] If Not ComponentModel.DesignerProperties.GetIsInDesignMode(Me) Then MyServis.GetNewsFromBlogAsync() Else textBlock.Text = "Blend ierisinde blog ile balant kurulamaz." End If Yukarda grdnz kod ile herhangi bir UIElement'in Blend ierisinde Design modunda alp almadn renebiliyorsunuz. rnein bizim rneimizde normal artlarda web servisinden veri eken kod eer Blend ierisinde alm ise veri ekmek yerine uygun yere uygun mesaj yazyor. Farkl rneklerde tasarmcya yardmc olmak amac ile DataBind ettiiniz kontrolleri belki de tasarmc iin kod ierisinde veri yaratp databind edebilirsiniz. Oysa uygulama altnda gerek veri kaynana ynelebilir. GetIsInDesignMode metoduna parametre olarak herhangi bir UIElement verdiinizde size Design modunda olunup olunmadna dair Boolean bir deer dndryor. Hepinize kolay gelsin ;) Daron YNDEM www.Daron.Yondem.com Volkan ALBAYRAK www.volkanalbayrak.blogspot.com

You might also like