Makale Özeti

Bu yazımızda Expression Blend ile data binding yapılarına giriş yaparken yazılımcılar tarafında da Blend uyumlu ara katmanların oluşturulmasına göz atıyoruz.

Makale

İster Silverlight tarafında olsun ister WPF teknolojinin ve araçların sürekli bahsedilen en önemli özelliklerinden biri tasarımcı ile yazılımcı arasındaki ilişkiyi düzenlediği yönünde. Tabi ki eskisine kıyasla çok sayıda artı özellik bu iki profil arasındaki "kavgaların" azalmasını sağlıyor fakat diğer yandan özellikle yazılımcının da Expression Blend uyumlu binding yapılabilir nesnelerini tanımlayabiliyor olması çok önemli. Tabi aynı derecede bir tasarımcının da Blend içerisinden yola çıkarak programcının arka planda kendisine sağladığı CLR nesnelerine ulaşabilmesi şart.

Tüm bu senaryo ile ilgili ufak bir örnek yapacağımız bu yazımızda ilk olarak bir programcı olarak tasarımcının uygulama tasarımında istediği gibi işlevsellikleri ayarlayabileceği ve binding'leri set ederek hangi datanın nerede gözükeceğine karar verebileceği bir altyapı oluşturacağız. Sonrasonda tasarımcı profili ile Expression Blend'e geçerek arka tarafta programcının hazırlamış olduğu nesneleri alıp uygulama arayüzünde istediğimiz yerlere yerleştireceğiz.

Visual Studio tarafından başlayalım!

Varsayalım ki elinizde bir Insan listesi var ve bunu bir şekilde tasarımcının ellerine aktarmak istiyorsunuz. Sizin bir programcı olarak yapmanız gereken bu listeyi bir veri kaynağından alıp (bu ister SQL ister başka bir kaynak olabilir) Expression Blend tarafında kullanılabilir hale getirmek. Yani verinizin User Interface tarafında kullanılabilmesini sağlamanız gerekiyor. İlk olarak gelin basit bir şekilde Insan nesnemizi tanımlayalım.

[VB]

Public Class Insan

 

    Private _Soyadi As String

    Public Property Soyadi() As String

        Get

            Return _Soyadi

        End Get

        Set(ByVal value As String)

            _Soyadi = value

        End Set

    End Property

 

 

    Private _Adi As String

    Public Property Adi() As String

        Get

            Return _Adi

        End Get

        Set(ByVal value As String)

            _Adi = value

        End Set

    End Property

 

End Class

Gördüğünüz gibi nesnemizin şimdilik iki basit özelliği var. Amacımız bu nesneden birden çok sayıda yaratıp bir liste olarak tasarımcıya aktarmak. Bunun için ayrı bir sınıf tanımlamamız uygun olur. Söz konusu sınıf içerisinde de ObservableCollection dönecek bir metod yer alacak.

[VB]

Public Class AllData

 

    Private _All As New System.Collections.ObjectModel.ObservableCollection(Of Insan)

    Public Property All() As System.Collections.ObjectModel.ObservableCollection(Of Insan)

        Get

            Return _All

        End Get

        Set(ByVal value As System.Collections.ObjectModel.ObservableCollection(Of Insan))

            _All = value

        End Set

    End Property

 

    Sub New()

        _All.Add(New Insan() With {.Adi = "1asdasd", .Soyadi = "2222"})

        _All.Add(New Insan() With {.Adi = "2asdasd", .Soyadi = "4222"})

        _All.Add(New Insan() With {.Adi = "3asdasd", .Soyadi = "5222"})

        _All.Add(New Insan() With {.Adi = "4asdasd", .Soyadi = "6222"})

    End Sub

 

End Class

