Silverlight 2.0 içerisinde ControlTemplating ve Style yapıları.

0 dakikada yazıldı

7402 defa okundu

Düzenle

Silverlight 2.0 Beta 1 ile beraber gelen görsel özellikler
içerisinde özellikle tasarımcıların en çok beğenecekleri ve bildiğimiz
teknolojiler arasında CSS'e benzetebileceğimiz "Resource" yapısı çok
önemli bir yere sahip. WPF'de hali hazırda var olan ve Silverlight
tarafına da (ciddi farklılıklar ile) taşınan bu özellikler sayesinde
Silverlight uygulamaları içerisinde kontrollerin programatik
işlevselliklerinden bağımsız olarak görsel özellikleri ayarlanabildiği
gibi merkezi bir yönetim de sağlanabiliyor. Gelin hızlı bir örnek ile
konumuza giriş yapalım.

<UserControl
x:Class="SilverlightApplication7.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">

      <Button
HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch"
Content="Button"/>

    </Grid>

</UserControl>

İlk olarak yukarıdaki gibi yaratacağımız yeni bir Silverlight 2.0
uygulamasına basit bir Button yerleştirelim ve Button içerisinde
yazının (Content) yerine farklı birşeyler koymayı deneyelim.
Yukarıdaki kod içerisinde Content değeri doğrudan bit metne
eşitlenmiş durumda. Oysa bu değerin içerisine başka bir Silverlight
kontrolü yerleştirebiliriz.

<UserControl
x:Class="SilverlightApplication7.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">

    <Button
HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch">

      <Button.Content>

        <Image
