Sayfalama senaryoları her zaman ihtiyacımız olan işlevselliklerden olmuştur.
En basit kullanımı ile bir DataGrid içerisindeki verinin sayfalanabilir olarak
gösterilebilmesi gerekir. Bu sayfalama işlemi bazen sunucu taraflı bazen de
istemci taraflı yapılabilir. Bu makalede Silverlight 3.0 ile beraber gelen
DataGrid kontrolünü kullanarak sayfalama işlemlerine göz atacağız.
Sayfalama için görsel kontrol?
Sayfalama işlemi için doğrudan Silverlight 3.0 ile beraber gelen DataPager
kontrolünü kullanacağız. Bu kontrol kendisine verilen PagedCollectionView
nesnesine göre sayfalama yapabiliyor. Tabi söz konusu veriyi doğrudan
DataPager'a vermek pek anlamlı değil o nedenle verimizi yaratıp ilk olarak bir
gride bağlayalım. Sonrasında Grid içerisindeki veriyi sayfalaması üzerine
DataPager'a gerekli komutu vereceğiz.
İstemci taraflı sayfalama...
İlk örneğimizde tüm veriyi istemci tarafında sayfalayacağız. Bu gibi bir
sayfalamayı ancak tüm veriyi istemci tarafına uygun bir sürede alabiliyorsanız
yapabilirsiniz. Eğer elinizdeki veri bir defada istemciye yüklenemeyecek durumda
ise sayfalamayı da tabi ki sunucu tarafında yapmak gerekecektir. İstemci
tarafındaki sayfalama aslında sadece görsel amaçlarla ve ileriki adımlarda
filtreme için kullanılabilir.
[XAML]
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm"
x:Class="SilverlightApplication77.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">
<StackPanel>
<data:DataGrid x:Name="Grid"></data:DataGrid>
<dataControls:DataPager x:Name="Pager"></dataControls:DataPager>
</StackPanel>
</Grid>
</UserControl>
Yukarıdaki örneğimizde bir DataGrid ve bir de DataPager kontrolü bulunuyor.
Söz konusu kontrollere gerekli isimleri de vererek kod tarafından ulaşılabilir
hale getirip uygulamamıza devam edebiliriz. Elimizde basit bir isim listesi
olduğunu düşünürsek ilk olarak bu listeyi bir PagedCollectionView'a
çevirmemiz gerekecek.
[VB]
Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim AnaListe As New List(Of String)
AnaListe.Add("Daron")
AnaListe.Add("Burak")
AnaListe.Add("Muammer")
AnaListe.Add("Uğur")
Dim Liste As New
PagedCollectionView(AnaListe)
Grid.ItemsSource = Liste
End Sub
Yukarıdaki kod içerisinde basit bir String List'in
PagedcollectionView'a çevrilmesini görebilirsiniz. Aslında işlem epey
basit çünkü PagedCollectionView zaten constructor'larından birinde
IEnumarable interface'ini implemente eden obje istiyor. Elimizdeki
liste de buna uyduğunu göre doğrudan çeviri işlemini hızlıca halledebiliyoruz.
Son olarak eldeki PagedCollectionView'u da Grid adındaki DataGrid'imize
aktarmamız ilk aşamanın tamamlanması için yeterli olacaktır.
[XAML]
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm"
x:Class="SilverlightApplication77.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">
<StackPanel>
<data:DataGrid x:Name="Grid"></data:DataGrid>
<dataControls:DataPager x:Name="Pager" PageSize="2" DisplayMode="PreviousNextNumeric"
Source="{Binding ItemsSource, ElementName=Grid}"></dataControls:DataPager>
</StackPanel>
</Grid>
</UserControl>
Şu ana kadar DataPager kontrolümüz ile DataGrid'in birbirinden haberi yoktu.
İşte yukarıdaki kod içerisinde bu iki kontrolü birbirinden haberdar ediyoruz ve
DataGrid'in ItemsSource'un kodumuz ile vermiş olduğumuz PagedViewCollection'ın
DataPager tarafından kontrol edilmesini sağlıyoruz.
Tüm bu işlemleri yapabilmek için basit bir Element Binding kullanarak
DataPager'ın Source Property'sini Grid'in
ItemsSource'una bind etmemiz yeterli oluyor. Artık elimizde
istemci tarafında sayfalama ile çalışabilen bir DataGrid var. DataGrid'in her
sayfasında kaç kayıt gösterileceğini PageSize özelliğinden
ayarlayabilirsiniz.

