Silverlight 4 Beta'da sağ tuş desteği ve bir ContextMenü kontrolü

0 dakikada yazıldı

6362 defa okundu

Düzenle

Silverlight 3 zamanlarında gelen en önemli isteklerden biri farenin sağ
tuşu ile ilgili eventları yakalayabilmekti. Biliyorsunuz normal
şartlarda herhangi bir Silverlight uygulamasına sağ tuş ile tıklarsanız
karşınıza "Silverlight" diye bir menü seçeneği geliyor ve burada da
Silverlight Runtime ile ilgili ayarlara ulaşılabiliyor. Uzun bir süre
sağ tuş implementasyonunun pek de mümkün olmadığı ve güvenlik nedeni ile
Microsoft'un bu gibi bir şeye izin vermeyeceği konusunda yorumlar
internette gezindi. İtiraf etmek gerekirse ben de konsept olarak pek
olası bir çözüm öngöremiyordum.

Silverlight 4'te fareye sağ tuş desteği!

Oysa bir de baktık ki Silverlight 4 ile (Beta) farenin sağ tuşuna dair
eventleri de ayrıca yakalayabiliyoruz. Bu destek özellikle iş
uygulamalarında çok anlamlı bir boşluğu dolduruyor. Kullanıcılara hali
hazırda web ortamında bir "thinclient" deneyimi sunan ve sanki windows
ortamındaki programları kullanıyormuşcasına zengin deneyimler
sağlayabilen Silverlight'ın aynı hissiyatı devam ettirebilmesi adına
farenin sağ tıklamalarına da uygun tepkileri verebilmesi çok önemliydi.
Bu açığın kapatılıyor olduğunu görmek çok sevindirici.

Peki nasıl?

Aslında konu epey basit. Artık Silverlight içerisindeki tüm kontrollerin
MouseLeftButtonDown ve MouseLeftButtonUp gibi birer de
MouseRightButtonDown ve MouseRightButtonUp eventları bulunuyor.
Söz konusu eventları tarayıcı ve platform bağımsız olarak yakalayıp
istediğiniz işlevselliği sunabilirsiniz.

Silverlight 4'te sağ tuş desteği gelmesine rağmen varsayılan ayarlarla
hala sağ tuş ile tıkladığınızda eksi klasik Silverlight menüsü
gelecektir. Bu menünün gelmesini engellemek için tabi ki kendi
implementasyonunuzu yapmanız gerekiyor. Eğer bu menünün gelmesini
istemiyorsanız hemen herhangi bir kontrolün MouseLeftButtonDown
eventını yakalayarak event listener'a gelen argüman üzerindeki
Handled Property'sini kullanabilirsiniz.

[XAML]

<UserControl
x
:Class="SilverlightApplication13.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">

        <TextBox
x
:Name="txtMetin"
Height
="100" />

        <Grid
x
:Name="ContextMenu"
Visibility
="Collapsed" HorizontalAlignment="Left"

             VerticalAlignment="Top"
Height
="50" Width="150"
Background
="Red">

            <TextBlock
Text
="Başardın!" />

        </Grid>

    </Grid>

</UserControl>

Yukarıdaki XAML kodunda basit bir TextBox ve bir de Visibility
özelliği Collapsed olarak ayarlanmaış Grid görüyorsunuz.
Amacımız TextBox'a sağ tuş ile tıklandığında bir ContextMenu kıvamında
Grid'imizi kullanıcıya göstermek. Grid içerisinde ben deneme amacı ile
bir TextBlock koydum fakat siz hem bu Grid'in içerisinde duruma göre
programatik olarak doldurabilir hem de içerisine düğmeler koyup
düğmelerin click eventlarını yakalayabilirsiniz. Sistemi geliştirmek
size kalmış.

