Ana Sayfa | English Blog | Fotoğraf Albümü | Dil Cookie Sil  RSS 2.0 Atom 1.0 CDF 
Daron Yöndem
bir yazılımcının tasarıları...
 Wednesday, May 14, 2008

Visual Studio 2008 ve .NET Framework'ün 3.5 sürümünün üzerinden uzun bir süre geçmeden SP1'in Beta 1'i de karşımıza çıktı. İlginç olan SP1'in aslında alıştığımız Service Pack yapısına benzemiyor olması. Var olan bazı hataları düzeltmekten öte yeni özellikler ekleme yolunda ilerleyen bu SP ile beraber gelen yenilikler arasında Visual Studio'nun WPF Designer View kısmında performans optimizasyonları, Visual Basic ve C++ için yeni kontroller, Office 2007 Ribbon kontrolü, JavaScript Intellisense altyapısında geliştirmeler, SQL 2008 desteği ve ADO.NET Entity Framework dikkati çekiyor.

Özellikle .NET Framework 3.5 SP1 Beta1 kısmına baktığımızda ise WPF uygulamalarında şu an kadar yazılmış uygulamaların kodlarında hiçbir değişiklik gerektirmeyecek şekilde tamamen altyapıda yapılan değişiklikler ile ortalama %20 ile 45 arası performans kazanımı elde edileceği belirtilen önemli noktalar arasında. Örneğin WPF tarafında kullandığımız gerçek zamanlı DropShadow gibi efektler şu anda yazılım destekli olarak yaratılırken SP1 sonrasında donanım destekli olarak yaratılacak.

.NET Framework 3.5 Client Profile

Bu gerçekten çok akıllıca :) Bahsettiğim şey aslında şu; bugün .NET Framework yüklemesi aslında bizim heryere yaptığımız bir yükleme. Yani IIS üzerinde ASP.NET çalıştırmak için de aynı .NET Framework'ü yüklüyoruz, istemcide çalıştırılacak .NET uygulaması için de istemciye aynı .NET Framework'ü kuruyoruz. Oysa ASP.NET'te kullanılan altyapı ile istemcideki exe'yi çalıştıracak altyapı tamamen birbiri ile aynı değil. Özetle, bazı yerlere gereksiz şeyler yüklüyoruz :) İşte tam da bu sorunu çözmek için .NET Framework3.5 Client Profile geliyor. Sadece istemci tarafına yüklenmek üzere özel olarak hazırlanacak olan bu Framework paketi ile artık istemciye yaklaşık 20MB'lık bir yükleme yaptırarak .NET uygulamalarını çalıştırabileceğiz.

Tüm bu yenilikler ve daha fazlası :) şimdilik Beta1 yüklemeleri ile karşınızda;

Visual Studio 2008 Service Pack 1 Beta
.NET Framework 3.5 Service Pack 1 Beta
Visual Studio 2008 Express Editions with Service Pack 1 Beta

Bü yüklemelerin Beta olduğunu ve üretim yapılan sistemlere yüklenmemesi gerektiğini özellikle belirtmek istiyorum. Ayrıca Silverlight 2.0 için kullandığınız sanal makinelere de yükleme yapmamanızda fayda var. SL 2.0 için yapılan Beta yüklemeler ile bir çakışma söz konusu, sistem çalışmaz hale geliyor. :)

Hepinize kolay gelsin...

Wednesday, May 14, 2008 9:12:09 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   .NET Framework 3.5 | Visual Studio 2008  | 
 Tuesday, May 13, 2008

Bugün Konya, Selçuk Üniversitesin'deydim. Sabah 10.00'da başlayarak 19.00'a kadar WPF, AJAX, Silverlight ve LINQ konularını inceleyen bir seminer ile güzel bir gün geçirdik. Umarım "yol yorgunluğum" aktiviteye çok yansımamıştır. Bir gün öncesinde bildiğiniz üzere Çanakkale 18 Mart Üniversitesin'deydim ve akşam 23.00'da Çanakkale'den mecburen otobüs ile İstanbul'a döndüm. O saatte uçak vs yok. Sabaha karşı 05.00'de İstanbul'daydım ve 07.00 uçağı ile Konya'ya uçtum :) Durum böyle olunca hem uykusuzluk (buna alışkınım aslında) hem de sadece uçakta verilen abuk sandwich nedeniyle açlık (işte buna dayanamam!) nedeniyle performansımdan şüphe etmediğimi söylesem yalan olur.

Konya, Selçuk Üniversitesi
Konya, Selçuk Üniversitesi

Aktivitede katkılarından dolayı sevgili MSP, Okan Öztürkmenoğlu'na çok teşekkür ediyorum. Bereketine hayran kaldığım etli ekmek desteği ile tüm günü ayakta geçirebilmeme büyük katkıları oldu :)

Tekrar görüşmek üzere ;)

Tuesday, May 13, 2008 6:16:49 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   AJAX | LINQ | Seminer | Silverlight | Silverlight 2.0 | WPF  | 
 Monday, May 12, 2008

