Makale Özeti

Bu makalemizde Silverlight 3.0 ile beraber gelen DataPager kontrolünü incelerken sunucu ve istemci taraflı farklı sayfalama tekniklerine de göz atıyoruz.

Makale

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