Makale Özeti

DataGrid neredeyse her iş uygulamasında sıkça kullandığımız kontrollerin arasında yerini alıyor. Silverlight 2.0 Beta 1 ile beraber tamamen istemci tarafında çalışabilen DataGrid kontrolünün özelliklerini DataBinding senaryoları ile beraber inceliyoruz.

Makale

Silverlight 2.0 Beta 1 ile beraber gelen ilginç kontrollerden biri de DataGrid kontrolüdür. Aslında kontrolün kendisinde herhangi bir ilginçlik yok, ilginç olan WPF'in ilk sürümlerinde böyle bir kontrol yokken Silverlight'ın ikinci sürümünde DataGrid'in geliyor olması. Bu yazımızda Silverlight 2.0 Beta 1 ile DataGrid kullanımına deyineceğiz.

Silverlight 2.0 projenizi Visual Studio 2008 ile yarattıktan sonra hemen araç çubuğunda DataGrid kontrolü ile karşılaşabilirsiniz. Expression Blend içerisinde ise varsayılan ayarlar ile gelmeyecektir. Bunun aslında basit bir nedeni var; DataGrid gibi veri kontrolleri Silverlight 2.0 için harici bir Control Library olan System.Windows.Controls.Data altında geliyor ve bu kütüphane normal şartlarda uygulamaları referans olarak eklenmiş olmuyor. Eğer uygulamanıza bu sınıfı referans olarak eklerseniz Blend içerisinde de gerekli seçenekler gelecektir. Visual Studio içerisinde sahneye bir DataGrid yerleştirdiğinizde gerekli referanslar otomatik olarak ekleniyor.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="SilverlightApplication25.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

    Width="400" Height="300">

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

      <my:DataGrid></my:DataGrid>

    </Grid>

</UserControl>

Yukarıdaki kodu incelediğinizde herhangi bir Silverlight uygulamasına DataGrid yerleştirildiğinde en üst satırdaki XML namespace tanımını görebilirsiniz. Söz konusu tanım veri kontrollerinin Assembly'lerine bağlı. Böylece artık uygulamamızda veri kontrollerini kullanabiliriz. Bunun bir sonucu olarak artık uygulamamızdan üretilecek XAP paketinde de System.Windows.Controls.Data.dll dosyası bulunacaktır.

İlk olarak istemci tarafındaki kodumuz ile DataGrid içerisinde gösterilmek üzere bir veri yığını yaratalım. Bu noktada siz uygulamalarınızda rahatlıkla farklı web servislerinden çektiğiniz verileri kullanabilirsiniz.

[VB]

    Public Class Urun

 

        Private PAdi As String

        Public Property Adi() As String

            Get

                Return PAdi

            End Get

            Set(ByVal value As String)

                PAdi = value

            End Set

        End Property

 

 

        Private PStok As Boolean

        Public Property Stok() As Boolean

            Get

                Return PStok

            End Get

            Set(ByVal value As Boolean)

                PStok = value

            End Set

        End Property

 

        Sub New()

 

        End Sub

 

        Sub New(ByVal adi As String, ByVal stok As Boolean)

            Me.Adi = adi

            Me.Stok = stok

        End Sub

 

    End Class