[VB]

    Private Sub txtMetin_MouseRightButtonDown(ByVal sender As Object,
ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles txtMetin.MouseRightButtonDown

        e.Handled = True

    End Sub

İlk olarak TextBox kontrolümüzün MouseRightButtonDown eventını
yakalayarak burada Handled özelliğine True değerini veriyoruz.
Böylece TextBox'ın üzerine sağ tuş ile tıklandığı anda söz konusu
senaryoyla bizim ilgilendiğimizi sisteme belirtmiş oluyoruz ve artık
Silverlight Runtime kendi menüsünü göstermiyor. Normal şartlarda Context
menülerin gösterimi farenin sağ tuşu kaldırıldığında yapılır. Yani tuşa
bastığınızda değil tuştan parmağınızı çektiğinizde context menü
gösteriliyor. Biz bu event ile tuşa basıldığı anda "Hop! Ben
halledeceğim bu işi
" :) şeklinde bir mesaj ile Silverlight Runtime'ı
pinglemiş oluyoruz ve tabi ki MouseRightButtonUp durumunu yakalayıp
kendi menümüzü göstermek de bize kalıyor.

[VB]

    Private Sub txtMetin_MouseRightButtonUp(ByVal sender As Object,
ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles txtMetin.MouseRightButtonUp

        ContextMenu.Margin = New Thickness(e.GetPosition(Me).X, e.GetPosition(Me).Y, 0, 0)

        ContextMenu.Visibility = Windows.Visibility.Visible

    End Sub

Sıra geldi olası bir ContextMenu yapısını kullanıcıya göstermeye. XAML
kısmından hatırlarsanız bizim elimizde adı ContextMenu olan bir Grid
vardı. Amacımız bu Grid'i farenin sağ tuşu ile tıklandığında tıklanan
noktada göstermek. Bu nedenle yine TextBox'ın MouseRightButtonUp
eventını yakalayarak bu elimizdeki ContextMenu'nün Margin'ini
ayarlıyoruz. ContextMenu işlevselliği görecek Grid'imiz bir başka Grid
içerisinde yer aldığı için pozisyonunu değiştirebilmek adına Margin
vermemiz şart. Dikkat etmeniz gereken nokta Grid'in XAML içerisinde
pozisyonlandırma olarak sol üste yaslanmış olması. O nedenle sol üst
köşeden mesafalelerini vermemiz pozisyonlandırma için yeterli olacaktır.
Yine event listener'a gelen argüman üzerinden GetPosition metodunu
kullanarak farenin tıklandığı yerin X ve Y koordinatlarını alarak
Margin olarak Grid'imize veriyoruz. Böylece ContextMenu'müz artık
istediğimiz yere geldi ve gösterime hazır. Bu durumda Visibility'sini de
Visible yaparak kullanıcıya gösterebiliriz.

[VB]

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

        ContextMenu.Visibility = Windows.Visibility.Collapsed

    End Sub

Unutmadan! Uygulama içerisinde bir yerlere farenin sol tuşu ile
tıklandığında ContextMenu'üyü tekrar görünmez yapmayı atlamayın yoksa
context menü sürekli gözükecektir. Bunun için basit bir şekilde root
elementin MouseLeftButtonDown özelliğini yakalayıp orada Grid'imizin
Visibility'sini Collapsed yapabilirsiniz.

Daha kolay yolu yok mu ContextMenü meselesinin?

Farkındayım :) Kendi kendinize "Ya tamam da bir ContextMenü için bu
kadar uğraşmak doğru mu? Yok ContextMenü kontrolü?" şeklinde sordunuz :)
Maalesef yok! Yani en azından Silverlight 4 Beta ile şu anda gelmiyor.
Ama güzel bir haberim var. Silverlight Program Manager'lardan Jesse
Bishop
'un
yazmış olduğu bir kontrol var. Söz konusu kontrolü kullanarak rahatlıkla
uygulamalarınıza ContextMenu'ler ekleyebilirsiniz. Gelin basit bir
şekilde bu implementasyonun nasıl yapıldığına bir göz atalım.

İlk olarak Jesse Bishop'un yazmış olduğu kontrolün kaynak kodlarını
sitesinden indirerek compile etmeniz gerek veya üşeniyorsanız ben sizin
için compile ettim :) Aşağıdaki linkten doğrudan Assembly'leri
indirebilirsiniz.