AllData adındaki bu sınıfın içerisinde All adında da bir Property var. Bu property geriye bir ObservableCollection döndürüyor. Bildiğiniz üzere ObservableCollection'lar TwoWay binding destekleyen collection nesneleridir. Yani görsel arayüzdeki değer değişiklikleri de otomatik olarak arka plandaki nesneye yansır. Expression Blend'de bu nesne bind edildiğinde Blend nesneyi çağırmadan önce bir Instance yani kopyasını alacaktır. İşte tam da bu kopyayı yaratırken sınıfımızın constructor'ında datamızı ObservableCollection'ımıza ekleyebiliriz. Kod yönetimi açısından tüm bu kodları harici bir VB veya C# dosyasında yazmanızda fayda var.

İşimiz bu kadar artık bu veriyi gösterme işi tasarımcının işi. Expression Blend tarafına geçerek geri kalanı bir tasarımcı profili ile yapalım.

Expression Blend tarafına geçiyoruz!

Aynı projeyi Expression Blend ile açtıktan sonra sağ barda "Data" tabını bulabilirsiniz. Data tabında "Add Live Data Source" komutunu verdikten sonra "Define New Object Data Source" diyebilirsiniz.

Expression Blend içerisinde Data Source'umuzu tanımlıyoruz.
Expression Blend içerisinde Data Source'umuzu tanımlıyoruz.

Karşınızda çıkacak ekranda AllData adındaki sınıfımızı seçmeniz yeni DataSource'u yaratmanız için yeterli olacaktır. Artık sıra geldi bu DataSource içerisinde hangi Property'yi nasıl kullanacağınıza.

Nesnelerimiz Expression Blend tarafından algılandı.
Nesnelerimiz Expression Blend tarafından algılandı.

Artık Data tabındaki veri kaynağı ile ilgili tüm detayları görebiliriz. Tasarımcı olarak Data tabından veriyi sahneye koymak için birkaç yolumuz var. Bunlardan ilki liste görünüşünü kullanmak. Şu an yukarıdaki ekran görüntüsünde List Mode gözüküyor. Bu durumda ObservableCollection'ı alıp sahneye bıraktığınızda otomatik olarak bir ListBox yaratılacak ve veri ListBox'a bağlanacaktır.

Sürükle, bırak! Ve karşında ListBox!
Sürükle, bırak! Ve karşında ListBox!

Artık bu ListBox'ın ItemTemplate'inin vs tasarımını değiştirmek tabi ki makalemizin sınırları dışında. Fakat unutmamak gerek ki artık canlı veriye bağlı ve tamamiyle tasarımı özelleştirilebilir bir ListBox tasarımcımızın ellerinde. Ayrıca tek seçenek ListBox da değil. Eğer sahnede bir Grid veya başka bir kontrol olsaydı doğrudan Collection'ı onun üzerine sürükleyip bırakarak da Data Binding işlemi rahatlıkla yapılabilirdi.

Details Mode karşınızda.
Details Mode karşınızda.

List Mode'un yanı sıra Blend içerisinde kullanabileceğimiz bir diğer Data modu da Details Mode olarak karşımıza çıkıyor. Bu moddayken veri kaynağından nesneleri ancak Property'ler olarak sürükleyip bırakabilirsiniz çünkü artık amacınız bir liste göstermek değil. Artık amacımız nesnelerin detaylarınız göstermek. Tek tek her Property'yi sahnedek ayrı nesnelere Bind edebileceğiniz gibi nesnelerin yaratılmasını Blend'e de bırakabilirsiniz. Örneğin gelin hem Adi hem de Soyadi Property'lerini seçerek sahneye sürükleyip bırakalım.

Details Mode ile otomatik detay görünümü yaratabilirsiniz.
Details Mode ile otomatik detay görünümü yaratabilirsiniz.

Gördüğünüz gibi sürükle bırak sonrasında otomatik olarak bir Grid yaratılarak içerisinde hem Property isimlerini taşıyan hem de değerleri taşıyan birer TextBlock yerleştirildi. İşin en güzel tarafı binding işlemini aynı nesne kopyasına yaptığımız için ListBox içerisinde hangi nesne seçilirse onun detaylarının bu Grid içerisinde gösterilecek olması. Yani tüm işlevsellik tamamlanmış durumda!