Bugün Çanakkale 18 Mart Üniversitesi'ndeydim. WPF ve Silverlight konulu toplam 6 saatlik bir seminerin sonunda ilk defa bir üniversitenin öğrencilerinden bu kadar çok iltifat duydum :) Hepiniz çok sağ olun arkadaşlar. Benim için de çok zevkli bir gündü, böyle ilgili bir kitleyle birşeyler paylaşabiliyor olmak gerçekten muhteşem. Özellikle bir arkadaşın "Uzaktan küçük gözüküyorsunuz hocam" yorumunu sanırım hayatım boyunca unutmayacağım :)

Çanakkale 18 Mart Üniversitesi, WPF ve Silverlight Semineri
Çanakkale 18 Mart Üniversitesi, WPF ve Silverlight Semineri

Organizasyonla ilgili özellikle sevgili Erçin Yontar'a çok teşekkür ediyorum. Çanakkale zaten bana yabancı olmayan bir şehir :) yine de sevgili Erçin iskeleden alıp iskeleye kadar yolculadı beni :) Herşey için çok çok teşekkürler arkadaşlar, tekrar görüşmek dileği ile ;)

Monday, May 12, 2008 6:21:07 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Seminer | Silverlight | Silverlight 2.0 | WPF  | 
 Sunday, May 11, 2008

Silverlight 2.0 ile beraber istemci taraflı CLR altyapısı ile aslında hayal bile edemeyeceğimiz bir sürü işlemi bildiğimiz .NET dilleri ile yapabiliyoruz. Birazdan yapacağımız örneği Silverlght 2.0 öncesi herhangi bir teknoloji ile uygulamaya kaltığımızda bir .NET yazılım geliştiricisi için çok daha acı verici bir süreç söz konusu olabilirdi. Oysa doğrudan istemci tarafında .NET kullanımı ile çok daha rahat bir platform sağlanabiliyor.

Silverlight 2.0 Beta 1 içerisinde ister farklı User Control yapıları olsun veya ister farklı görsel stiller kullanın belirli noktalarda dinamik olarak Gradient yapıları kurmanız gerekebiliyor. İşte tam da bu noktada bir rengin geçiş yapabileceği başka uygun bir rengi programatik olarak bulmak ciddi sıkıntı verebilir. Aslında en basit çözüm Expression Design gibi programlarda yapabildiğimiz; bir rengin Hue / Saturation / Lightness değerlerini değiştirmektir. Böylece rengin ana yapısı değişmese de parlaklık ve ışık miktarı değiştirilerek farklı geçişler sağlanabilir ve bu farklı renklerden Gradient'lar dinamik olarak yaratılarak rahatlıkla kullanılabilir. Fakat maalesef Silverlight ile beraber gelen yapıya baktığımızda biz renklerin RGB (Red, Green, Blue) olarak geldiğini görüyoruz. Peki Hue, Lightness ve Saturation nasıl hesaplanıyor? Bu konuda live.com'da ufak bir araştırma HSL ile RGB arasında çeviri işlemlerinin nasıl yapılacağını öğrenmemiz için yeterli. Maalesef internette bu işi hazır yapan bir kod bulamadım. Ben matematik hesaplamaların ve sisteminin mantığının detayına girmeden sizinle yazmış olduğum kodu paylaşacağım.

