22.05.2012

Silverlight 2.0 Beta 1 içerisinde DataGrid Kullanımı


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 ileDataGrid 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 StringByVal 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 ObjectByVal 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öyleceDataBinding 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 Stokbilgisi gösteren kolonu biraz değiştirerek normalde içerisinde True veya False yazmasını sağlamak. Yani normal şartlarda o kolonda bir CheckBoxgö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 CellEditingTemplatevar. 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 Stokbilgisini 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 daTwoWay'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 ObjectByVal targetType As System.Type, ByVal parameter As ObjectByVal culture AsSystem.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 ObjectByVal targetType As System.Type, ByVal parameter As ObjectByVal culture AsSystem.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 Booleandeğ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 Converteryapı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ıkTextBlock 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.

Hiç yorum yok:

Yorum Gönder