2 Mayıs 2011 Pazartesi

Silverlight'ta Double-Click Nasıl Yapılır

Silverlight 5 ile birlikte, projelerimizde bazen ihtiyaç duyduğumuz double click (hatta 3,4 .. n tane click) olayının yakalanması geldi. Aslında eski Silverlight sürümlerinde bu özellik direkt olarak olmasa da biraz akıl yürütmeyle gerçeklenebiliyordu. (Global bir datetime ve point tanımla, mouse click’te belirli bir zaman geçmediyse ve mouse belirli bir mesafe içerisinde tıklanmışsa bunu yakala vs.). Silverlight 5’te ise bu olay ilginç bir şekilde gerçeklenmiş. Örneğimize bakalım;

Açtığımız Silverlight 5 projesinin xaml dosyasında bir Rectangle tanımlıyoruz (Makalenin ilerisinde bunun neden Button değil de Rectangle olduğunu söyleyeceğim ;) )
<UserControl x:Class="SilverlightApplication2.MainPage"
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"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
<Rectangle x:Name="rectangle1" Stroke="Black" StrokeThickness="10"
VerticalAlignment="Center" Width="100" Height="100"></Rectangle>
</Grid>
</UserControl>
Silverlight 5’te ilginç bir şekilde gerçeklenmiş dediğim nokta burada ortaya çıkıyor. Double Click desteği için özel bir “DoubleClicked” benzeri bir event tanımlamak yerine “MouseLeftButtonDown” eventi içerisinde, eventArgs parametresini kullanmayı tercih etmişler. Görelim;
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 SilverlightApplication2
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();

rectangle1.MouseLeftButtonDown += new MouseButtonEventHandler(rectangle1_MouseLeftButtonDown);
}

private void rectangle1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
MessageBox.Show("Double clicked!");
}
}
}
}
Event Args içerisindeki ClickCount property’si bize kaç sayıda click yapıldığını verdiği için buradan single, double, triple .. n-adet click sayısına göre istediğimiz ayrımı yapabiliyoruz. Silverlight 5 bloglarında bu gerçeklemenin Beta’ya özel olduğu ve Release ile değiştirilebileceği konuşuluyor, bu da aklınızda bulunsun.

Örnek uygulamamızın ekran çıktısı da tahmin edeceğiniz üzere şu şekilde;



















Peki bu örneği neden Rectangle kullanarak yaptım :) Aslında biz uygulamalarımızda rectangle’lar değil Button’lar kullanıyoruz. Silverlight Button’larda çoğunuzun da bildiği üzere MouseDown ve MouseUp eventleri, as designed olarak, Click eventi tarafından engellenir. Bunun çözümü olarak 2 yol var:
Birincisi ve çok tercih edilmeyeni Buton’un ClickMode’unu Hover yapmak ve MouseDown ve MouseUp event’lerinin engellenmesini önlemek. Ancak hangimiz isteriz ki bir Buton’un üzerine gelince Click event’i tetiklensin :)

Daha temiz olan 2. Yol ise, kendi Button sınıfımızı implement etmek ve bu sınıf içerisinde MouseDown ve MouseUp event’lerini isteğimize göre override etmektir. Bu da şu şekilde yapılıyor;
using System.Windows.Controls;
using System.Windows.Input;

namespace SilverlightApplication2
{
public class BenjaminButton: Button
{
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
e.Handled = false;
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
e.Handled = false;
}
}
}
Burada dikkat edilmesi gereken nokta, override edilen metotların sonunda e.Handled = False yapılması gerekliliğidir. Bu sayede, Click eventi, MouseDown ve MouseUp event’lerini engellemeyecektir. Xaml içerisinde kullanımı da tahmin ettiğiniz üzere;
<UserControl x:Class="SilverlightApplication2.MainPage"
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"
xmlns:Onur="clr-namespace:SilverlightApplication2"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<Onur:BenjaminButton x:Name="btn1" Content="Yeni Buton" Height="100" Width="100" HorizontalAlignment="Left"></Onur:BenjaminButton>

<StackPanel Orientation="Horizontal">
<TextBlock Text="Click: " Width="150" Height="30"></TextBlock>
<TextBlock x:Name="txt1" Width="250" Height="30"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="On Mouse Down: " Width="150" Height="30"></TextBlock>
<TextBlock x:Name="txt2" Width="250" Height="30"></TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
şeklinde olacaktır. Code behind ise;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SilverlightApplication2
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();

btn1.Click += new RoutedEventHandler(btn1_Click);
btn1.MouseLeftButtonDown += new MouseButtonEventHandler(btn1_MouseLeftButtonDown);
}

private void btn1_Click(object sender, RoutedEventArgs e)
{
txt1.Text = "Click olayı yakalandı";
}

private void btn1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
txt2.Text = "Mouse down olayı yakalandı. " + e.ClickCount.ToString() + " kere tıklandı";
}
}
}
Tıklama sonrasında ekran çıktısından görüldüğü üzere,



Hem Click hem de MouseDown olayı yakalanıyor ve double click desteğimizi de sağlamış oluyoruz.

Silverlight 5'te Double Click desteği bu şekilde verilmiş oluyor. Ancak tekrar hatırlatmakta fayda var, bu implementasyon Beta sürümü için geçerli ve SL 5 release olduğunda değişme ihtimali bulunuyor.