Namespace HSLveRGB

    Public Structure HslRenk

        Public Alpha As Double

        Public Hue As Double

        Public Saturation As Double

        Public Lightness As Double

 

        Private Function Normal(ByVal gelen As Double) As Double

            If gelen  < 0 Then

                gelen  += 1

            End If

            If gelen  > 1 Then

                gelen  -= 1

            End If

            Return gelen

        End Function

 

        Private Shared Function B2P(ByVal gelen As Byte) As Double

            Dim giden As Double = gelen

            giden  = giden  / 255

            Return giden

        End Function

 

        Private Shared Function P2B(ByVal gelen As Double) As Byte

            gelen *= 255

            gelen += 0.5

            If gelen > 255 Then

                gelen = 255

            End If

            If gelen < 0 Then

                gelen = 0

            End If

            Return CByte(gelen)

        End Function

 

        Public Shared Function FromColor(ByVal BirRenk As Color) As HslRenk

            Return HslRenk.FromArgb(BirRenk.A, BirRenk.R, BirRenk.G, BirRenk.B)

        End Function

 

        Public Function RengiAc(ByVal x As Double) As HslRenk

            Dim BirRenk As New HslRenk()

            BirRenk.Alpha = Me.Alpha

            BirRenk.Hue = Me.Hue

            BirRenk.Saturation = Me.Saturation

            BirRenk.Lightness = Math.Min(Math.Max(Me.Lightness + x, 0), 1)

            Return BirRenk

        End Function

 

        Public Shared Function FromArgb(ByVal Alpha As Byte, ByVal Kirmizi As Byte, ByVal Yesil As Byte, ByVal Mavi As Byte) As HslRenk

            Dim BirRenk As HslRenk = FromRgb(Kirmizi, Yesil, Mavi)

            BirRenk.Alpha = B2P(Alpha)

            Return BirRenk

        End Function

 

        Public Shared Function FromRgb(ByVal Kirmizi As Byte, ByVal Yesil As Byte, ByVal Mavi As Byte) As HslRenk

            Dim BirRenk As New HslRenk()

            BirRenk.Alpha = 1

            Dim red As Double = B2P(Kirmizi)

            Dim green As Double = B2P(Yesil)

            Dim blue As Double = B2P(Mavi)

            Dim max As Double = Math.Max(blue, Math.Max(red , green))

            Dim min As Double = Math.Min(blue, Math.Min(red , green))

            If max = min Then

                BirRenk.Hue = 0

            ElseIf max = red AndAlso green >= blue Then

                BirRenk.Hue = 60 * ((green - blue) / (max - min))

            ElseIf max = red AndAlso green < blue Then

                BirRenk.Hue = 60 * ((green - blue) / (max - min)) + 360

            ElseIf max = green Then

                BirRenk.Hue = 60 * ((blue - red) / (max - min)) + 120

            ElseIf max = blue Then

                BirRenk.Hue = 60 * ((red - green) / (max - min)) + 240

            End If

 

            BirRenk.Lightness = 0.5 * (max + min)

            If max = min Then

                BirRenk.Saturation = 0

            ElseIf BirRenk.Lightness <= 0.5 Then

                BirRenk.Saturation = (max - min) / (2 * BirRenk.Lightness)

            ElseIf BirRenk.Lightness > 0.5 Then

                BirRenk.Saturation = (max - min) / (2 - 2 * BirRenk.Lightness)

            End If

            Return BirRenk

        End Function

 

        Public Function RengiKoyulastir(ByVal x As Double) As HslRenk

            Return RengiAc(-x)

        End Function

 

        Private Function Hesap(ByVal Bir  As Double, ByVal Iki As Double, ByVal Uc As Double) As Double

            If Bir < (1 / 6) Then

                Return Iki  + ((Uc  - Iki ) * 6 * Bir )

            End If

            If Bir < 0.5 Then

                Return Uc

            End If

            If Bir < (2 / 3) Then

                Return Iki  + ((Uc  - Iki ) * 6 * ((2 / 3) - Bir ))

            End If

            Return Iki

        End Function

 

        Public Function ToColor() As Color

            Dim Bir As Double = 0

            If Lightness < 0.5 Then

                Bir  = Lightness * (1 + Saturation)

            Else

                Bir  = Lightness + Saturation - (Lightness * Saturation)

            End If

            Dim Iki As Double = (2 * Lightness) - Bir

            Dim Key As Double = Hue / 360

            Dim red As Double = Hesap(Normal(Key + (1 / 3)), Iki , Bir )

            Dim green As Double = Hesap(Normal(Key), Iki , Bir)

            Dim blue As Double = Hesap(Normal(Key - (1 / 3)), Iki , Bir )

            Return Color.FromArgb(P2B(Alpha), P2B(red ), P2B(green), P2B(blue))

        End Function

    End Structure

End Namespace

Yukarıdaki kodu isterseniz harici bir DLL olarak derleyerek tüm projelerinizde kullanabilirsiniz. Silverlight içerisindeki kullanımına da ufak bir örnek ile göz atalım. Aşağıdaki şekilde Silverlight 2.0 uygulamamıza bir dikdörtgen ve Slider yerleştirerek Slider ile dikdörtgen içerisindeki rengi değiştireceğiz.

<UserControl x:Class="HSL2RGB.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

    Width="400" Height="300">

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

      <Rectangle HorizontalAlignment="Stretch" Margin="43,23,47,124" VerticalAlignment="Stretch" Fill="#FFD05D5D" Stroke="#FF000000" x:Name="Kutu"/>

      <Slider Height="24" Margin="43,0,47,82" VerticalAlignment="Bottom" x:Name="Slider" Maximum="1" LargeChange="0.1" SmallChange="0.01"/>

    </Grid>

</UserControl>

Özellikle Slider'ın alabildiği maksimum değere dikkat etmekte fayda var. Bu değer üzerinden bizim daha önceki HSL nesnesini kullanarak RengiAc ve RengiKoyulastir metodlarını çalıştıracağız. Geçelim uygulamanın kod kısmına.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Dim AnaRenk As Color = System.Windows.Media.Color.FromArgb(100, 255, 50, 50)

 

    Private Sub Slider_ValueChanged(ByVal sender As Object, ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of Double)) Handles Slider.ValueChanged

        CType(Kutu.Fill, SolidColorBrush).Color = HSLveRGB.HslRenk.FromColor(AnaRenk).RengiAc(e.NewValue - 0.5).ToColor

    End Sub

End Class

Yukarıdaki kod içerisinde ilk olarak dikkat edilmesi gereken nokta bizim global AnaRenk değişkenimiz. Bu değişken içerisinde sürekli bizim ana rengimiz duruyor ve bu renk üzerinden gerekli işlemleri yaparak yarattığımız yeni rengi Kutu nesnesinin Fill özelliğine atanmış SolidColorBrush'ın Color özelliğine aktarıyoruz. RengiAc metodunu kullanırken de Slider'ın mevcut değerine göre -0.5 ile 0.5 arasında bir değer gelmesini sağlıyoruz. Zaten aynı metod kendisine eksi değer verildiğinde rengi açmak yerine kapatıyordu.

