Makale Özeti

Behavior' lar, Silverlight projelerinde uzun kodlama süreçlerinde ihtiyaç duyulan bazı görevleri, sürükle-bırak metodu ile kolayca halletmemize yarayan olgular. Bu makalede Behavior kavramının biraz daha derinlerine inip, hoş bir kar yağışı efekti yaratmaya çalışacağız.

Makale

Merhabalar. Bu Silverlight makalemizde, Behavior(davranış) dosyası oluşturarak nasıl kar yağışı efekti yaratırız'ı inceliyor olacağız.

Öncelikle biraz Silverlight' daki Behavior (davranış)  kavramından bahsetmek istiyorum. Aslında Behavior yapısını, karmaşık kodlama gerektiren işlemleri, kod yazmadan XAML içerisinden halletmemize yarayan araçlar olarak tanımlayabiliriz. Mesela, bazı fizik kurallarını nesnelere uygulamak için Behavior' lara ihtiyaç duyarız. Bu noktada Silverlight SDK ve Blend 3 ile gelen birkaç Behavior' a değinmek istiyorum.

  1. ChangePropertyAction : Herhangi bir kontrolün, herhangi bir anda, herhangi bir özelliğini değiştirmemize yarar.
  2. FluidMoveBehavior : Bir Panel kontrolü düşünelim. Bu Panel kontrolünde gerçekleşen herhangi bir görsel değişimden altındaki kontrollerin etkilenmesi esnasında animasyon gerçekleştirmemize yarar.
  3. HyperlinkAction : Herhangi bir nesneye HyperLink davranışı vermemize yarar.

Listeyi daha uzatabiliriz ama gerek yok.

Bu makalede ise, sürükle bırak yaptığımız, işlerimizi kolayca halletmemize yarayan Behavior' ları nasıl oluşturabiliceğimizi göreceğiz ve aşağıda gördüğünüz efekti yaratacağız.

Get Microsoft Silverlight

Tasarım Aşaması

Hazırsak artık başlayabiliriz. Öncelikle Blend' de yeni bir Silverlight 3 projesi oluşturalım. File-->New Project-->Silverlight 3 Application + Website

Projemizi Yaratalım!

Projemiz oluştuktan sonra ilk iş olarak LayoutRoot kontrolünün tipini değiştiriyoruz. Öntanımlı olarak Grid tipinde gelir. Grid ne kadar güzel özelliklere sahip olsa da, bizim Canvas kullanmamız daha yararlı olacaktır. Bunun için LayoutRoot' a sağ klik yapıyoruz ve Change Layout Type--> Canvas 'ı seçiyoruz.

Layout Root' un Tipini Değiştirdik

 Bir de sayfamıza gece efekti sağlamak için Properties-->Brushes-->Gradient Brush 'ı kullanalım.

Renk kodlarınına dikkat edin!

Artık kar tanelerimizi oluşturabiliriz. Ellipse nesnesi bu iş için biçilmiş kaftan bence. Copy-Paste yardımı ile sayfamızı değişik ebatlarda, beyaz Ellipse' lerle dolduralım. Bu işlemler sonucunda aşağıdaki görüntüye benzer bir görüntü elde etmiş olmalıyız.

Ortadaki TextBlock Tercihe Bağlıdır :)

Tasarım aşamasının sonuna gelmiş bulunmaktayız. Artık Behavior' ımızı oluşturabiliriz.

Behavior Yazma Aşaması

Behavior kullanmamızın bize sağladığı en büyük yarar, onlarca kartanesinin düşüş animasyonunu bir kerede halledebilme imkanı sunması. Bu nedenle projemize yeni bir Behavior ekleyelim. Blend' in tasarım alanında sol üst köşede, Projects tabından Silverlight projemizi bulalım. Sonra sağ klik yapıp açılan context menuden Add New Item seçeneğini seçelim. Karşımıza bir pencere çıkacak. Oradan da Behavior'ı işaretleyip, isimini de "KarYagisi" verebiliriz.

Behavior'ımızı Oluşturduk