Sayfalama desteği ile bir DataGrid kontrolü.
DataPager ile ilgili farklı görsel özellikler için DisplayMode
Enumaration'ını incelemenizi tavsiye ederim.
Sunucu taraflı sayfalama...
Eğer veri miktarınız çok yüksek ise maalesef tüm veriyi istemci tarafına
almak gibi bir şansınız olmayabilir. Bu gibi durumlarda Silverlight
uygulamasının sürekli olarak istediği sayfanın sayısını sunucuya göndererek
sadece o sayfadaki veriyi sunucudan alması gerekecektir. Tahmin edebileceğiniz
üzere bu işin iki farklı ayağı var; birincisi sunucu tarafında uygun sayfaya ait
veriyi sayfa numarasına göre döndürebilen bir web servisinin hazırlanması,
ikincisi ise bu servisin Silverlight tarafından doğru olarak kullanılabilmesi.
[Service / VB]
Dim DB As New DataClasses1DataContext
<OperationContract()> _
Public Function VeriGetir(ByVal Atla As Integer, ByVal Al As Integer) As List(Of Urunler)
Return (From inc In DB.Urunlers Skip (Atla) Take (Al) Select inc).ToList()
End Function
<OperationContract()> _
Public Function KayitSayisi() As Integer
Return (From inc In DB.Urunlers Select inc).Count
End Function
Yukarıda sunucu tarafındaki servisimizin kodunu bulabilirsiniz. Toplamda iki
servise ihtiyacımız var; bu servislerinden biri veritabanında bulunan toplam
kayıt sayısını alarak istemciye göndermek zorunda. Böylece DataPager kontrolü
toplam kaç sayfalık bir veri ile uğraştığını bilebilecek. Diğer yandan sayfa
sayfa duruma göre veri döndürebilecek bir servis de kesinlikle şart. Tüm bunları
LINQ2SQL ile beraber yaparsanız sayfalamanız otomatik olarak SQL tarafına kadar
taşınmış oluyor. Aksi halde sizin SQL tarafındaki sayfalama mekanizmasını da
kurmanız gerekecektir.
Özellikle VeriGetir adındaki metodumuzu incelemek gerekirse toplamda iki
parametre aldığını görebiliriz. Bunlardan biri veritabanından kayıt çekilirken
kaç kayıt atlanmasını gerektiğini diğeri ise kaç kayıt alınması gerektiğini
belirtiyor. Örneğin her defasında 10'ar kayıt gösteriyorsak ve üçüncü
sayfadaysak toplam 20 kayıt atlamamız gerektiği ve 10 kayıt almamız gerektiğini
hesaplamak pek zor değil. Bu hesaplamaları Silverlight tarafında yaparak servise
parametre olarak vereceğiz. Servis de bize uygun veriyi döndürecek.
[XAML]
<UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm"
x:Class="SilverlightApplication77.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">
<StackPanel>
<data:DataGrid x:Name="Grid"></data:DataGrid>
<dataControls:DataPager x:Name="Pager" PageSize="1" DisplayMode="PreviousNextNumeric"></dataControls:DataPager>
</StackPanel>
</Grid>
</UserControl>
Yukarıdaki XAML kodu uygulamamızın ana ekranını temsil ediyor. Bir önceki
örneğimizden farklı olarak burada artık bir ElementBinding kullanmadığımı
görebilirsiniz. Nedeni çok basit; artık tüm veri DataGrid üzerinde değil o
nedenle DataPager gidip de Grid'in ItemsSource'u üzerinden sayfalama
yapamayacak.
Not: ElementBinding mekanizmasının çalışmasını ve ilk örneğimizdeki sistemi
daha profesyonel bir şekilde veriyi sunucu tarafında sayfalar hale getirmek
isterseniz yapmanız gereken IPagedCollectionView
interface'ini implemente eden kendi PagedCollectionView nesnenizi
programlamanız. Nesne içerisinde sayfa değişim eventlarından bir çok farklı
duruma erişip verinin uygun kaynaklardan alınmasını sağlayabilirsiniz. Ben
kişisel olarak ne kadar bu yolun daha profesyonel olduğunu düşünsem de hem
yazılım geliştirme süreci olacak hem de kalifikasyon açısından hedeflediğimiz
işlevsellik için biraz yüksek seviyede kaldığını düşünüyorum. O nedenle makalede
çok daha basit bir teknik kullanacağım. Eğer siz daha karışık işlevselliklere
ihtiyaç duyarsanız IPagedCollectionView
interface'i üzerinden ilerleyebilirsiniz.
DataPager'ı kullanmaktaki tek amacımız kullanıcıya uygun arayüzü göstermesi.
Yani "sağ" "sol" düğmeleri ve "sayılar" bizim için yeterli. Bundan sonrasında ne
de olsa sunucu tarafında sayfalama yapacağımıza göre DataPager'ın bize kullanıcı
tarafından seçili sayfanın sayısını vermesi yeterli olacaktır. Fakat
DataPager'ın çalışması için uygun bir PagedViewCollection'ın Source
olarak atanmış olması şart.
[VB]
WithEvents Servis As New ServiceReference1.Service1Client
Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Servis.KayitSayisiAsync()
End Sub
Private Sub Servis_KayitSayisiCompleted(ByVal sender As Object, ByVal e As ServiceReference1.KayitSayisiCompletedEventArgs) Handles Servis.KayitSayisiCompleted
Dim Liste As New List(Of Nullable(Of Integer))
For index As Integer = 1 To e.Result
Liste.Add(Nothing)
Next
Dim DummyList As New PagedCollectionView(Liste)
Pager.Source = DummyList
Servis.VeriGetirAsync(Pager.PageIndex * Pager.PageSize, Pager.PageSize)
End Sub
Sayfa ilk yüklendiğinde hemen kayıt sayısını getirecek olan servisimizi
çağırıyoruz. Söz konusu servisten toplam kayıt sayısı geldiği gibi sadece
DataPager'a verilmek üzere boş bir List yaratıyoruz. Bu List içerisinde
Item sayısı gelen kayıt sayısı ile aynı fakat List'in içindeki her Item
aslında boş! DataPager'ın çalışması için aslında boş bir liste yaratıp kendisini
kandırıyoruz.
[VB]
Private Sub Pager_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Pager.PageIndexChanged
Servis.VeriGetirAsync(Pager.PageIndex * Pager.PageSize, Pager.PageSize)
End Sub
Private Sub Servis_VeriGetirCompleted(ByVal sender As Object, ByVal e As ServiceReference1.VeriGetirCompletedEventArgs) Handles Servis.VeriGetirCompleted
Grid.ItemsSource = e.Result
End Sub
Artık DataPager kontrolümüzün PageIndexChanged durumunu yakalayabiliriz. Her
defasında sayfa değiştiğinde sayfa sayısı ile sayfa boyutunu çarpıp atlanacak
olan kayıt sayısını buluyoruz. Zaten sayfa sayısı Index olarak geldiği için ilk
sayfada 0 gelecek ve atlanacak kayıt sayısı da 0 olacak. Servise göndermemiz
gereken ikinci parametre de zaten DataPager'ın PageSize özelliği, yani sayfa
başına gösterilecek kayıt sayısı.
Son olarak bu servisimizden gelen sonucu da Grid'imize bağlarsak işlem
tamamlanmış olacaktır. Artık elimizde sunucu tarafında sayfalama yapabilen bir
arayüzümüz var.