Silverlight 5 Beta'da Implicit Data Templates

0 dakikada yazıldı

10903 defa okundu

Düzenle

Silverlight 5 Beta ile beraber gelen yeni özelliklerden biri de Implicit
Data Templates. Özelliğin güzelliğine gelmeden önce :) biraz elimizde
neler var ona bakalım.

Malum ListBox gibi kontrollerin ItemTemplate'ini
özelleştirebiliyoruz. ItemTemplate kabaca kontrol içerisinde
kontrole vereceğimiz nesne listesindeki her nesneyi görsel olarak temsil
edecek olan görsel tasarımı tanımlıyor.

[XAML]

     <ListBox x:Name="list_Mesajlar" HorizontalAlignment="Left" Margin="24,18,0,17" 
    Width
="131" ItemTemplate="{StaticResource DataTemplate1}"/>

ItemTemplate editleme işlemini Expression Blend ile yaparsak Blend
otomatik olarak bir DataTemplate'i kontrolün Resources kolleksiyonuna
koyarak DataTemplate'e verdiğimiz ismi direk ListBox'ın ItemTemplate
özelliğine atıyor.

[XAML]

<DataTemplate x:Key="DataTemplate1">
  <StackPanel d:DesignWidth="318" d:DesignHeight="108">
    <StackPanel Orientation="Horizontal">
      <TextBlock TextWrapping="Wrap" Text="Gönderen:" Foreground="#FF3F3F3F"/>
      <TextBlock TextWrapping="Wrap" Text="{Binding GonderenAdi}"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
      <TextBlock TextWrapping="Wrap" Text="Alan:" Foreground="#FF3F3F3F"/>
      <TextBlock TextWrapping="Wrap" Text="{Binding AlanAdi}"/>
    </StackPanel>
    <TextBlock TextWrapping="Wrap" Text="Mesaj:" Foreground="#FF3F3F3F"/>
    <TextBlock TextWrapping="Wrap" Text="{Binding Metin}"/>
  </StackPanel>
</DataTemplate>

Yukarıdaki gördüğünüz basit bir DataTemplate. Tahmin edebileceğiniz
üzere AlanAdi, GonderenAdi ve Metin gibi Property'leri ile
nesnelerden oluşan bir kolleksiyonu göstermek için yaratılmış durumda.
Şimdi bir de kod tarafına göz atalım.

[C#]

        public class Mesaj
        {
            public string Metin { getset; }
        }
        public class Mail : Mesaj 
        {
            public string GonderenMail { getset; }
            public string GonderenAdi { getset; }
            public string AlanMail { getset; }
            public string AlanAdi { getset; }
        }
        public class SMS : Mesaj 
        {
            public string GonderenNumara { getset; }
            public string AlanNumara { getset; }
        }

Kodumuz içerisinde iki tip mesajımız var. SMS ve Mail adındaki bu mesaj
tipindeki nesneler Mesaj adında bir başka nesneden türetilmiştir. Bizim
istediğimiz ise tüm bu nesneleri alıp topluca ListBox'da gösterebilmek
ve duruma göre de eğer elde Mail varsa farklı bir DataTemplate,
SMS varsa farklı bir tasarım kullanmak.

Karşınızda Implicit Data Templates

Biraz önce karşılaştığımız sorunu çözebilmek için Implicit Data Template
kullanmamız şart. Peki nasıl olacak? İlk olarak elimizdeki Mesaj
listesini gönül rahatlığı ile ListBox'ın ItemsSource'una vereceğiz.
Listemizde Mail ve SMS'ler karşılık olarak duracaklar. Herhangi bir
sorun yok. DataTemplate'ler konusuna gelince ise ilk olarak Key ile
DataTemplate'i ListBox'a bağlamaktan vazgeçeceğiz. Sonra ise her
DataTemplate'e hangi tür veriyi göstereceklerine dair gerekli bilgiyi
vermemiz gerekecek.

[XAML]

<UserControl.Resources>
  <DataTemplate** DataType="daron:Mesaj">
    <StackPanel d:DesignWidth="318" d:DesignHeight="108">
      <StackPanel Orientation="Horizontal">
        <TextBlock TextWrapping="Wrap" Text="Gönderen:" Foreground="#FF3F3F3F"/>
        <TextBlock TextWrapping="Wrap" Text="{Binding GonderenAdi}"/>
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <TextBlock TextWrapping="Wrap" Text="Alan:" Foreground="#FF3F3F3F"/>
        <TextBlock TextWrapping="Wrap" Text="{Binding AlanAdi}"/>
      </StackPanel>
      <TextBlock TextWrapping="Wrap" Text="Mesaj:" Foreground="#FF3F3F3F"/>
      <TextBlock TextWrapping="Wrap" Text="{Binding Metin}"/>
    </StackPanel>
  </DataTemplate>
  <DataTemplate DataType
=**"daron:SMS">
    <StackPanel d:DesignWidth="318" d:DesignHeight="108">
      <StackPanel Orientation="Horizontal">
        <TextBlock TextWrapping="Wrap" Text="Gönderen:" Foreground="#FF3F3F3F"/>
        <TextBlock TextWrapping="Wrap" Text="{Binding GonderenNumara}"/>
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <TextBlock TextWrapping="Wrap" Text="Alan:" Foreground="#FF3F3F3F"/>
        <TextBlock TextWrapping="Wrap" Text="{Binding AlanNumara}"/>
      </StackPanel>
      <TextBlock TextWrapping="Wrap" Text="Mesaj:" Foreground="#FF3F3F3F"/>
      <TextBlock TextWrapping="Wrap" Text="{Binding Metin}"/>
    </StackPanel>
  </DataTemplate>
</UserControl.Resources>

Yukarıda iki farklı DataTemplate görüyorsunuz. DataType özelliklerinden
de anlayabileceğiniz bu arkadaşlar iki farklı nesne tipini
hedefliyorlar. Bu arada tabi C# kodunda tanımladığım nesneleri XAML'a
alabilmek için XML NameSpace tanımımızı da koymayı unutmamalıyı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:daron="clr-namespace:SilverlightApplication10"\     mc:Ignorable="d"\     d:DesignHeight="300" d:DesignWidth="400"\>

Bu şekli ile örneği çalıştırdığınızda ListBox'a verdiğiniz farklı
mesajlardan, yani SMS ve Mail'lerden oluşan listenin başarılı bir
şekilde ListBox tarafından gösterildiğini göreceksiniz. Listedeki her
SMS için uygun SMS'lere bağladığımız DataTemplate her Mail için de Mail
nesnesi ile eşleştirdiğimiz DataTemplate kullanılıyor olacak.

Sorun olabilir!

Diyelim ki aynı UserControl içerisinde bir de Combobox var ve şansa
bakın ki Combobox'da Mail veya SMS tipinde nesneler gösteriyor :) İşte
dağıldığımız noktadır :) DataTemplate'ler ayrı ayrı isimlerle ListBox'a
bağlamadığımız ve bir anlamda ortada bıraktığımız için Combobox da aynı
DataTemplate'leri kullanacak.