Böylece rahatlıkla renklerin Hue / Saturation ve Lightness özellikleri Silverlight tarafında dinamik olarak değiştirilebiliyor. Bu özellikleri kullanarak sadece tek bir renk üzerinden giderek başka renkler de yaratıp güzel Gradient yapıları kurabilirsiniz.

Hepinize kolay gelsin.

Sunday, May 11, 2008 1:57:27 AM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Saturday, May 10, 2008

Silverlight 2.0 ile beni en çok şaşırtan özelliklerden biri de WPF'in web sürümü diyebileceğimiz ve WPF'e kıyasla bir çok eksiği olan bir torun olarak Silverlight ile beraber artık WPF'de bulunmayan bazı kontrollerin geliyor olması. Tahminen uzun vadede her iki taraf da birbirinden besleniyor olacaktır. Bugün baktığımızda ilk dikkati çeken kontrollerden biri de maalesef WPF tarafında olmayan Calendar ve DateTimePicker kontrolleri. Bu yazımızda bu iki kontrolü ve bu kontrollerle neler yapabileceğimizi inceleyeceğiz.

Calendar kontrolü şekilden şekilde girebiliyor.
Calendar kontrolü şekilden şekilde girebiliyor.

Yukarıdaki şekli ile birer Calender kontrolü yaratmak için tek yapmanız gereken XAML kodunuzu aşağıdaki şekilde düzenlemek.

<UserControl x:Class="Calendar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

    Width="400" Height="300">

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

    <Calendar Margin="21,20,145,57"/>

  </Grid>

</UserControl>

Tek yaptığımız bir Calendar tagı açarak kenarlardan olan uzaklığını belirtmek. "Çocuk oyuncağı" denen bu olsa gerek. Peki daha neler yapabiliriz? Aslında bu aşamadan sonra bahsedeceğimiz tüm özellikler Calendar ve DatePicker kontrolleri için birebir aynı. O nedenle gelin öncesinde bir de DatePicker kontrolünün XAML koduna bakalım.

<DatePicker Height="20" Margin="42,0,156,23" VerticalAlignment="Bottom"/>

DatePicker kontrolünü de sahneye yerleştirmek en az Calendar kontrolü kadar basit. Bu durumda hızlıca programatik işlevselliklere göz atabiliriz. Aşağıdaki gibi bir Silverlight uygulaması hazırlayarak kodlamaya başlayalım.

<UserControl x:Class="Calendar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

    Width="400" Height="300">

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

    <Calendar Margin="21,20,145,57" x:Name="Takvim"/>

    <DatePicker Height="20" Margin="42,0,156,23" VerticalAlignment="Bottom" x:Name="TarihSecici"/>

  </Grid>

</UserControl>

Uygulamamızda Takvim adında bir Calendar kontrolü ve TarihSecici adında bir DateTimePicker bulunuyor. Bu kontroller Silverlight uygulaması ile beraber ilk gösterildiklerinde içlerinde herhangi bir tarih seçili gelmiyor. Oysa aşağıdaki şekilde güncel tarihi seçili hale getirebilirsiniz.

        Takvim.SelectedDate = Date.Now

        TarihSecici.SelectedDate = Date.Now

Makalemizin en üstündeki görsele baktığınızda Calendar kontrolünün iki farklı görsel durumunun bulunduğunu görebilirsiniz. Normal şartlarda Calendar kontrolü günleri gösterecek şekilde açılıyor, sonrasında eğer üstteki ay ismine tıklarsanız ayların seçilebileceği arayüz geliyor. Oysa isterseniz Calendar kontrolü sayfada ilk açıldığında da ayların seçilebileceği arayüzün otomatik gelmesini sağlayabilirsiniz.

        Takvim.DisplayMode = CalendarMode.Year

Eğer Calender nesnesinin DisplayMode özelliği Month olursa tam bir ayı gösteriyor, Year şeklinde düzenlendiğinde ise tüm yılı yani ayları gösteriyor. Bunun haricinde isterseniz her iki kontrolün de hangi tarih aralıklarını gösterebileceğini ek olarak düzenleyebilirsiniz.

        TarihSecici.SelectableDateStart = Date.Today.Subtract(New TimeSpan(5, 0, 0, 0))

        TarihSecici.SelectableDateEnd = Date.Today.AddDays(5)

Yukarıdaki kod içerisinde DatePicker kontrolümüzün SelectableDateStart ve SelectableDateEnd özelliklerine DatePicker içerisinde seçilebilecek başlangıç ve bitiş tarihlerini aktarıyoruz. Bunu yaparken söz konusu tarihlerin hesaplamalarını da tabi ki dinamik olarak yapabilirsiniz. Böylece bu örneğimizde kontrol sürekli olarak mevcut tarihden 5 gün öncesinin ve 5 gün sonrasının seçilebilmesine olanak tanıyacaktır.

        TarihSecici.DisplayDateStart = Date.Today.Subtract(New TimeSpan(5, 0, 0, 0))

        TarihSecici.DisplayDateEnd = Date.Today.AddDays(5)