Silverlight 4 Beta için ContextMenu Kontrolleri - 21112009_1.zip
(19,11 KB)

Referans alma işlemini tamamladıktan sonra Assembly içerisindeki
kontrolleri kullanabilmek adına Assembly'yi XML NameSpace ile XAML
tarafına import etmemiz gerek.

[XAML]

<UserControl
x:Class="SilverlightApplication13.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"

            xmlns:context="clr-namespace:ContextMenuControls;assembly=ContextMenuControls"

  
mc:Ignorable="d"

  
d:DesignHeight="300" d:DesignWidth="400">

Import işlemi de tamamlandığına göre artık bu Assembly içerisindeki tüm
kontrolleri projemizde kullanabiliriz. Bir önceki örneğimizdeki TextBox
ile devam edelim. Amacımız bu TextBox'a yine bir ContextMenü atamak.

[XAML]

        <TextBox x:Name="txtMetin"
Height="100" >

            <context:ContextMenu.ContextMenu>

                <context:ContextMenu>

                    <context:MenuItem
Text
="Hede" Tag="1"
Click
="MenuItem_Click" />

                    <context:MenuItem
Text
="Hödö" Tag="2"
Click
="MenuItem_Click" />

                    <context:MenuItem
Text
="Bödö" Tag="3"
Click
="MenuItem_Click" />

                </context:ContextMenu>

            </context:ContextMenu.ContextMenu>

        </TextBox>

Gördüğünüz gibi olay epeyce basit aslında. TextBox için bir
ContextMenu atadıktan sonra içerisine de istediğimiz kadar
MenuItem koyabiliyoruz. Ben örnek olarak tüm MenuItem'ları aynı
event-listener'a bağladım. Söz konusu event listener içerisinde de gelen
MenuItem'ın Tag'ına göre senaryolarınızı ayrıştırabilirsiniz.
Aslında söz konusu kontroller Silverlight 4 ile beraber gelen Commanding
yapısına da destek veriyor fakat şimdilik daha commanding kısmı ile
ilgili makale yazmadığım için konuyu oralara genişletmiyorum.

[VB]

    Private Sub MenuItem_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs)

        MessageBox.Show(CType(sender, ContextMenuControls.MenuItem).Tag)

    End Sub

Eğer ContextMenu'leri kod ile yaratıp kontrollere atamak isterseniz tabi
ki bu da mümkün. Bunun için örneğimizdeki TextBox'a ait ContextMenu
Assembly'sinden gelen bir attached property'yi set ederek
ilerleyebiliriz.

[VB]

        Dim CMenu As New
ContextMenuControls.ContextMenu

        Dim Item As New
ContextMenuControls.MenuItem

        Item.Text = "Gel Tıkla"

        AddHandler Item.Click, Sub()

                                   MessageBox.Show("ok")

                               End
Sub

        CMenu.Items.Add(Item)

        ContextMenuControls.ContextMenu.SetContextMenu(txtMetin,
CMenu)

Yukarıdaki kod içerisinde bir ContextMenu yaratıp içerisine de bir
MenuItem yerleştiriyoruz. Basit bir şekilde şimdilik MenuItem'a
tıklandığında bir MessageBox gösteriyoruz. Önemli olan en sonda
ContextMenu sınıfı üzerinden SetContextMenu ile TextBox'a
elimizdeki menüyü ataçlamamız. Böylece herşey tıkırında çalışacaktır.

Buradan bu güzel kontrol için Jesse'ye teşekkür ediyorum :) Umarım
yakında Silverlight Toolkit'te görürüz bu kontrolü.

Hepinize kolay gelsin.