[C#]

    public class Urun

    {

 

        private string PAdi;

        public string Adi

        {

            get { return PAdi; }

            set { PAdi = value; }

        }

 

 

        private bool PStok;

        public bool Stok

        {

            get { return PStok; }

            set { PStok = value; }

        }

 

        public Urun()

        {

 

        }

 

        public Urun(string adi, bool stok)

        {

            this.Adi = adi;

            this.Stok = stok;

        }

 

    }

Yukarıdaki sınıf yapısını verimizi oluştururken kullanacağımız nesneler olarak hazırladık. Silverlight 2.0'daki DataBinding WPF ile büyük bir benzerliğe sahip. Özellikle LINQ ile beraber kullanıldığında nesneleri kontrollere bind edebiliyor olmak büyük avantaj sağlıyor. Şimdi gelelim bize geçici olarak veri yaratacak olan kodumuzu yazmaya.

[VB]

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

        Dim liste As New System.Collections.Generic.List(Of Urun)

        For x As Integer = 0 To 9

            liste.Add(New Urun("Urun Adi" & x, (Math.Round(Rnd() * 1) - 1)))

        Next

        BirGrid.ItemsSource = liste

    End Sub

[C#]

        public Page()

        {

            InitializeComponent();

 

            System.Collections.Generic.List<Urun> liste = new System.Collections.Generic.List<Urun>();

            Random RastGele = new Random();

            for (int x = 0; x <= 9; x++)

            {

                liste.Add(new Urun("Urun Adi" + x.ToString(), Convert.ToBoolean(RastGele.Next(0, 1) - 1)));

            }

            BirGrid.ItemsSource = liste;

        }

Kod içerisinde de gördüğünüz gibi elimizdeki veriyi doğrudan BirGrid adındaki DataGridimizin ItemsSource özelliğine bağlıyoruz. Böylece DataBinding işlemi tamamlanmış oldu. Fakat bağladığımız bu verinin Grid içerisinde kolonlara yerleşmesi için tabi bizim "kolon"lara ihtiyacımız var. Otomatik olarak veriye uygun kolon yaratılabilmesi için DataGrid'in AutoGenerateColumns özelliğinin True olarak ayarlanmış olması gerekiyor.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="SilverlightApplication25.Page"

    xmlns="http://schemas.microsoft.com/client/2007"

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

    Width="400" Height="300">

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

    <my:DataGrid x:Name="BirGrid" AutoGenerateColumns="True"></my:DataGrid>

  </Grid>

</UserControl>

XAML kodumuzun son hali yukarıdaki gibi olmalı. Böylece uygulamamızı çalıştırdığımızda aşağıdaki manzara ile karşılaşabiliriz.

Silverlight 2.0 içerisinde DataGrid görüntüsü.
Silverlight 2.0 içerisinde DataGrid görüntüsü.

İsterseniz alternatif satırların fon renklerini hatta kolonlar arası çizgilerin renklerini bile tek tek belirleyebilirsiniz. Aşağıdaki kod yapabileceğiniz renk değişikliklerine dair bir ipucu olabilir.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

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

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="True"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3"></my:DataGrid>

  </Grid>

</UserControl>

Kendi kolonlarımızı tanımlayalım!

Aslında AutoGenerateColumns özelliği bizim ASP.NET'teki GridView'den de alışık olduğumuz bir özellik. Kolay bir kullanım sağlasa da çoğu zaman bu özellik istediğimiz uygulamaları hazırlayabilmemiz için yeterli değil. O nedenle gelin şimdi beraber bir DataGrid içerisinde kolonları nasıl elle ayarlayabileceğimizi inceleyelim.

Eğer AutoGenerateColumns özelliğini True yapmazsanız hali hazırda varsayılan ayarı zaten False olarak geliyor. O nedenle bir önceki projemize devam edeceğimiz için ilk olarak ya AutoGenerateColumns özelliğini XAML kodunuzdan silin ya da False olarak ayarlayın.

Bir DataGrid'in üç çeşit kolonu olabilir;

  • DataGridTextBoxColumn
  • DataGridCheckBoxColumn
  •  DataGridTemplateColumn

Adlarından da anlaşılacağı üzere ikisi kendi isimlerindeki kontrolleri kolonlara yerleştirirken TemplateColumn ise bize daha esnek bir yapı sağlıyor. İlk olarak gelin TextBoxColumn ve CheckBoxColumn kullanarak bir önceki adımdaki örneğimizin kolonlarını elle tanımlayalım.

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="False"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3">

      <my:DataGrid.Columns>

        <my:DataGridTextBoxColumn Header="Adi"

                                  DisplayMemberBinding="{Binding Adi}" />

        <my:DataGridCheckBoxColumn Header="Stokta Var?"

                                  DisplayMemberBinding="{Binding Stok}" />

 

      </my:DataGrid.Columns>

    </my:DataGrid>

Kolonlarımızı ekledikten sonra her kolonun Header özelliğini değiştirerek o kolonda gözükecek olan başlığı ayarlayabiliyoruz. Son olarak da veri kaynağından hangi Property'nin söz konusu kolonda gözükeceğini belirlemek için bir Binding kullanıyoruz. Görsel olarak sonuç bir önceki örneğimizdeki ile aynı olacak fakat bu sefer kolonları biz el ile tek tek ayarlamış olduk. Bunun getireceği esnekliği özellikle TemplateColumn ile çok daha rahat görebiliriz.

Özel kolonlar : TemplateColumn

Özel bir kolon tanımlarken yapmamız gereken iki şey var; ilk olarak kolonun normal görüntüsünü tanımlamak, ikincisi ise "edit" modundaki görüntüsünü tanımlamak. Eğer ReadOnly özelliklerini değiştirmezseniz normal şartlarda hem TextBoxColumn hem de CheckBoxColumn üzerlerine tıklandıklarında içlerindeki verinin değiştirilebilmesine olanak tanırlar. Hatta Binding Mode olarak da TwoWay parametresini aktarırsanız arka planda Bind ettiğiniz List içerisinde gerekli değişiklikler de otomatik olarak yapılır. Şimdi biz tüm bunları bir TemplateColumn ile deneyeceğiz. Amacımız Stok bilgisi gösteren kolonu biraz değiştirerek normalde içerisinde True veya False yazmasını sağlamak. Yani normal şartlarda o kolonda bir CheckBox gözükmeyecek, fakat kullanıcına kolona çift tıklar ve değeri değiştirmek isterse karşınızda bu sefer bir CheckBox gelecek.

        <my:DataGridTemplateColumn Header="Stokta Var?">

          <my:DataGridTemplateColumn.CellTemplate>

            <DataTemplate>

              <TextBlock Text="{Binding Stok}"/>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellTemplate>

          <my:DataGridTemplateColumn.CellEditingTemplate>

            <DataTemplate>

              <CheckBox IsChecked="{Binding Stok, Mode=TwoWay}"></CheckBox>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellEditingTemplate>

        </my:DataGridTemplateColumn>

Yukarıdaki kodu detaylı olarak incelemekte fayda var. Yarattığımız TemplateColumn'un içerisinde bir CellTemplate, bir de CellEditingTemplate var. Bu kolonun normal şartlardaki görüntüsü CellTemplate, düzenleme modundaki görüntüsü ise CellEditingTemplate içerisindeki şablona göre hazırlanacak. CellTemplate içerisinde DataTemplate içinde sadece bir TextBlock koyuyoruz ve söz konusu TextBlock'un da Text özelliğini Stok bilgisini bind ediyoruz. Böylece normalde Stok bilgisi String olarak bu TextBlock içerisinde gösterilecek. Gelelim CellEditingTemplate şablonunda; bu şablon içerisinde de bir CheckBox kullanarak söz konusu CheckBox'un IsChecked özelliğini Stok Property'sine Bind ederken Mode olarak da TwoWay'i seçiyoruz. Böylece bu CheckBox üzerinde yapılan değişiklikler elimizdeki List verimize yansıyacak, yani kaydedilecek.

Uygulamamızın tam XAML kodunu aşağıda inceleyebilirsiniz.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

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

            Width="400"

            Height="300">

  <Grid x:Name="LayoutRoot"

        Background="White">

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="False"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3">

      <my:DataGrid.Columns>

        <my:DataGridTextBoxColumn Header="Adi"

                                  DisplayMemberBinding="{Binding Adi}" />

        <my:DataGridCheckBoxColumn Header="Stokta Var?"

                                  DisplayMemberBinding="{Binding Stok}" />

        <my:DataGridTemplateColumn Header="Stokta Var?">

          <my:DataGridTemplateColumn.CellTemplate>

            <DataTemplate>

              <TextBlock Text="{Binding Stok}"/>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellTemplate>

          <my:DataGridTemplateColumn.CellEditingTemplate>

            <DataTemplate>

              <CheckBox IsChecked="{Binding Stok, Mode=TwoWay}"></CheckBox>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellEditingTemplate>

        </my:DataGridTemplateColumn>

      </my:DataGrid.Columns>

    </my:DataGrid>

  </Grid>

</UserControl>

IValueConverter ile Binding'lere müdahale edin

Bir önceki örnek biraz saçma gelmiş olabilir. Kolon içerisinde doğrudan True veya False yazıyor olmak pek hoş değil. Stok bilgisinden bahsettiğimize göre True veya Flase yerine "Var" veya "Yok" yazdırsak belki çok daha mantıklı olabilirdi. Kullanıcı satıra tıkladığında ise yine karşısına düzenleme modunda bir CheckBox gelecektir. Bu işlemi yapabilmemiz için bizim CellTemplate içerisindeki TextBlock'un Binding'ine müdahale ederek "Eğer True geliyorsa VAR yazdır, gelmiyorsa YOK yazdır" diyebilmemiz gerekiyor. İşte tam da bu işlemi yapabilmek için Silverlight 2.0 Beta 1 içerisinde ValueConverter yapılarını kullanabiliyoruz.

[VB]

Public Class StokCevirici

    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

        If value Then

            Return "Var"

        Else

            Return "Yok"

        End If

    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

        If value = "Var" Then

            Return True

        Else

            Return False

        End If

    End Function

End Class

[C#]

    public class StokCevirici : System.Windows.Data.IValueConverter

    {

 

        object System.Windows.Data.IValueConverter.Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            if (bool.Parse(value.ToString()))

            {

                return "Var";

            }

            else

            {

                return "Yok";

            }

        }

 

        object System.Windows.Data.IValueConverter.ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)

        {

            if (value.ToString() == "Var")

            {

                return true;

            }

            else

            {

                return false;

            }

        }

    }

İlk olarak yukarıdaki şekilde System.Windows.Data.IValueConverter sınıfını implemente etmemiz gerekiyor. Bu şekilde bir Converter yapısının her zaman bir Convert ve bir de ConvertBack metodlarının bulunması şart. Bu metodlar aslında bizim elimizdeki True veya False olan Boolean değerinin String'e çevireceğimiz ve Binding için DataGrid'e göndereceğimiz veriyi oluşturmamıza olanak tanıyorlar. Kod içerisinde de duruma göre parametre olarak gelen Boolean değeri String'e veya tam tersine işlemler yapıyoruz. Sıra geldi bu Converter yapısını XAML kodumuzda kullanarak Binding işlemine dahil etmeye.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

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

            xmlns:local="clr-namespace:SilverlightApplication25"

            Width="400"

            Height="300">

İlk olarak yukarıdaki şekilde XAML içerisinde kullanacağımız Assembly'mizi tanımlıyoruz. Böylece Converter sınıfımızı rahatlıkla kullanabileceğiz. Fakat işlemler bu kadarla bitmiyor. Tanımladığımız Assembly içerisinde Convertor'ımızı da alarak sayfada Resource olarak yerleştirmemiz şart.

  <UserControl.Resources>

    <local:StokCevirici x:Key="StokCevirici" />

  </UserControl.Resources>

Tüm bu işlemlerde Visual Studio'nun Intellisense yapısı size yardımcı olacaktır. Artık XAML tarafında StokCevirici adını verdiğimiz Converter yapımızı istediğimiz bir Binding için kullanmaya hazırız.

<UserControl xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

            x:Class="SilverlightApplication25.Page"

            xmlns="http://schemas.microsoft.com/client/2007"

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

            xmlns:local="clr-namespace:SilverlightApplication25"

            Width="400"

            Height="300">

  <UserControl.Resources>

    <local:StokCevirici x:Key="StokCevirici" />

  </UserControl.Resources>

  <Grid x:Name="LayoutRoot"

        Background="White">

    <my:DataGrid x:Name="BirGrid"

                AutoGenerateColumns="False"

                AlternatingRowBackground="#FFFFFF00"

                HorizontalGridlinesBrush="#FFD4FF00"

                RowBackground="#FFE3E3E3">

      <my:DataGrid.Columns>

        <my:DataGridTextBoxColumn Header="Adi"

                                  DisplayMemberBinding="{Binding Adi}" />

        <my:DataGridCheckBoxColumn Header="Stokta Var?"

                                  DisplayMemberBinding="{Binding Stok}" />

        <my:DataGridTemplateColumn Header="Stokta Var?">

          <my:DataGridTemplateColumn.CellTemplate>

            <DataTemplate>

              <TextBlock Text="{Binding Stok, Converter={StaticResource StokCevirici}}" />

            </DataTemplate>

          </my:DataGridTemplateColumn.CellTemplate>

          <my:DataGridTemplateColumn.CellEditingTemplate>

            <DataTemplate>

              <CheckBox IsChecked="{Binding Stok, Mode=TwoWay}"></CheckBox>

            </DataTemplate>

          </my:DataGridTemplateColumn.CellEditingTemplate>

        </my:DataGridTemplateColumn>

 

      </my:DataGrid.Columns>

    </my:DataGrid>

  </Grid>

</UserControl>

Uygulamanın son halinin tam kodunu yukarıdaki inceleyebilirsiniz. Özellikle yarattığımız Converter'ın kullanım şekline dikkat etmekte fayda var. Artık TextBlock içerisinde gösterilen veriler söz konusu Converter'dan geçtikten sonra gösterileceği için ekranda "Var" veya "Yok" yazıları yer alacak. Oysa kullanıcı çift tıklayarak değeri değiştirmek istediğinde karşısına bir CheckBox çıkacak ve True veya False olabilecek Boolean değeri değiştiriyor olacak.

Hepinize kolay gelsin.