Seçili tarihleri belirlemenin yanı sıra isterseniz belirli tarihleri seçilemez yapmanın yanı sıra tamamen o tarihlerin gösterilmemesini de sağlayabilirsiniz. Bunun için DisplayDateStart ve DisplayDateEnd özelliklerinden faydalanabilirsiniz.

SelectableDateve DisplayDate arasında fark.
SelectableDateve DisplayDate arasında fark.

Hepinize kolay gelsin.

Saturday, May 10, 2008 1:46:36 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Friday, May 09, 2008

Socket programlama Silverlight çıktığından beri biz yazılım geliştiricilerin en büyük hayali ve bu hayal gerçek oluyor. Silverlight 2.0 Beta 1 ile beraber Socket Programlama karşımızda. Yani artık istemci ile sunucu arasında TCP/IP ile haberleşmek mümkün. Tabi belirli kurallar var; bu kurallardan ilki sunucudaki uygulamanın istemci uygulamanın yüklendiği web sitesi ile aynı konumda olması. Yani sunucu uygulamanızın web siteniz ahmet.com ise ahmet.com'un reverse DNS Look-Up ile bakıldığında çıkan IP adresine sahip sunucuda bulunması gerekiyor. Bu durumun Silverlight'ın Beta 1 sonrası sürümlerinde policyfile gibi sistemlerde daha esnek hale getirileceği söylentiler arasında fakat baktığımızda şu anki hali ile bile süper bir potansiyel söz konusu.

Peki nedir bunun avantajı?

Diyorum ya, hayalimizdi diye, peken neden? Web sitelerinde güncel bilgi göstermek her zamanki en büyük derttir. Bunu yapabilmek için çok eskilere döndüğümüzde bazı meta tagları ile belirli aralıkla sayfanın refresh atmasını sağladığımız günler bile olurdu. IFRAME vs nin gelmesi ile en azından bunu sayfada kısmi bölümlerde uygulayabilir hale geldik. Sonrasında AJAX geldi ve çok daha sinsi bir şekilde kullanıcı farkında olmadan belirli aralıklarla sunucudan yeni veri talebinde bulunarak sayfa değişmeden yeni içeriği gösterebildik. Oysa hep bizi rahatsız eden bir nokta vardı, o da şu; sürekli istemciden sunucuya bağlanarak bir veri değişikliğinin olup olmadığını kontrol etmek durumunda kalıyorduk. Sunucuya "Yeni birşey var mı?" diye dakikada bir soruyor ve çoğunda da hüsran ile geri dönüyordu. Keşke sunucu bize bir "Alo" diyebilse ve değişiklik olduğunda istemciyi haberdar edebilse? Teknik olarak bu güvenlik sebepleri nedeniyle zaten mümkün değil çünkü bir istemci bilgisayara dışarıdan içeriye bağlantı kuramazsınız (kuramamanız gerekir). Peki nasıl oluyor da Socket Programming bunu aşıyor? Aslında aşmıyor, yine istemci sunucuya bağlanıyor fakat söz konusu bağlantı TCP bazında olduğu herhangi bir trafiğe neden olmadan sürekli açık tutulabiliyor. Durum böyle olunca sunucu kendisine bağlı istemciye istediğinde söz konusu bağlantı üzerinden rahatlıkla ulaşabiliyor.

Sunucu tarafından işe başlayalım.

İlk olarak sunucudaki programımızı hazırlayalım. Söz konusu program kendisine gelen tüm istekleri karşılayarak gerektiğinde istemcilere veri gönderecek. Bizim programımız içerisinde bir TextBox bulunacak ve kutu içerisine metin yazıldıkça kendisine bağlı tüm istemcilere bu metin sürekli gönderilecek.

    Dim Baglilar As New System.Collections.Generic.List(Of System.IO.StreamWriter)

    Dim yeniTR As System.Threading.Thread

    Dim TCPBaglantilari As New System.Threading.ManualResetEvent(True)

    Dim Dinleyici As New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 4530)

İlk olarak global değişkenlerimizi tanımlıyoruz. Bunlardan ilki olan Baglilar değişkeni sunucuya bağlı olan istemcilere veri gönderecek olan StreamWriter nesnelerini bir listesini taşıyacak. Böylece istediğimizde bu liste içerisinde gezerek tüm bağlı olan istemcilere veri gönderebileceğiz. yeniTR adındaki değişkenimizi yeni bir Threat yaratmak ve her yerden kendisine ulaşabilmek için kullanacağız. TCPBaglantilari değişkenimiz var olan Threat'ın blocklanması ve tüm event-larının sıfırlanması için kullanılacak. Dinleyici adındaki değişkenimizi ise tüm istemcileri dinleyecek olan ve gelen bağlantıları algılayacak olan TCPListener nesnemizin ta kendisi. Gördüğünüz gibi bu nesneyi tanımlarken iki parametre aktarmışız. Bunlardan ilki herhangi bir IP adresi üzerinden bu uygulamaya bağlanılabileceği anlamına gelirken diğer ise sadece 4530 portu üzerinden bağlantı yapılabileceği anlamına geliyor. Silverlight 2.0 Beta 1 şu anda 4502-4532 aralığındaki portları kullanabiliyor.

    Private Sub btn_Basla_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Basla.Click

        yeniTR = New System.Threading.Thread(AddressOf Bekle)

        yeniTR.Start()

    End Sub

