Makale Özeti

Bu yazımızda Silverlight 3.0 Beta ile beraber gelen Element Binding sistemini incelerken zor durumlarda IValueConverter ile farklı tipteki Property'leri nasıl birbirine bağlayabileceğimizi de göreceğiz.

Makale

Bu makalemizde aslında uzun zamandır WPF tarafında bulunan fakat Silverlight 2.0'da olmayan bir özellikten bahsedeceğiz. Tabi bu özellikten bahsetmemizin nedeni ise artık Silverlight 3.0 ile söz konusu özelliği kullanabiliyor olmamız. Bahsettiğimiz özellik Element Binding özelliği. Element Binding'i kabaca bir kontrolün herhangi bir özelliğinin otomatik olarak başka bir kontrolün bir özelliğine bağlanması ve aradaki değer değişikliklerinin karşı tarafa otomatik olarak aktarılması şeklinde tanımlayabiliriz.

[XAML]

        <StackPanel>

            <TextBox x:Name="BirTextBox" ></TextBox>

            <Slider

               x:Name="BirSlider"></Slider>

        </StackPanel>

Ekranımızda yukarıdaki şekli ile bir TextBox ve bir de Slider kontrolü olduğunu düşünelim. İstediğimiz şey bu Slider kontrolündeki değerin sürekli olarak TextBox içerisinde gösterilmesi. Normal şartlarda böyle bir işlevsellik için basit bir şekilde Slider'ın ValueChanged durumunu yakalayıp sürekli olarak Slider'ın Value özelliğinden değer alıp, bunu da String'e çevirip TextBox'ın Text değerine eşitleyebilirdik. Eğer bu eşitlemenin çift taraflı olmasını istiyorsanız farklı taklalar ile TextBox'ın da TextChanged durumunu yakalayıp Slider'ın Value değerinin değiştirmeniz gerekecektir. Sonuç olarak her iki kontrolden birinde kullanıcı bir değişiklik yaptığında diğerine yansıyacak. Ama bu kadar kod yazmaktansa artık Binding tanımlayarak hızlıca ilerleyebiliyoruz.

[XAML]

        <StackPanel>

            <TextBox Text="{Binding Value, ElementName=BirSlider}" ></TextBox>

            <Slider

               x:Name="BirSlider"></Slider>

        </StackPanel>

Artık TextBox'ımızın Text özelliğine farklı bir değer veriyoruz. Bu değer özünde bir Binding nesnesi. Binding'imizi tanımlarken hedeflediğimiz Property olarak Value ve bu Property'nin alınacağı yer olarak da BirSlider adındaki Slider kontrolümüzü gösteriyoruz. Bu noktadan sonra projeyi çalıştırdığımızda Slider içerisinde kullanıcı tarafından bir değişiklik yapıldığında otomatik olarak TextBox'ın Text'inin de güncellendiğini görebiliriz. Oysa teknik açıdan baktığımızda birbirine Bind ettiğimiz Property'ler olan Text ve Value Property'lerinin tipleri farklı. Value bir Double olarak gelirken Text ise String olarak geliyor. Binding esnasında buna rağmen bir sorun yaşamıyoruz.

Diğer yandan eğer TextBox içerisindeki sayısal değeri el ile değiştirirsek bu değerin Slider'a yansımadığını görüyoruz. Bu sorunu halledebilmek için Binding tanımlarken özellikle Binding işleminin çift taraflı olarak yapılacağını da belirtmemiz gerekecek.

[XAML]

        <StackPanel>

            <TextBox

               Text="{Binding Value, ElementName=BirSlider, Mode=TwoWay}"></TextBox>

            <Slider

               x:Name="BirSlider"></Slider>

        </StackPanel>

Kod içerisinde de gördüğünüz üzere artık Binding'imizin modunu TwoWay olarak değiştirdik. Sonuç olarak kullanıcı TextBox içerisine sayısal bir değer girdiğinde bu değer otomatik olarak Slider'ın da Value özelliğine aktarılacaktır.

Peki ya bind edilecek tipler tutmazsa?

