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
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.
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.
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...
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.