Uygulamamızdaki düğmeye basıldığında dinleme işlemini başlatmak üzere yeni bir Thread yaratıyoruz. Söz konusu Thread Bekle Sub'ına bağlı. Yarattığımız thread'i hemen başlatıp yolumuza devam edelim.

    Sub Bekle()

        Dinleyici.Start()

        While True

            TCPBaglantilari.Reset()

            Dinleyici.BeginAcceptTcpClient(New System.AsyncCallback(AddressOf BaglantiGeliyor), Nothing)

            TCPBaglantilari.WaitOne()

        End While

    End Sub

Yeni Thread içerisinde hemen Dinleyici nesnemizi başlatıyoruz ve kısır bir döngüye giriyoruz. Sürekli olarak elimizdeki Threadi sıfırlayarak Dinleyici'nin BeginAcceptTcpClient metodu ile istemciden bir bağlantı geleceğini belirterek WaitOne metodu ile de bekliyoruz. Eğer burada bir bağlantı gelir ve başarılı veya başarısız şekilde sonuçlanırsa bu döngü başa gelerek tekrar yeni bir bağlantı bekleyecek. BeginAcceptTcpClient içerisinde parametre olarak verdiğimiz BaglantiGeliyor event-handları herhangi bir bağlantı geldiğinde çalıştırılacak.

    Private Sub BaglantiGeliyor(ByVal ar As System.IAsyncResult)

        TCPBaglantilari.Set()

        Dim Musteri As System.Net.Sockets.TcpClient = Dinleyici.EndAcceptTcpClient(ar)

        If Musteri.Connected Then

            Dim yazici As New System.IO.StreamWriter(Musteri.GetStream)

            yazici.AutoFlush = True

            Baglilar.Add(yazici)

            yazici.Write("Bağlandınız.")

        End If

    End Sub

Baglanti geldiği anda bekleyen Threat'leri devam ettirmek adına TCPBaglantilari.Set() metodunu çağırıyoruz. Unutmayalım ki programımız aynı anda sadece tek istemcinin bağlantısını authenticate edebilir, yani diğerleri bir önceki istemci bağlanıp bağlantısını oluşturana kadar bekleyecektir. Bu noktada artık istemci bağlantı kurma işlemini tamamladığı için diğerlerine yol veriyoruz. Musteri adında bir TCPClient yarattıktan sonra Dinleyici'nin EndAcceptTcpClient metodu ile args parametresi üzerinden gelen Request'i alıyoruz. Eğer Musteri bağlı ise, yani Connected ise artık sıra geldi ona veri göndermeye. Musteri'nin yani TCPClient'ın Stream'ini alarak bundan bir StreamWriter oluşturuyoruz. Bu Stream üzerinden artık istemciye istediğimiz veriyi gönderebiliriz.

Unutmayın ki uygulamamızda bir TextBox vardı ve içerisine birşey yazıldığında tüm bağlı kullanıcılara gönderecektik. Bunun için sonra kullanabilmek adına elimizdeki canlı Stream'leri saklamak sorundayız. Global olarak tanımladığımız Baglilar adında Generic.List'e elimizdeki Stream'i aktarıyoruz. Bu arada kullanıcıya "Bağlandınız" diye de bir metin gönderiyoruz.

    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

        For Each x As System.IO.StreamWriter In Baglilar

            x.Write(TextBox1.Text)

        Next

    End Sub

Artık TextBox içerisinde değişiklik olunca bunu istemcilere göndermek çok kolay. Basit bir şekilde Generic.List içerisinde gezin ve her Stream'e elinizdeki veriyi gönderin.

İstemci tarafında neler olacak?

Silverlight tarafında çok basit görsellikte bir uygulamamız olacak. Sadece bir TextBlock! Uygulama tarayıcı içerisinde ilk açıldığında sunucuya bağlanacak ve gelen veriyi sürekli olarak söz konusu TextBlock içerisinde gösterecek.

<UserControl x:Class="SocketsClient.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

    Width="400" Height="300">

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

    <TextBlock Margin="42,46,37,125" Text="TextBlock" TextWrapping="Wrap" x:Name="Metin"/>

  </Grid>

</UserControl>