Ortalık karışmış gibi duruyor...
Ortalık karışmış gibi duruyor...

Bu durumu engellemenin yolu DataTemplate'leri doğrudan ListBox'ın içine
gömmek. Böylece bu DataTemplate'ler sadece o ListBox için geçerli
olacaktır.

[XAML]

        <ListBox x:Name="list_Mesajlar" 
                 Margin="24,18,119,17">
     **       <ListBox.Resources>
                <DataTemplate DataType="daron:Mesaj">
                    <StackPanel d:DesignWidth="318" d:DesignHeight="108">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock TextWrapping="Wrap" Text="Gönderen:" Foreground="#FF3F3F3F"/>
                            <TextBlock TextWrapping="Wrap" Text="{Binding GonderenAdi}"/>
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock TextWrapping="Wrap" Text="Alan:" Foreground="#FF3F3F3F"/>
                            <TextBlock TextWrapping="Wrap" Text="{Binding AlanAdi}"/>
                        </StackPanel>
                        <TextBlock TextWrapping="Wrap" Text="Mesaj:" Foreground="#FF3F3F3F"/>
                        <TextBlock TextWrapping="Wrap" Text="{Binding Metin}"/>
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="daron:SMS">
                    <StackPanel d:DesignWidth="318" d:DesignHeight="108">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock TextWrapping="Wrap" Text="Gönderen:" Foreground="#FF3F3F3F"/>
                            <TextBlock TextWrapping="Wrap" Text="{Binding GonderenNumara}"/>
                        </StackPanel>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock TextWrapping="Wrap" Text="Alan:" Foreground="#FF3F3F3F"/>
                            <TextBlock TextWrapping="Wrap" Text="{Binding AlanNumara}"/>
                        </StackPanel>
                        <TextBlock TextWrapping="Wrap" Text="Mesaj:" Foreground="#FF3F3F3F"/>
                        <TextBlock TextWrapping="Wrap" Text="{Binding Metin}"/>
                    </StackPanel>
                </DataTemplate>
        **    </
ListBox.Resources>
        </ListBox>

Normalde bir DataTemplate'i ListBox'ın içine gömmek için
Listbox.ItemTemplate diyerek bir XML elementi açar ve aslında hem
Resource'u ListBox içine koymuş hem de gerekli Property'si set etmiş
olurduk. Bu sefer birden çok DataTemplate olacağı için hepsini alıp
Resource olarak ListBox'ın içine koyuyoruz. ListBox yine her zamanki
gibi DataType'ın göre uygun Template'i seçerken ekrandaki diğer
hiçbir kontrol bu DataTemplate'lere ulaşamayacaktır.

Hepinize kolay gelsin ;)