Height="84" HorizontalAlignment="Center" 
VerticalAlignment="Center"
Width="139" Source="Dock.jpg"/>

  **    </**Button.Content>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde Button nesnesinin Content özelliğini
belirlemek için Button tagları arasında ayrıca bir Button.Content
tagları açtık.

Button.Content özelliğini değiştirilen Button nesnesi sağda.
Button.Content özelliğini değiştirilen Button nesnesi sağda.

Bu noktada Button.Content içerisinde istediğiniz Silverlight kontrolünü
yerleştirebilirsiniz fakat dikkat etmeniz gereken bir nokta var;
maalesef bu taglar arasında sadece bir Silverlight kontrolü
yerleştirilebilir. Aslında cümle olarak yanlış bir cümle oldu, daha
doğru tabiri ile Button.Content içerisinde XAML kodunun her zaman tek
bir RootElement'inin olması gerekiyor. Yani eğer bu bölgeye iki kontrol
yerleştirmek istiyorsanız kontrollerinizi bir Container Element
içerisinde gruplayarak yerleştirmek zorundasınız. Aşağıdaki örneğimizde
Container Element olarak bir StackPanel kullanacağız.

<UserControl
x:Class="SilverlightApplication7.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">

    <Button
HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch">

      <Button.Content>

        <StackPanel
Orientation="Horizontal">

          <Image
Height="84" HorizontalAlignment="Center" 
VerticalAlignment="Center"
Width="139" Source="Dock.jpg"/>

          <Image
Height="84" HorizontalAlignment="Center" 
VerticalAlignment="Center"
Width="139" Source="Dock.jpg"/>

        </StackPanel>

      </Button.Content>

    </Button>

  </Grid>

</UserControl>

Gördüğünüz gibi Root Element olarak Button.Content içerisinde bir
StackPanel kullandıktan sonra artık StackPanel içerisine istediğimiz
kadar kontrol yerleştirebiliyoruz.

Button.Content içerisinde birden çok Silverlight kontrolü.
Button.Content içerisinde birden çok Silverlight kontrolü.

Bu yapı ile farklı kontrollerinin farklı görsel özelliklerini tanımlamak
mümkün.

Bir kontrolün tüm görsel yapısını nasıl değiştiririz?

Bu noktaya kadar elimizdeki bir düğmenin içerisinde farklı Silverlight
kontrolleri yerleştirdik. Oysa söz konusu düğmenin tüm görsel yapısını
değiştirmek de isteyebilirdiniz. Örneğin bir Resim nesneninin bir Button
olarak tanımlanması mümkün müdür?

<UserControl
x:Class="SilverlightApplication7.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">

    <Button
HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch">

      <Button.Template>

**        <**ControlTemplate>

          <Image
Height="84" HorizontalAlignment="Center" 
VerticalAlignment="Center"
Width="139" Source="Dock.jpg"/>

**        </ControlTemplate>**

**      </**Button.Template>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kodumuz içerisinde bir Button nesnesinin Template özelliğini
başka bir ControlTemplate atayarak değiştiyoruz. Tanımladığımız
ControlTemplate içerisinde sadece bir adet Image nesnesi var. Böylece
artık düğmemiz sadece bir Image nesnesinden oluşacak oysa programcımız
için bu nesne hala bir Button.

Bir Button nesnesine benzemiyor değil mi? Ama öyle.
Bir Button nesnesine benzemiyor değil mi? Ama öyle.

Peki tüm bunların anlamı nedir?

Yukarıdaki iki yapıyı Button.Content ve Button.Template beraber
kullanmanız halinde istediğimiz gibi düğmeler oluşturabilirsiniz. Gelin
şimdi güzel bir dikdörtgen çizelim ve bunu yeni yarattığımız bir Button
nesnesinin Template özelliğine aktaralım.

<UserControl
x:Class="SilverlightApplication7.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">

    <Button
HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch">

      <Button.Template>

**        <ControlTemplate>**

**          <Rectangle
Stroke="#FF000000"
RadiusY="16" RadiusX="16"
Margin
="{TemplateBinding Margin}**">

            <Rectangle.Fill>

              <RadialGradientBrush>

                <GradientStop
Color="#FFFF0000"
Offset="1"/>

                <GradientStop
Color="#FFFFFFFF"
Offset="0"/>

              </RadialGradientBrush>

            </Rectangle.Fill>

      **    </Rectangle>**

**        </ControlTemplate>**

**      </**Button.Template>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde en önemli nokta Button'umuzun
ControlTemplate'i içerisindeki Rectangle nesnesinin Margin
özelliklerinin TemplateBinding ile içerisinde olduğu kontrolün
Margin özelliğine bağlanmış olması. Böylece Button nesnesi büyüdükçe
otomatik olarak ControlTemplate içerisinde tanımlanmış Rectangle da
büyüyecek. Her zaman olduğu gibi eğer ControlTemplate içerisinden birden
çok Silverlight kontrolü kullanarak görsel özellikler tanımlamak
isterseniz bir Container Element kullanmanız gerekecektir. Bizim
örneğimizde tek nesne bulunduğu için gerek olmadı.

Yeni Silverlight Button nesnemiz karşınızda!
Yeni Silverlight Button nesnemiz karşınızda!

Gördüğünüz gibi düğmemizin görsel özellikleri tamamlandı. Peki ya bu
düğmenin içerisine yazılacak olan yazı nerede? Şu anda kontrolün bu hali
ile Button.Content özelliğine farklı değerler verdiğiniz görsel
anlamda herhangi bir değişiklik görmeyeceksiniz. Çünkü kontrolün
ControlTemplate tanımı içerisinde herhangi bir şekilde Content
içeriğinin konacağı bir yer ayarlanmış değil. Yani Button.Content
içerisine konacak nesnelerin veya yazının ControlTemplate içerisinde
nereye konacağını tanımlamamız gerekiyor.

<UserControl
x:Class="SilverlightApplication7.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">

    <Button
HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch">

      <Button.Content>

        <TextBlock
VerticalAlignment="Center"
Text="TextBlock"
TextWrapping="Wrap"/>

      </Button.Content>

      <Button.Template>

        <ControlTemplate
TargetType
="Button">

          <Grid>

            <Rectangle
Stroke="#FF000000"
RadiusY="16" RadiusX="16" Margin="{TemplateBinding Margin}">

              <Rectangle.Fill>

                <RadialGradientBrush>

                  <GradientStop
Color="#FFFF0000"
Offset="1"/>

                  <GradientStop
Color="#FFFFFFFF"
Offset="0"/>

                </RadialGradientBrush>

              </Rectangle.Fill>

            </Rectangle>

            <ContentPresenter
Content
="{TemplateBinding Content}" HorizontalAlignment="Center"
VerticalAlignment="Center"/>

          </Grid>

        </ControlTemplate>

      </Button.Template>

    </Button>

  </Grid>

</UserControl>

Yukarıdaki kod içerisinde tanımladığımız Button'ın ControlTemplate'i
içerisinde bir ContentPresenter nesnesi bulunuyor. Bu
ContentPresenter'ın Content özelliği ise TemplateBinding ile ana
Button nesnesinin Content'ına bağlanmış durumda. Böylece Button'un
**Button.Content'**ı içerisindeki tüm Silverlight kontrolleri otomatik
olarak ControlTemplate içerisindeki ContentPresenter içerisine
yerleştirilmiş olacaktır. Bu noktada dikkat etmemiz gereken önemli bir
ayar var, ControlTemplate'ın TargetType'ının özel olarak ayarlanmış
olması gerekiyor, aksi halde söz konusu ControlTemplate bir Button
içerisinde bulunmasına rağmen doğru olarak çalışmıyor. Umarım Beta
sürümü sonrasında sürümlerde bu yapı düzeltilir, şu anki çalışma yapısı
pek mantıklı değil.

Button'umuzun son hali.
Button'umuzun son hali.

Peki neden doğrudan herşeyi ControlTemplate içerisine koymuyoruz?

Çok mantıklı bir soru. Çünkü bu noktaya kadar yaptığımız tüm görsel
ayarların üzerinden bir merkezi yönetim sistemi kurmak istiyoruz. Bir
önceki adımda Button nesnemizin Template özelliğini ayarlamıştık. Şimdi
sıra geldi söz konusu Template'ı birden çok kontrol tarafından
kullanılabilir hale getirmeye.

<UserControl
x:Class="SilverlightApplication7.Page"

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

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

    Width="400" Height="300">

  <UserControl.Resources>

**    <Style ****
x:Key
="Dugme" ****
TargetType
="Button">**

**      <Setter
****
Property
="Template">**

**        <**Setter.Value>

          <ControlTemplate TargetType="Button">

            <Grid>

              <Rectangle
Stroke="#FF000000"
RadiusY="16" RadiusX="16" Margin="{TemplateBinding Margin}">

                <Rectangle.Fill>

                  <RadialGradientBrush>

                    <GradientStop
Color="#FFFF0000"
Offset="1"/>

                    <GradientStop
Color="#FFFFFFFF"
Offset="0"/>

                  </RadialGradientBrush>

                </Rectangle.Fill>

              </Rectangle>

              <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center"
VerticalAlignment="Center"/>

            </Grid>

          </ControlTemplate>

      **  </Setter.Value>**

**      </Setter>**

**    </Style>**

**  </**UserControl.Resources>

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

    <Button
Style="{StaticResource Dugme}" HorizontalAlignment="Stretch"
Margin="44,54,55,45"
VerticalAlignment="Stretch">

      <Button.Content>

        <TextBlock
VerticalAlignment="Center"
Text="TextBlock"
TextWrapping="Wrap"/>

      </Button.Content>

    </Button>

  </Grid>

</UserControl>

Template tanımımızı Button'un içerisinden keserek doğrudan
UserControl.Resources altına alıyoruz. Böylece artık tüm Silverlight
XAML sayfası içerisinde kullanabileceğiz. Tabi bunu yaparken bir
Style tanımlıyoruz ve TargetType özelliğini de Button olarak
düzenliyoruz. Style içerisinde bir Setter yerleştirerek hedef
kontrolün Template özelliğini değiştirmek istediğimizi de
belirttikten sonra Setter.Value içerisine daha önce hazırladığımız
Template yapısını yerleştiriyoruz.

Son olarak adını Dugme koyduğumuz bu Style'ı kullanmak istediğimiz
tüm Button kontrollerinin Style özelliğini StaticResource
olarak stilimize bağlayarak kullanabiliyoruz. Böylece tüm düğmelerimiz
aynı ControlTemplate'i kullanacaklar ve hepsi de kendi içerisindeki
Content'ı hedef Style içerisindeki ContentPresenter'a
yerleştirerek gösterecekler. Herhangi bir görsel değişiklik gerektiğinde
ise merkezi olarak Style'ımızı değiştirerek ilerleyebileceğiz.

İsterseniz bu Stlye'ınızı Silverlight uygulamasının App.xaml dosyası
içerisine koyarak Silverlight uygulamanızdaki tüm XAML dosyaları
içerisinde kullanılabilir hale de getirebilirsiniz.

Hepinize kolay gelsin.