XAML kodumuzu yukarıdaki şekilde düzenledikten sonra hemen code-behind dosyasına geçerek bağlantı kodlarımızı yazmaya başlayalım.

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

        Dim Hat As New System.Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)

        Dim Args As New System.Net.Sockets.SocketAsyncEventArgs

 

        Args.UserToken = Hat

        Args.RemoteEndPoint = New System.Net.DnsEndPoint("localhost", 4530)

        AddHandler Args.Completed, AddressOf Baglandi

        Hat.ConnectAsync(Args)

    End Sub

Silverlight uygulaması ilk yüklendiğinde hemen bir Socket bağlantısı yaratmak için System.Net.Sockets.Socket üzerinden ilerliyoruz. Hat adındaki değişkenimizi yaratırken verdiğimiz parametrelerden ilki olan InterNetwork bizim bağlantı için IPv4 kullanacağımızı ve ikinci parametre de TCP kullanacağımızı belirtiyor. Asenkron bir çalışma yapısı için bir de SocketAsyncEventArgs nesnesi yaratarak söz konusu nesneyi Hat adındaki Socket'imize bağlıyoruz. Args'ın RemoteEndPoint özelliği istemcinin bağlanacağı sunucunun adresini ve port bilgisini içeriyor. Bağlanti oluşturulduğunda elimizdeki SocketAsyncEventArgs nesnesi olan Args'ın Completed event-handları çalışacağı için ona da dinamik bir event-handler olarak Baglandi metodunu atıyoruz. Son olarak ConnectAsync diyerek Socket değişkenimizin eldeki SocketAsyncEventArgs ile sunucuya bağlanmasını sağlıyoruz.

    Private Sub Baglandi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen(1024) As Byte

        e.SetBuffer(Gelen, 0, Gelen.Length)

        RemoveHandler e.Completed, AddressOf Baglandi

        AddHandler e.Completed, AddressOf Geldi

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

Artık istemci sunucuya bağlandığında göre sıra geldi karşı taraftan yeri geldiğinde veriyi almaya. Hatta ilk bağlantı esnasında hatırlarsanız bizim sunucumuzun "Bağlandınız" diye bir metin gönderiyordu. Gelen veriyi alabilmek için ve sürekli gelen veriyi dinlemek için eldeki Socket'i alarak sürekli dinleme durumunda olmamız şart. Kodumuzdaki event-handler içerisinde e parametresi aslında bizim bir önceki adımda tanımladığımız Args adaınki SocketAsyncEventArgs'ın ta kendisi. SetBuffer ile veriyi önbelleklemek için kullanacağımız ayarları da bir Byte değişkeni üzerinden aktardıktan sonra ilginç bir şekilde elimizdeki event-handlerları değiştiyoruz. Bundan sonra Args'ın Compeleted durumu yeni bir bağlantı oluştuğunu değil yeni veri geldiğini bildireceği için farklı bir event-handlerı bağlamamız gerekiyor. Baglandi adındaki metodumuzla Args'ın ilişkisi keserek Geldi adında farklı bir metoda bağlıyoruz. Son olarak Page.Load'a atadığımız ve e.UserToken üzerinden alabileceğimiz ana Socket değişkenimizi de yakalayarak ReceiveAsync metodu ile veri alımını başlatıyoruz.

Geldi ve Baglandi metodları aslında Silverlight içerisinde ayrı bir Thread içerisinde çalışıyor. Bu nedenle tüm bu işlemler yapılırken kullanıcının uygulama ile olan interaktivitesi kesinlikle kesilmiyor. Tabi ayrı bir Thread gibi davranıyor olmasını dezavantajı ise birazdan karşımıza çıkacak. Kısır döngü içerisinde süreki ReceiveAsync ile sunucuyu dinlerken istemci tarafında görsel arayüzde değişiklik yapamayacağız. Bu da bizim sunucudan veri alabilmemizi fakat ekranda göstermememize neden olacak. Tabi demokrasilerde çare tükenmez...

    Delegate Sub MyDelegate(ByVal myArg2 As String)

 

    Sub GelGel(ByVal x As String)

        Metin.Text = x

    End Sub

İlk olarak bir Delegate tanımlayacağız, söz konusu delegemiz sadece bir parametre alacak. Ayrıca bir de Sub yaratıyoruz. Aynı şekilde Sub'da bir metin parametresi alıyor ve bizim uygulamamızda adı Metin olan TextBlock içerisine yerleştiriyoruz. İşte bu yapı ile biraz önce bahsettiğimiz sorundan kurtuluyor olacağız.

    Private Sub Geldi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen As String = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred)

        Me.Dispatcher.BeginInvoke(New MyDelegate(AddressOf GelGel), New String() {Gelen})

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

Aslında sunucudan gelen veriyi almak çok kolay. Kodumuz içerisindeki ilk satır bu işi hallediyoruz. Esas mesele veriyi aldıktan sonra sahnede göstermek. Dispatcher nesnesi belki de Silverlight içerisinde en ilginç yapılardan biri; Dispatcher ile mevcut Thread'i yakalayarak BeginInvoke ile başka bir metod çalıştırıyoruz. Çalıştıracağımız metodu sunucudan gelen veriyi parametre olarak vereceğiz ve söz konusu metod (GelGel) bu veriyi alarak sahnedeki Metin adındaki TextBlock içerisine yerleştirecek. BeginInvoke ile ilgili işimizi de tamamladıktan sonra artık tekrar sunucunun dinlenmeye başlanması için elimizdeki Socket'i yakalayarak ReciveAsync metodunu çalıştırıyoruz. Bu sistem böyle sonsuza tek dönecek ve sunucudan gelen veri sürekli olarak tüm istemcilerde anında gösterilecek.