Tüm bu işlemler bittikten sonra, kodlamaya başlamaya geliyor sıra. Oluşan dosyanın içine bakıcak olursanız, gözünüze otomatik olarak oluşturulmuş OnAttached() ve OnDetaching() metodları çarpıcaktır. İsimlerinden de anlaşılacağı üzere, behavior bir nesneye bağlandığında OnAttached metodu, bir nesneden ayrıldığında da OnDetaching metodu çalışacaktır. Bu prensiplere göre kodumuzu yazmalıyız.

İlk dikkat etmemiz gereken nokta behavior' ın hangi nesneye etki ediceğini belirlemek. Varsayılan olarak DependencyObject geliyor. Biz Behavior' ımızı, daha önce Canvas tipine çevirdiğimiz Layout Panel' a bağlıyacağımız için bu değeri Canvas olarak değiştiriyoruz. Burada önemli olan nokta , oluşturduğunuz Behavior' ı hangi tipteki nesneye bağlayacak olmanız. Ona göre bu değeri değiştirmeniz gerekiyor.

[C#]
  1. public class KarYagisi : Behavior<Canvas>
[VB]
  1. Public Class KarYagisi
  2.     Inherits Behavior(Of Canvas)

Kodlama sırasında bolca rastgele(random) değer almış double tipindeki değerlere ihtiyaç duyacağız. Örnek vermek gerekirse, kartanelerinin opaklık değerleri, hızları ve dönüş açıları farklı olmalı. Hiç bir kartanesi dümdüz yere düşmez değil mi :).

Bu yüzden öncelikle Random bir değişken oluşturuyoruz.

