Makale Özeti

Bu makalemizde Silverlight Toolkit ile beraber gelen AutoCompleteBox kontrolünü inceliyoruz.

Makale

Bu yazımızda Silverlight Toolkit ile beraber gelen AutoCompleteBox kontrolünü inceleyeceğiz. Bilgisayarınızda Silverlight Toolkit yükledikten sonra Toolkit içerisindeki tüm kontrolleri Visual Studio içerisinde Toolbox'ta görebilirsiniz. Ayrıca Toolkit DLL'lerini referans alarak kontrolleri elle XAML sayfalarınıza ekleme şansınız da var. Örneğin AutoCompleteBox kontrolünü inceleyecek olursak; bir sayfaya söz konusu kontrolü eklemek için ilk olarak Toolkit Assembly'lerinden System.Windows.Controls.Input Assembly'sini projenize referans almanız sonrasında da System.Windows.Controls NameSpace'i altından kontrolü bulmanız gerekecektir.

[XAML]

<UserControl xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input" x:Class="SilverlightApplication54.MainPage"

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

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

   Width="400" Height="300">

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

        <input:AutoCompleteBox></input:AutoCompleteBox>

    </Grid>

</UserControl>

Yukarıda gördüğünüz basit örnek içerisinde XAML root elementimizde gerekli input XML namespace'i tanımlanmış durumda. Böylece artık input namespace'i üzerinden AutoCompleteBox kontrolümüzü kullanabiliriz. Daha önce de bahsettiğim üzere eğer Visual Studio'nun Toolbox'ından söz konusu kontrolü kod tarafına sürükle bırak tekniği ile yerleştirirseniz zaten tüm bu işlemleri otomatik olarak gerçekleştirilebiliyor.

Haydi veriye bağlayalım!

Kontrolümüzü artık sahneye yerleştirdiğimize göre hemen çalıştırmak ve sonucu görmek isteyeceğiz fakat onun öncesinde tabi ki bir veri bağlantısı yapmamız şart. Kullanıcılar kutuya birşey yazarken AutoComplete kısmında neler gösterilecek?

[XAML]

<UserControl xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input" x:Class="SilverlightApplication54.MainPage"

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

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

   Width="400" Height="300">

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

        <input:AutoCompleteBox x:Name="myAutoCompleteBox" VerticalAlignment="Top"></input:AutoCompleteBox>

    </Grid>

</UserControl>

[VB]

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

        Dim Secenekler() As String = {"Silverlight", "Silvernight", "Silverfight", "SilverMonth"}

        myAutoCompleteBox.ItemsSource = Secenekler

    End Sub

[C#]

        void MainPage_Loaded(object sender, RoutedEventArgs e)

        {

            string[] Secenekler = { "Silverlight", "Silvernight", "Silverfight", "SilverMonth" };

            myAutoCompleteBox.ItemsSource = Secenekler;

        }

Yukarıdaki kod içerisinde aslında basit bir şekilde tüm seçenekleri doğrudan AutoCompletebox'ın ItemsSource'una atamış oluyoruz. Sonrasında AutoCompleteBox kendi içerisinde gerekli filtrelemeleri kullanıcılar metin giriş yaptıkça gerçekleştirerek sonucu gösteriyor.

Silverlight içerisinde basit bir AutoCompleteBox
Silverlight içerisinde basit bir AutoCompleteBox

Peki ya web servisinden alacak olsak sonuçları?

Bir önceki örneği incelerken büyük ihtimal ile kendi içinizden "Eee peki kocaman bir listemiz varsa hepsini istemciye mi alacağız?" diye sormuşsunuzdur. Tabi ki hayır. Aslında normal şartlarda yapmamız gereken şey AutoCompleteBox içerisine yazılan kelimeyi sunucuya göndermek ve geri gelen sonucu da AutoCompleteBox'ın AutoComplete bölümünde göstermek. İşte bu işlemi yapabilmek için AutoCompletebox'ın Populating eventını kullanıyoruz.

Örneğimizde Tavsiye adında bir webmethod kullanacağız. Web servisinin yazımı kısmına girmeyeceğim fakat kabaca bahsetmek gerekirse istemciden aranacak kelimeyi alan ve veritabanına gidip uygun AutoComplete seçeneklerini bir list olarak döndüren bir webmethod yeterli olacaktır.

[VB]

    Private Sub myAutoCompleteBox_Populating(ByVal sender As Object, ByVal e As System.Windows.Controls.PopulatingEventArgs) Handles myAutoCompleteBox.Populating

        e.Cancel = True

        Dim servis As New ServiceReference1.Service1Client

        AddHandler servis.TavsiyelerCompleted, AddressOf Servis_TavsiyelerCompleted

        servis.TavsiyelerAsync(myAutoCompleteBox.Text)

    End Sub

[C#]

        public MainPage()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainPage_Loaded);

            myAutoCompleteBox.Populating += new PopulatingEventHandler(myAutoCompleteBox_Populating);

        }

 

        void myAutoCompleteBox_Populating(object sender, PopulatingEventArgs e)

        {

            e.Cancel = true;

            ServiceReference1.Service1Client servis = new ServiceReference1.Service1Client();

            servis.TavsiyelerCompleted += Servis_TavsiyelerCompleted;

            servis.TavsiyelerAsync(myAutoCompleteBox.Text);

        }

