Silverlight 5 Beta'da Ancestor Relative Binding

0 dakikada yazıldı

12653 defa okundu

Düzenle

Geldik bir başka Silverlight 5 yeniliğine... WPF'ten bilenler yazıyı
okuyarak işkence çekmesinler diye hemen söyleyelim Ancestor Relative
Binding zaten WPF'te vardı. Silverlight 5 ile SL dünyasına da geliyor.
Eğer WPF tarafından biliyorsanız zaten sorun yok.

Ancestor Relative Binding herhangi bir Binding işleminin nesnenin üst
nesnelerine doğru yönlendirilebilmesini sağlıyor. Yani düşünün ki
ListBox içerisindeki ItemTemplate'i değiştirdiniz fakat her ItemTemplate
içerisinde bir kontrolün de gidip ListBox'dan birşey alması gerek, işte
bu durumda Ancestor Binding işinizi kolaylaştırabiliyor. Özellikle
Ancestor yani üst nesnelerin Runtime tarafından automated yaratıldığı
senaryolarda bu nesnelerin propertylerine ulaşıp binding yapabiliyor
olmak çok keyifli olabiliyor.

Değişik hareketler yapalım....

Aslında pek de değişik olmayacak :) yapacağımzı hareket çok basit bir
hareket olacak. Şimdi diyelim ki bir DataGrid var elimizde ve
hücrelerinden birinde de veya bir kolonunda da custom bir
UserControl'ümüz var. Bu UserControl duruma göre DataGrid içerisinde
bulunduğu satırın fon rengini değiştirebilmek istiyor. Günün sorusu
geliyor : Bunu nasıl yaparız?

Aklınıza birçok çözüm gelebilir. Hatta düşündüklerinizi hemen yorum
olarak bu yazıya atabilirseniz belki ilginç şeyler de çıkabilir. Benim
aklıma ilk gelen DataGrid'in stilleri ile oynayıp stilleri override
ederek stillerdeki bir özelliği binding aracalığı ile bir şekilde bizim
kontrole kadar getirmek oldu. Fakat bu iş hiç de kolay olmayacak. Oysa
:) Ancestor Relative Binding ile olay çok basit bir şekilde çözülebilir.

DataGrid içerisindeki her ColumnDefinition DataTemplate'i çalışma
zamanında önce bir CellPresenter, sonra da CellsPresenter içerisine
alınır. Bunu biz XAML içerisinde görmeyiz fakat on-thy-fly check
ettiğimizde bu kontrolleri yakalayabiliriz. Tahmin edebileceğiniz üzere
CellPresenter içerisinde bulunduğumuz hücreyi içerirken CellsPresenter
ise birden çok CellPresenter içerir. Bizim de aslında satırın fon
rengini değiştirmek için yapmamız gereken CellsPresenter'ın fon rengini
değiştirmek olacak.

Gördüğünüz üzere ulaşmak istediğimiz kontrol runtime'da yaratılıyor ve
aslında bizim DataTemplate içerisindeki kontrolümüzün çok üstünde. İşte
tam da Ancestor Binding kullanmanın zamanı.

[XAML]

        <sdk:DataGrid AutoGenerateColumns="true" Height="186" HorizontalAlignment="Left" 
                    Margin
="12,12,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="376" >
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                               
<
Button Click="Button_Click" Tag="{Binding ???Nasıl bir
binding olacak burada????}"
  />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>

Bir Ancestor Binding'in iki özelliği var. Bunlardan ilki
AncestorType; yani Binding işleminin yapılabilmesi için aranan
nesnenin tipi. Bizim senaryomuzda elimizde DataTemplate içerisinde
bulunan basit Button kontrolünün Tag Property'sini bind eceğiz satırın
fon rengine. O nedenle yukarıya doğru arama yaparaken bulmamız gereken
nesnenin tipi DataGridCellsPresenter olacak. Bu nesne tipini XAML
içerisinde tanımlayabilmek için bir XMLNS tanımlayacağız.

[XAML]

\\     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"\     xmlns:Primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"\     mc:Ignorable="d"\     d:DesignHeight="300" d:DesignWidth="400" \     xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"\>

Hedef tipimizi ayarladığımızda göre karar vermemiz gereken ikinci şey
ise hedef nesnenin hangi Property'sini Button'un Tag'ına bind
edeceğimiz. Satırın fon rengini değiştirmek istediğimize göre binding
Path'imiz de Background olacak. Artık iki parametremiz de hazır.
Button'dan yola çıkarak yukarı doğru gezip ilk
DataGridCellsPresenter'ı bulup Background property'sini bizim
Tag Property'sine bind etmemiz gerek.

[XAML]

<Button Click="Button_Click" 
  Tag="{Binding RelativeSource={RelativeSource AncestorType=Primitives:DataGridCellsPresenter}, 
  Path
=Background, Mode=TwoWay}"  />

Yukarıda gördüğünüz Binding Syntax'ı Ancestor Relative Binding
olarak adlandırılıyor. RelativeSource özelliğini set ettiğimiz
Binding kendisine verilen AncestorType'a göre tüm üst elementleri
arayarak ilk karşılaştığının Path özelliği ile binding işlemini
gerçekleştiriyor. Örnekte UserControl yerine ben basit bir Button
kullanıp Click eventini de code behind'da bir methoda bağladım. Click
eventinde basit bir şekilde Button'un Tag'ine atadığım SolidColorBrush
binding sayesinde otomatik olarak DataGridCellsPresenter'ı
Background 'una atanmış oluyor.

[C#]

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button S = sender as Button;
            S.Tag = new SolidColorBrush(Colors.Red );
        }

Button yerine custom bir UserControl kullandığınızda kendi Custom
Property'leriniz ile de bu işi yapabilirsiniz. Ancestor Relative Binding
çoğu farkı mekanizması kolaylaştırabilir ve yaptığınız çoğu şey daha
kolay yapmanızı sağlayabilir. Artık Silverilght 5 Beta ile aklımızda
bulundurmamız gereken bir seçenek olarak kenara kaydetmek gerek ;)

Hepinize kolay gelsin.