Son olarak hem istemci hem de sunucu uygulamanın tam kodunu sizlerle paylaşmak istiyorum.

[İstemci: Silverlight uygulaması]

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

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

        Dim Hat As New System.Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Stream, Net.Sockets.ProtocolType.Tcp)

        Dim Args As New System.Net.Sockets.SocketAsyncEventArgs

 

        Args.UserToken = Hat

        Args.RemoteEndPoint = New System.Net.DnsEndPoint("localhost", 4530)

        AddHandler Args.Completed, AddressOf Baglandi

        Hat.ConnectAsync(Args)

    End Sub

 

    Private Sub Baglandi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen(1024) As Byte

        e.SetBuffer(Gelen, 0, Gelen.Length)

        RemoveHandler e.Completed, AddressOf Baglandi

        AddHandler e.Completed, AddressOf Geldi

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

 

    Private Sub Geldi(ByVal sender As Object, ByVal e As System.Net.Sockets.SocketAsyncEventArgs)

        Dim Gelen As String = System.Text.Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred)

        Me.Dispatcher.BeginInvoke(New MyDelegate(AddressOf GelGel), New String() {Gelen})

        Dim Baglanti As System.Net.Sockets.Socket = CType(e.UserToken, System.Net.Sockets.Socket)

        Baglanti.ReceiveAsync(e)

    End Sub

 

    Delegate Sub MyDelegate(ByVal myArg2 As String)

 

    Sub GelGel(ByVal x As String)

        Metin.Text = x

    End Sub

 

End Class

[Sunucu: Winforms Uygulaması]

Public Class Form1

 

    Dim Baglilar As New System.Collections.Generic.List(Of System.IO.StreamWriter)

    Dim yeniTR As System.Threading.Thread

    Dim TCPBaglantilari As New System.Threading.ManualResetEvent(True)

    Dim Dinleyici As New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 4530)

 

    Private Sub btn_Basla_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Basla.Click

        'İzin Verilen Port Aralığı 4502-4532

        yeniTR = New System.Threading.Thread(AddressOf Bekle)

        yeniTR.Start()

    End Sub

 

    Sub Bekle()

        Dinleyici.Start()

        While True

            TCPBaglantilari.Reset()

            Dinleyici.BeginAcceptTcpClient(New System.AsyncCallback(AddressOf BaglantiGeliyor), Nothing)

            TCPBaglantilari.WaitOne()

        End While

    End Sub

 

    Private Sub BaglantiGeliyor(ByVal ar As System.IAsyncResult)

        TCPBaglantilari.Set()

        Dim Musteri As System.Net.Sockets.TcpClient = Dinleyici.EndAcceptTcpClient(ar)

        If Musteri.Connected Then

            Dim yazici As New System.IO.StreamWriter(Musteri.GetStream)

            yazici.AutoFlush = True

            Baglilar.Add(yazici)

            yazici.Write("Bağlandınız.")

        End If

 

    End Sub

 

    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

        For Each x As System.IO.StreamWriter In Baglilar

            x.Write(TextBox1.Text)

        Next

    End Sub

End Class

Hepinize kolay gelsin.

Friday, May 09, 2008 12:47:14 PM (GTB Standard Time, UTC+02:00)  #    Comments [0]   Silverlight 2.0  | 
 Thursday, May 08, 2008

Herhangi bir içeriği Silverlight 2.0 arayüzlerinde göstermek istediğinizde özellikle veri bağlanabilir çoğu kontrolün kendi içerisinde "ScrollBar" (Kaydırma Çubukları) içerdiğini görebilirsiniz. Fakat bazı durumlarda bu hazır kontrolleri kullanmadığınızda veya scrollbar özelliği bulunmayan bazı yapı taşı niteliğinde kontrolleri beraber kullanmak istediğiniz ayrıca bir ScrollBar'a ihtiyacınız olabilir. Bu gibi durumlarda bize scrollbar özellikleri ekleme konusunda ScrollViewer kontrolü yardımcı oluyor.

Yapacağımız ilk örnekte 1024*768 piksel büyüklüğünde bir resmi uygulamamıza ekleyeceğiz. Fakat biz bu resim nesnesini tam ekran göstermek istemiyoruz. Uygulamamız içerisinde ufak bir karede göstererek insanların istiyorlarsa ScrollBar'lar aracılığı ile resmi gezmesini istiyoruz. Bu durumda aslında yapmamız gereken çok basit. Aşağıdaki XAML kodunu yaratacak şekilde Image nesnemizi bir ScrollViewer içerisine yerleştirmemiz yeterli.

<UserControl x:Class="ScrollBar.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

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

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