Yukarıdaki kodumuzda AutoCompleteBox'ın Populating durumunu yakalayarak hemen e.Cancel değerini True yaparak Populate işlemini iptal ediyoruz. Neden mi? Çünkü Populate işlemi, yani AutoComplete listesinin gösterilmesi işlemi şu anda yapılamaz. İşlemi yapabilmek için bizim Webmethod'umuza parametreyi vermemiz, söz konusu bilginin sunucuya gitmesi ve en önemli cevabın gelmesi gerekiyor! Cevap gelmeden Populate edemeyiz! O nedenle burada hemen Populate işlemini iptal ediyoruz. Sonrasında WebServis'imizden bir kopya alıp Completed durumu da ayrı bir handler'a bağlayıp elimizdeki AutoCompleteBox içerisinde metni Tavsiyeler adındaki Webmethod'umuza gönderiyoruz.

[VB]

    Private Sub Servis_TavsiyelerCompleted(ByVal sender As Object, ByVal e As ServiceReference1.TavsiyelerCompletedEventArgs)

        myAutoCompleteBox.ItemsSource = e.Result

        myAutoCompleteBox.PopulateComplete()

    End Sub

[C#]

        private void Servis_TavsiyelerCompleted(object sender, ServiceReference1.TavsiyelerCompletedEventArgs e)

        {

            myAutoCompleteBox.ItemsSource = e.Result;

            myAutoCompleteBox.PopulateComplete();

        }

Populating durumunda çağırdığımız web servisimizin Completed durumunda artık veri elimizde olduğunda göre doğrudan AutoCompleteBox'ımızın ItemsSource'una verebiliriz. Son olarak tabi ki Populate işlemini bitirdiğimizi de AutoCompleteBox'a belirtmemiz gerek ki hemen sonucu kullanıcıya göstersin.

Arama şeklini nasıl değiştiririz?

Varsayılan ayarları ile AutoCompleteBox'lar kendilerine verilen verinin içinde arama yaparken kullanıcının yazdığı metinile başlayan sonuçları gösterirler. Bunun değiştirmenin yolu AutoCompletebox'ların SearchMode özelliğinde yatıyor.

Veri kaynağında nasıl arama yapılacağını belirleyin.
Veri kaynağında nasıl arama yapılacağını belirleyin.

Peki bu arama sistemleri size yetmedi ve daha da özelleştirmek isterseniz ne yapabilirsiniz? Filtreleme işlemini tamamen ele alma şansınız da var. Bu durum özellikle AutoCompleteBox'a kendi nesne tiplerinizi bağladığınızda çok anlamlı olabilir. Filtreleme esnasından belki de sadece ItemsSource'a verdiğiniz nesnelerin belirli Property'lerine göre ayrı ayrı mantıklarıda aramalar yapılsın isteyebilirsiniz.

[VB]

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

        myAutoCompleteBox.ItemFilter = AddressOf Arama

    End Sub

 

    Function Arama(ByVal metin As String, ByVal nesne As ServiceReference1.Service1Urun) As Boolean

        If nesne.Adi.Contains(metin) Then

            Return True

        Else

            Return False

        End If

    End Function

[C#]

        public MainPage()

        {

            InitializeComponent();

            myAutoCompleteBox.ItemFilter = Arama;

        }

 

        bool Arama(string metin, ServiceReference1.Service1Urun nesne)

        {

            if (nesne.Adi.Contains(metin)) {

                return true;

            }

            else {

                return false;

            }

        }

Yukarıdaki örneğimizde AutoCompleteBox'ın ItemFilter'ına yeni bir metod atıyoruz. Bu metod parametre olarak o anda filtrelenmek istenen Item'ı, yani benim örneğimde ServiceReference ile beraber gelen tipte bir nesneyi ve filtrelemede kullanılacak metni alıyor. Sonrasında gerekli kontrolleri yaptıktan sonra geriye filtrelediğiniz her bir nesnenin gösterilip gösterilmeyeceğine dair birer Boolean değer döndürmeniz yeterli olacaktır.

Görsel özelleştirmeler...

Makalemizde incelediğimiz tüm özellikleri kullandınız, kendi nesnelerinizi web servisi ile döndürdünüz ve özel bir filtrelemede de eklediniz. Fakat AutoComplete listesinde daha çok detay göstermek istiyorsunuz. Bu durumda gelin AutoCompleteBox'ın ItemTemplate'ini bir inceleyelim.

[XAML]

        <input:AutoCompleteBox x:Name="myAutoCompleteBox" VerticalAlignment="Top">

            <input:AutoCompleteBox.ItemTemplate>

                <DataTemplate>

                    <Grid HorizontalAlignment="Stretch" Width="Auto">

                        <Grid.ColumnDefinitions>

                            <ColumnDefinition Width="250" />

                            <ColumnDefinition Width="250" />

                        </Grid.ColumnDefinitions>

                        <TextBlock Foreground="Red" Grid.Column="0" Text="{Binding Adi}" />

                        <TextBlock Foreground="Red" Grid.Column="1" Text="{Binding Soyadi}" />

                    </Grid>

                </DataTemplate>

            </input:AutoCompleteBox.ItemTemplate>

        </input:AutoCompleteBox>

Kod içerisinde de gördüğünüz üzere AutoCompleteBox'ın ItemTemplate'i aslında kendi içerisinde AutoComplete kısmında tekrar ettiği satırları tanımlıyor. Bu satırların tasarımı aslında arkaplanda bir ListBox'ın Item'larıdır. Bizim örneğimizde ulaşmaya çalıştığımız işlevsellik iki veya daha çok Property'i kullanıcıya gösterirken arka plandaki filtrelememiz ile de bir AutoComplete işlevselliği sağlamak. Zaten hali hazırda AutoCompleteBox'ımıza nesnelerimizi ItemsSource üzerinden aktardığımız için o nesnelerin tüm Property'lerine dair Binding'leri de ItemTemplate içerisinde ayarlayabiliyoruz.

AutoComplete kısmı özelleştirilmiş bir AutoCompleteBox.
AutoComplete kısmı özelleştirilmiş bir AutoCompleteBox.

Taktikler

Eğer herhangi bir AutoCompleteBox'ın ItemsSource'una kendi tanımladığınız tiplerden oluşan listeler verirseniz AutoComplete bölümünde saçma metinler görebilirsiniz. Normal şartlarda bir String Array vs verildiğinde herhangi bir sorun olmuyor fakat kendi tanımladığınız sınıflarda veya web servislerinden Proxy aracılığı ile aldığınız sınıflarda sorun yaşayabilirsiniz. Bu durumu düzeltmenin yolu kendi sınıflarınız için birer ToString extension'ı yazmak olabilir. AutoCompleteBox kendisine verilen tüm nesnelerin üzerinden ToString metodunu çağırarak gelen metni AutoComplete kısmında gösterir. O nedenle siz de kendi sınıflarınızda ToString'i override ederek kendi istediğiniz verileri geri döndürebilirsiniz.

[VB]

Namespace ServiceReference1

    Partial Public Class Service1Urun

        Public Overrides Function ToString() As String

            Return Me.Adi & Me.Soyadi

        End Function

    End Class

End Namespace

[C#]

namespace ServiceReference1

{

    public partial class Service1Urun

    {

        public override string ToString()

        {

            return this.Adi + this.Soyadi;

        }

    }

}

Yukarıdaki örnek kod içerisinde ServiceReference1 adında bir servis referansı ile beraber gelen Service1Urun adındaki nesnenin ToString metodunu override ediyoruz. Artık söz konusu nesneden sonra ToString denildiğinde buradaki Function çalışacak ve nesnenin Adi ile Soyadi Property'lerini birleştirerek geri döndürecek. Böylece AutoCompleteBox da bu ToString'den gelen veriyi gösterebilecek.

Otomatik seçilseler...

AutoComplete listesini gösteriyorsunuz fakat her seferinde kullanıcının bir kayıt seçmek zorunda kalmasını da istemiyorsunuz. Belki de en uygun seçecek hemen seçilebilir şekilde gelse? Nasıl mı?

IsTextCompletionEnabled = True olursa...
IsTextCompletionEnabled = True olursa...

AutoCompleteBox'ın IsTextCompletionEnabled özelliği True yaparsanız yukarıdaki gibi kullanıcılar metin girişi yaparken bir yandan da en uygun seçeneği seçtirebilirsiniz. Böylece anında seçimi onaylayarak kullanıcılar hızlıca işleme devam edebilirler.

Hepinize kolay gelsin.