[C#]
  1. private static Random randomNumber;
[VB]
  1. Private Shared randomNumber As Random

Gelelim bir sonraki yapıcağımız hamleye. OnAttached() metodunun altına Behavior' ın bağlandığı nesnenin Load olayını yakalayabilmek için yeni bir RoutedEventHandler tanımı ekliyoruz.

[C#]
  1. protected override void OnAttached()
  2. {
  3.     base.OnAttached();
  4.  
  5.     randomNumber = new Random();
  6.  
  7.     this.AssociatedObject.Loaded += new RoutedEventHandler(ApplicationLoaded);
  8. }
[VB]
  1. Protected Overrides Sub OnAttached()
  2.     MyBase.OnAttached()
  3.  
  4.     randomNumber = New Random
  5.  
  6.     AddHandler Me.AssociatedObject.Loaded, AddressOf ApplicationLoaded
  7. End Sub

ApplicationLoaded metodu içinde efektimizi yaratmaya geldi sıra. ApplicationLoaded olayına erişiyoruz çünkü bir SL uygulaması çalıştığında sayfaya bir çok şey yüklenir. Bizim bir karmaşaya yol açmamak için tüm uygulama yüklendikten sonra işlemlerimizi yapmamız gerekiyor.  Oluşturucağımız efektin Layout Panel içindeki her objeyi etkilemesini istediğimiz için bu sorunu bir foreach döngüsü ile halledebiliyoruz. Bu sayede her bir nesnenin Render() olayında, ilk oluştuğunda ve ekran her yeniden yüklendiğinde uğrayacağı olayda ,  rastgele değerler almış hız, açı ve opaklık derecesi gibi değerlerimizi tanımlayabiliyoruz. Nasıl mı?

[C#]
  1. void ApplicationLoaded(object sender, RoutedEventArgs e)
  2. {
  3.     foreach (FrameworkElement element in this.AssociatedObject.Children)
  4.     {
  5.         FrameworkElement localCopy = element;
  6.         //TextBlock da kar taneleri gibi davranmasın diye ona "asd" ismini vermiştim.
  7.         if (localCopy.Name != "asd")
  8.         {
  9.  
  10.             double yPosition = Canvas.GetTop(localCopy);
  11.             double xPosition = Canvas.GetLeft(localCopy);
  12.  
  13.             double speed = 2 * randomNumber.NextDouble();
  14.             double counter = 0;
  15.             double radius = 30 * speed * randomNumber.NextDouble();
  16.  
  17.             localCopy.Opacity = .2 + randomNumber.NextDouble();
  18.  
  19.             CompositionTarget.Rendering += delegate(object o, EventArgs arg)
  20.             {
  21.                 counter += Math.PI / (180 * speed);
  22.  
  23.                 if (yPosition < Application.Current.RootVisual.DesiredSize.Height)
  24.                 {
  25.                     yPosition += .2 + speed;
  26.                 }
  27.                 else
  28.                 {
  29.                     yPosition = -localCopy.Height;
  30.                 }
  31.  
  32.                 Canvas.SetTop(localCopy, yPosition);
  33.                 Canvas.SetLeft(localCopy, xPosition + radius * Math.Cos(counter));
  34.             };
  35.         }
  36.         else
  37.         {
  38.             localCopy.Opacity = .2 + randomNumber.NextDouble();
  39.         }
  40.  
  41.     }
  42.  
  43. }
[VB]
  1.     Dim yPosition As Double
  2.     Dim xPosition As Double
  3.     Dim speed As Double
  4.     Dim counter As Double
  5.     Dim radius As Double
  6.     Dim localCopy As FrameworkElement
  7.     Private Sub ApplicationLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
  8.         For Each element As FrameworkElement In Me.AssociatedObject.Children
  9.             localCopy = element
  10.             If Not localCopy.Name = "asd" Then
  11.  
  12.                 yPosition = Canvas.GetTop(localCopy)
  13.                 xPosition = Canvas.GetLeft(localCopy)
  14.  
  15.                 speed = 2 * randomNumber.NextDouble
  16.                 counter = 0
  17.                 radius = 30 * speed * randomNumber.NextDouble
  18.  
  19.  
  20.                 localCopy.Opacity = 0.2 + randomNumber.NextDouble
  21.  
  22.                 AddHandler CompositionTarget.Rendering, AddressOf ObjectRender
  23.             End If
  24.         Next
  25.     End Sub
  26.     Private Sub ObjectRender(ByVal sender As Object, ByVal e As EventArgs)
  27.         counter += Math.PI / (180 * speed)
  28.         If yPosition < Application.Current.RootVisual.DesiredSize.Height Then
  29.             'Sayfanın içindeyse
  30.             yPosition += 0.2 + speed
  31.         Else
  32.             'Sayfanın dışında ise
  33.             yPosition = -localCopy.Height
  34.         End If
  35.         Canvas.SetTop(localCopy, yPosition)
  36.         Canvas.SetLeft(localCopy, xPosition + radius * Math.Cos(counter))
  37.     End Sub

Yukarıda yaptığımız işi özetlemek istiyorum. Öncelikle sayfaya koyduğum TextBlock hareket etmesin diye onu efektin dışında bıraktım. Sonra düzenlediğimiz nesnenin x ve y pozisyonunu değişkenlere atadım. randomNumber değişkeninin yardımıyla rastgele oluşturduğum hız, açı ve opaklık değerlerini değişkenlerine atadım. Her bir nesnenin Render() olayına erişerek, onları Y ekseninde hareket ettirdim.

Olay bu kadar kolay ! Böylelikle Behavior' ımızı oluşturmuş olduk.

Behavior' ı Layout Nesnesine Bağlama Aşaması

Evet, son aşamaya da gelmiş bulunuyoruz. Bu aşamada oluşturduğumuz Behavior' ı Layout' a uygulayacağız. Öncelikle projemizi Build etmemiz lazım. CTRL-SHIFT-B tuş kombinasyonu ile projemizi Build ettikten sonra tasarım alanının solundaki Assets tabının altına Behaviors kısmına tıklıyoruz. Karşımıza çıkan listeden KarYagisi adlı behavior' ımızı bulup, sürükle bırak metodu ile sol alttaki Layout Root nesnesinin üstüne bırakıyoruz.

Projeyi çalıştırdığınız zaman herhangi bir adımda hata yapmadıysanız sorunsuz çalıştığını göreceksiniz.

 

Böylelikle bu yazımızın sonuna gelmiş olduk. Başka bir Silverlight makalesinde görüşmek üzere herkese iyi kodlamalar.