Eğer birbirine bind etmek istediğiniz Property'lerin tamamen birbiri ile alakasız ise bu sefer de Binding esnasında Converter yapılarını kullanabilirsiniz. IValueConverter arayüzünü implemente eden bir sınıf yaratıp rahatlıkla Binding esnasında gelen ve giden veriye müdahale edebilirsiniz.

Örneğin gelin bir Slider'ın Value'su ile bir Calendar kontrolünün SelectedDate özelliğini birbirine bağlamaya çalışalım. Normal şartlarda DateTime ile Double'ı birbirine bağlayamazsınız ayrıca Slider'ın başlangıç ve son değerleri yine birer Double iken belki biz farklı başlangıç ve son tarihleri arasında Slider'ın çalışmasını isteyeceğiz. İşte tam da bu noktada Sliderdan gelen değerleri birer tarih eşleştirirsek Calendar için de anlamlı bir veri kaynağı yaratmış oluruz.

[VB]

Public Class Cevirici

    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

        Return Now.Date.AddDays(value)

    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

        Return CType(value, Date).Subtract(Now).TotalDays + 1

    End Function

End Class

[C#]

    public class Cevirici : System.Windows.Data.IValueConverter

    {

        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            return DateTime.Now.Date.AddDays((double)value);

        }

 

        public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            return ((System.DateTime)value).Subtract(DateTime.Now).TotalDays + 1;

        }

    }

Yukarıda gördüğünüz Cevirici sınıfı IValueConverter arayüzünü implemente ettiği anda Convert ve ConvertBack metodlarına da sahip oluyor. Bu metodlar Binding esnasında gelen ve giden verinin farklı tiplere çevrimi için kullanılabilir. Bizim örneğimizde Convert metoduna gelen Double değerlerini o anki tarihe gün olarak ekliyoruz. Böylece Slider'dan 2 değeri geldiğinde aslında Calendar kontrolüne de bugünden 2 gün sonrasına ait tarihi vermiş oluyoruz. Eğer Calendar içerisinde bir seçim yapıldığında Slider'a da yansımasını istiyorsanız ConvertBack metodunu da yazmanız gerekiyor. Bu metoda da Calendar'dan SelectedDate geleceği için o anki tarih ile farkını bulup geri döndüyüroz.

[XAML]

<UserControl

   xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

   x:Class="SilverlightApplication27.MainPage"

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

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

   xmlns:daron="clr-namespace:SilverlightApplication27"

   Width="400"

   Height="300">

    <UserControl.Resources>

        <daron:Cevirici

           x:Name="BirCevirici" />

    </UserControl.Resources>

    <Grid

       x:Name="LayoutRoot"

       Background="White">

        <StackPanel>

            <controls:Calendar

               SelectedDate="{Binding Value,

                               ElementName=BirSlider,

                               Converter={StaticResource BirCevirici},

                               Mode=TwoWay}"></controls:Calendar>

            <Slider

               x:Name="BirSlider"

               SmallChange="1"

               LargeChange="1"></Slider>

        </StackPanel>

    </Grid>

</UserControl>

Kod tarafında hazırladığımız Converter'ımızı XAML tarafında kullanabilmek için hemen daron adında bir XAML namespace'i tanımladım ve çalıştığım projenin Assembly'sine bağladım. Böylece söz konusu Assembly içerisindeki kontrolleri XAML tarafında kullanabileceğiz. Bir sonraki adımda kod tarafındaki Cevirici tanımından bir kopyayı UserControl'un Resource'larına alıyorum ve adını da BirCeviri koyuyorum. Artık BirCeviri nesnemizi Converter olarak istediğimiz Binding'lerde kullanabiliriz. Kendi Binding tanımımıza bu bilgiyi de ekledik mi işlem tamamdır. Unutmadan Binding'in modunu da TwoWay olarak ayarlayalım.

İşte bu kadar!

Gördüğünüz gibi kontrollerin farklı özelliklerini rahatlıkla birbirlerine gerektiğinde çift yönlü olarak da bağlayabiliyoruz. Bu bağlama işlemi esnasında çok farklı çeviri ve kontrol mekanizmaları oluşturabileceğimiz ValueConverter yapısına da göz attığımıza göre bir makalemizin daha sonuna geldik.

Hepinize kolay gelsin.