Arka planda Blend neler yaptı?

Blend aslında basit bir şekilde Binding mekanizmalarının tasarımcılar tarafında rahatlıkla kullanılabilmesini sağlıyor. Maalesef şu an için bu mekanizmaları yazılımcılar olarak bizim elle yazmaktan başka şansımız ki. Visual Studio 2010 ile bu durumda toparlanacak ve bizler de tüm bu ayarları yapabileceğimiz menülere sahip olacağız.

XAML tarafına bir göz atacak olursak dikkatimizi çeken birkaç nokta olabilir.

[XAML]

<UserControl

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

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

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   mc:Ignorable="d" xmlns:local="clr-namespace:SilverlightApplication2" xmlns:dataFormToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit" x:Class="SilverlightApplication2.MainPage"

   d:DesignWidth="640" d:DesignHeight="480">

    <UserControl.Resources>

        <local:AllData x:Key="AllDataDataSource" d:IsDataSource="True"/>

        <DataTemplate x:Key="InsanTemplate">

            <StackPanel>

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

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

            </StackPanel>

        </DataTemplate>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource AllDataDataSource}}" >

        <ListBox x:Name="listBox" Margin="47,96,0,84" ItemTemplate="{StaticResource InsanTemplate}" ItemsSource="{Binding All}" HorizontalAlignment="Left" Width="200"/>

        <Grid DataContext="{Binding SelectedItem, ElementName=listBox}" Margin="310,94,76,186" d:DataContext="{Binding All[0]}" Background="White">

            <TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="16" Text="Adi"/>

            <TextBlock Text="{Binding Adi}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="150" Height="16" Margin="104,0,0,0"/>

            <TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="16" Margin="0,20,0,0" Text="Soyadi"/>

            <TextBlock Text="{Binding Soyadi}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="150" Height="16" Margin="104,20,0,0"/>

        </Grid>

    </Grid>

</UserControl>

Yukarıda tüm uygulamanın XAML kodunu inceleyebilirsiniz. Özellikle renkli kısımlara bakacak olursak Blend'in neler yapmaya çalıştığını net bir şekilde görebiliriz. İlk olarak en üstte bizim arkadaki uygulamamızın bir XML namespace olarak Import edilmiş. Sonra söz konusu yerden AllData sınıfından bir instance alınıp Resrouce'lar arasına AllDataDataSource adı ile koyulmuş. Bu DataSource uygulama genelinde Grid'e bağlanmış. Grid içerisinde ListBox ise All metoduna bağlanmış. ListBox aldığı her Insan nesnesini yine Resource'lar içerisinde tanımlı InstanTemplate ile gösterebiliyor. InsanTemplate içerisinde ise her Insan'ın Property'leri uygun kontrollere bağlanmış durumda. Son olarak detayları gösterecek olan nesnelerin bulunduğu Grid'in DataContext'i bizim ListBox'ın SelectedItem'ına element binding ile bağlanmış. SelectedItem zaten bir Insan nesnesi olarak geleceğine göre Grid içerisindeki kontrolleri de doğrudan bu Insan nesnesinin Property'lerine bağlayabiliriz. Son ufak bir detay ise Grid'in DataContext'inin yanı sıra bir de d:DataContext diye bir Property'sinin All listesindeki Index numarası sıfır olan kayda bind edilmiş olması. d: XML namespace'i tamamen design view için gerekli özellikleri tanımlar. Yani tasarımcı Blend içerisinde uygulamayı görürken ve uygulama çalışmazken bu Grid'in doğrudan All listesindeki ilk nesneyi göstermesini sağlamak için Blend böyle bir kod eklemiş durumda.

Sonuç olarak gördüğünüz gibi aslında her iki tarafın da kurallara uyması halinde Expression Blend ve Visual Studio ile beraber tasarımcılar ve yazılımcıların beraber rahatça çalışması olması.

Hepinize kolay gelsin.