Makale Özeti

WPF uygulamalarında kullanmış olduğumuz kontrollerin tasarım için hazırladığımız özellikleri Style sınıfında nasıl kullanabileceğimizi incelemeye çalışıyoruz

Makale

Web programlama ile ilgilenenler CSS ‘in ne kadar yararlı olduğunu bilirler. Bilmeyenler için ise kısa bir bilgilendirme yapalım. Web sayfamızda kullanacak olduğumuz tasarımları, yazı fontlarını, renkleri ve daha birçok özelliği belirleyebildiğimiz dosyalardı. Daha sonrasından ise belirlemiş olduğumuz bu tasarımları gerekli yerlerde kullanarak hem zaman kaybından kurtulurken hem de web sayfamızda ekstra kod yazmaktan kurtuluyorduk.

Bu makalemizde Web uygulamalarından aşina olduğumuz stil işlemlerinin Windows Presentation Foundation ile nasıl yapabileceğimizi incelemeye çalışacağız.

Not: Visual Studio 2008 sp1 beta1 , .Net Framework 3.5 sp1 beta1 ve .Net Framework 3.0 sp2 beta1 12 Mayıs 2008 tarihinde bizlerin kullanımına sunulmuştur. Kullanmak isteyenler www.microsoft.com/download adresinden gerekli linki bularak indirebilirler. Fakat kurulması için sisteminizde kurulu olan beta ürünleri kaldırmanız gerekmektedir. Bu özellikle Silverlight 2,0 beta1 kullanan geliştiricileri ilgilendirmektedir. Beta ürünleri sildiğimizde geliştirme yapıyorsak nasıl devam edeceğiz derseniz ise SP1 beta1 ‘i kurduğunuz zaman silmiş olduğunuz yazılımlar geri yüklenecek ve diğer yazılımlarınızda eksikleri giderilmiş olarak bizlere sunulacaktır.

Stil işlemlerini uygulama üzerinden anlatmaya çalışacağız. Uygulamamızı ise Visual Studio 2008 ürünü ile gerçekleştiriyor olacağız. VS2008 ‘i olmayan geliştiriciler ise isterlerse Expression Blend veya C# Express Edition ile de yapacak olduğumuz uygulamaları yapabilmeleri mümkündür. Bahsettiğimiz herhangi bir ürün ile WPF application projesi oluşturarak stil işlemlerini incelemeye başlayabiliriz.

Stil işlemlerini incelerken uygulayacak olduğumuz senaryoyu özetlemek gerekirse. Ekranımızı kullanabileceğimiz iki sütuna bölerek bu sütunlara listbox ve buton kontrollerini ekleyeceğiz. Bu kontrolleri ve değerlerini ilk olarak bu kontrollere dâhil stil işlemleri ile daha sonrada style sınıfını kullanarak kontrollerimizde nasıl kullanabileceğimizi inceleyeceğiz.

Uygulamamızda kullanacak olduğumuz çalışma alanını iki sütuna bölüyoruz. Daha sonrada Listbox ve üç tane buton ekliyoruz.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <ListBox Width="200" Height="150" Grid.Column="0" VerticalAlignment="Top">
        <ListBoxItem>Deger 1</ListBoxItem>
        <ListBoxItem>Deger 2</ListBoxItem>
        <ListBoxItem>Deger 3</ListBoxItem>
        <ListBoxItem>Deger 4</ListBoxItem>
        <ListBoxItem>Deger 5</ListBoxItem>
    </ListBox>
    <StackPanel Grid.Column="1" Orientation="Vertical" VerticalAlignment="Top">
        <Button>Ekle</Button>
        <Button>Duzenle</Button>
        <Button>Sil</Button>
    </StackPanel>
</Grid>

Çalışacak olduğumuz alanının tasarımını belirledik. Şimdi ise eklemiş olduğumuz kontrollere en temel yöntemle tasarım ile ilgili özelliklerini aktarmaya başlayalım. Özelliklerimize ekranda nerede olacağına , köşe renklerine, arka plan renklerine ve yazı boyutlarını belirliyoruz. Ayrıca butonlara belirttiğimiz özelliklere ek olarak yazı stili de ekliyoruz. Sizler farklı yazı stilleri eklemek isterseniz XAML kod tarafında işlemlerinizi yapmak yerine form üzerindeki kontrollere ait özelliklerden font-family seçeneğinden bulabilirsiniz.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <ListBox Width="200" Height="150" Grid.Column="0" VerticalAlignment="Top">
        <ListBoxItem Margin="0,2,0,3" Foreground="Red" FontSize="18">Deger 1</ListBoxItem>
        <ListBoxItem Margin="0,2,0,3" Foreground="Red" FontSize="18">Deger 2</ListBoxItem>
        <ListBoxItem Margin="0,2,0,3" Foreground="Red" FontSize="18">Deger 3</ListBoxItem>
        <ListBoxItem Margin="0,2,0,3" Foreground="Red" FontSize="18">Deger 4</ListBoxItem>
        <ListBoxItem Margin="0,2,0,3" Foreground="Red" FontSize="18">Deger 5</ListBoxItem>
    </ListBox>
    <StackPanel Grid.Column="1" Orientation="Vertical" VerticalAlignment="Top">
        <Button Foreground="DarkBlue" Background="LightSkyBlue"
                    FontSize="15" FontFamily="French Script MT">Ekle</Button>
        <Button Foreground="DarkBlue" Background="LightSkyBlue"
                    FontSize="15" FontFamily="French Script MT">Duzenle</Button>
        <Button Foreground="DarkBlue" Background="LightSkyBlue"
                    FontSize="15" FontFamily="French Script MT">Sil</Button>
    </StackPanel>
</Grid>

Yukarıdaki kullanım biçimini sıkça uygulamalarımızda kullanıyorduk. Bu kullanım biçimini web uygulamalarında CSS kullanmadığımız zamanlarda görünen sayfaya tasarım bilgilerinin yazılması gibi kabul edebiliriz. WPF uygulamalarında ise bizim çalışma alanımızın dışında kalan bölümler stil dosyalarını belirleyeceğimiz bölümler olarak kullanacağız.

Eğer ki Expression Blend(EB) ile tasarım yapıyorsanız şimdi bahsedeceğimiz yönteme hiçte yabancı olmadığınızı fark edeceksiniz. Çünkü EB ile hazırladığınız tasarımlarda arka planda oluşturulmak olan XAML kodlar ekstra kod fazlalığını minimuma indirerek oluşturmaktadır. Bu sebepten ötürüde stil, animasyon gibi işlemlere ait kodları tek tek kontrollere eklemek yerine stil işlemleri stil sınıfına animasyon işlemlerini de Triggers sınıfına ekleyerek kullanmamızı sağlamaktadır.

Bizim hazırlayacak olduğumuz işlemlerin EB ile nasıl yapıldığını anlattıktan sonra şimdi bizde style sınıfını kullanarak tasarım işlemlerimizi miraslanabilir duruma getirebiliriz.

Penceremize ait özellikleri özkaynaklarında (resource) belirterek tekrardan kullanılabilir olmasına olanak tanıyoruz.



<Window.Resources>
    <Style x:Key="lb1" TargetType="ListBoxItem">
        <Setter Property="Margin" Value="0,2,0,3" />
        <Setter Property="Foreground" Value="Red" />
        <Setter Property="FontSize" Value="18" />
    </Style>
</Window.Resources>

Biraz önce kontrol içerisine eklemiş olduğumuz özelliklerin hepsini özkaynak olarak belirttik. Şimdi ise belirtmiş olduğumuz bu özkaynakları şimdi nasıl kullanacağımıza değinelim.

<ListBoxItem Margin="0,2,0,3" Foreground="Red" FontSize="18">Deger 1</ListBoxItem>

ListBox ‘a ait özellikleri en basit anlamda bu biçimde tanımlarken şu anda Style sınıfını kullanarak x:Key olarak belirlediğimiz attribute ‘e bağlayacağız.

<ListBox Width="200" Height="150" Grid.Column="0" VerticalAlignment="Top">
    <ListBoxItem Style="{StaticResource lb1}">Deger 1</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb1}">Deger 2</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb1}">Deger 3</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb1}">Deger 4</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb1}">Deger 5</ListBoxItem>
</ListBox>

ListBox kontrolünde değerleri tanımlamış olduğumuz ListBoxItem ‘ın özelliklerinde Style sınıfından tanımlanmış olan özelliğine statik olarak değeri bağlıyoruz.

Şimdi ise butonumuza ait özellikleri özkaynak olarak ayarlayalım. Style sınıfını kullanım yöntemine dikkat ettiyseniz standart olarak kontrollerde kullandığımız tasarım bilgilerini Setter sınıfının içerisinde özelliğini ve değerini belirleyerek kullanıyoruz. Setter ‘ın içerisinden tanımlamış olduğumuz özelliklere ilişkin değerler intellisence ile bize sunulmamaktadır. Bizler bu özelliklere ilişkin değerleri normalde kontrolün içerisinde kullanmış olduğumuz özelliklerden yararlanarak belirliyoruz.

Style kullanmadan önceki buton kontrolümüze ilişkin görüntü;

<Button Foreground="DarkBlue" Background="LightSkyBlue"
            FontSize="15" FontFamily="French Script MT">Ekle</Button>

Kullanmış olduğumuz style sınıfı;

<Style x:Key="ekleButon" TargetType="Button">
    <Setter Property="Foreground" Value="DarkBlue"/>
    <Setter Property="Background" Value="LightSkyBlue"/>
    <Setter Property="FontSize" Value="15"/>
    <Setter Property="FontFamily" Value="French Script MT"/>
</Style>
    <Style x:Key="duzenleButon" TargetType="Button">
    <Setter Property="Foreground" Value="DarkBlue"/>
    <Setter Property="Background" Value="LightSkyBlue"/>
    <Setter Property="FontSize" Value="15"/>
    <Setter Property="FontFamily" Value="French Script MT"/>
</Style>
<Style x:Key="silButon" TargetType="Button">
    <Setter Property="Foreground" Value="DarkBlue"/>
    <Setter Property="Background" Value="LightSkyBlue"/>
    <Setter Property="FontSize" Value="15"/>
    <Setter Property="FontFamily" Value="French Script MT"/>
</Style>

Belirmiş olduğumuz stilleri biraz önce ListBox kontrolünden kullandığımız gibi bağlamamız gerekecektir. Yukarıdaki stil dosyalarını kontrol ederken kafanıza ufak bir soru takılabilir. “Stillerde kullanılan bütün özellikler aynı olduğundan tek bir stilin içerisinde kullanıla bilemiyormuydu ? “diyebilirsiniz. Tabii ki de benzerlik olduğu durumlardan tek bir stil sınıfında toparlamak mümkün olacaktır. Fakat daha sonra yapacak olduğumuz değişikliklerden ötürü üç buton içinde ayrı ayrı stil ayarladık.

Buton kontrollerimizde stilleri kullanma şeklimiz;

<StackPanel Grid.Column="1" Orientation="Vertical" VerticalAlignment="Top">
    <Button Style="{StaticResource ekleButon}">Ekle</Button>
    <Button Style="{StaticResource duzenleButon}">Duzenle</Button>
    <Button Style="{StaticResource silButon}">Sil</Button>
</StackPanel>

Temel olarak stillerimizi oluşturduk ve gerekli olan kontrollerimize bağlamalarını yaptık. Şimdi isterseniz ekran görüntüsünün nasıl gözüktüğüne göz atalım.



Stilleri daha önceden oluşturupta kontrollere bağladığımızda herhangi bir sorun oluşmadan kontrollerimizin gerekli stillerine kavuştuğunu görürüz. Ayrıca dikkatinizi çekmek istediğimiz bir nokta var. Uygulamamızda kullanacak olduğumuz stillere ilişkin özellikleri çalışma penceremizin özkaynaklarına eklemeden önce XAML kod tarafımızın çok karmaşık olduğunu görürüz. Stillere ilişkin bilgileri özkaynak sınıfının içerisine eklediğimizde ise hem XAML kod tarafında oluşan karmaşık görüntüyü ortadan kaldırdı hem de bizleri aynı özellikleri defalarca kez yazmaktan kurtardı.

Şimdi ise düzenle ve sil butonlarımıza ilişkin stil özelliklerinde ufak değişiklikler yapalım. Sil butonunun dikkat çekmesi için yazı renklerini rengini kırmızı, düzenle butonunki ise yeşil olarak belirleyelim.

<Style x:Key="duzenleButon" TargetType="Button">
    ***
    <Setter Property="Foreground" Value="DarkGreen"/>
    ***
</Style>
<Style x:Key="silButon" TargetType="Button">
    ***
    <Setter Property="Foreground" Value="Red"/>
    ***
</Style>

Butonlara ilişkin stil özelliklerinde bu ufak değişiklikleri yaptıktan sonra uygulamamızı tekrardan çalıştırdığımızda değişikliklerin uygulandığını göreceksiniz.

ListBox kontrollerinde kullandığımız bütün kontrollere aynı stil sınıfını bağlamıştık. Şimdi ise hepsi için ayrı ayrı stiller oluşturacağız. Ekleyecek olduğumuz stiller de ana özellikler aynı olmakta birlikte yalnızca yazıların renklerini değiştireceğiz.

<Style x:Key="lb1" TargetType="ListBoxItem">
    <Setter Property="Margin" Value="0,2,0,3" />
    <Setter Property="Foreground" Value="Red" />
    <Setter Property="FontSize" Value="18" />
</Style>
<Style x:Key="lb2" TargetType="ListBoxItem">
    <Setter Property="Margin" Value="0,2,0,3" />
    <Setter Property="Foreground" Value="Blue" />
    <Setter Property="FontSize" Value="18" />
</Style>
<Style x:Key="lb3" TargetType="ListBoxItem">
    <Setter Property="Margin" Value="0,2,0,3" />
    <Setter Property="Foreground" Value="Green" />
    <Setter Property="FontSize" Value="18" />
</Style>
<Style x:Key="lb4" TargetType="ListBoxItem">
    <Setter Property="Margin" Value="0,2,0,3" />
    <Setter Property="Foreground" Value="Yellow" />
    <Setter Property="FontSize" Value="18" />
</Style>
<Style x:Key="lb5" TargetType="ListBoxItem">
    <Setter Property="Margin" Value="0,2,0,3" />
    <Setter Property="Foreground" Value="Cyan" />
    <Setter Property="FontSize" Value="18" />
</Style>

Özelliklerini değişitirdiğimiz listbox stillerini tek tek kontrollerine bağlamamız gerekmektedir. Onu da aşağıdaki gibi yapıyoruz.

<ListBox Width="200" Height="150" Grid.Column="0" VerticalAlignment="Top">
    <ListBoxItem Style="{StaticResource lb1}">Deger 1</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb2}">Deger 2</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb3}">Deger 3</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb4}">Deger 4</ListBoxItem>
    <ListBoxItem Style="{StaticResource lb5}">Deger 5</ListBoxItem>
</ListBox>



Stil işlemlerini yaparken kafamıza şöyle bir soru takılabilir. “Tek bir stil sınıfında tanımlamış olduğumuz özellikleri diğer stil sınıflarına özelliklerini miraslayamaz mıyız?”. Bu sorunu cevabı tabii ki de evet olacaktır. Çünkü dikkat sizlerde dikkat etmişsinizdir ki hem ListBox kontrolü için hem de Buton kontrolü için hazırmış olduğumuz stillerde birbirlerini tekrarlayan özellikler oldukça fazladır. Bizlerde bu tür işlemleri uygulamalarımızda daha az kod yazabilmek için yaptığımızdan dolayı farklı çözüm yolları üretmemiz gerekecektir. Style sınıfının özelliklerini incelediğimizde Baseon özelliği dikkatimizi çekmektedir. Bu özellik başka bir stil sınıfındaki özellikleri kullanıldığı sınıfa miraslayabilmeye olanak tanıyor. Miraslama işlemini ise hazırlamış olduğumuz stilleri kontrollere bağladığımız biçimde kullanacağız.



Stillerde yer alan benzer özellikleri sadece tek bir stil sınıfında kullanarak diğer stil sınıflarına miraslama yani bağlama yapacağız. Bu işlemleri aşağıdaki gibi yapabilmemiz mümkündür.

<Window.Resources>
    <Style x:Key="lb1" TargetType="ListBoxItem">
        <Setter Property="Margin" Value="0,2,0,3" />
        <Setter Property="Foreground" Value="Red" />
        <Setter Property="FontSize" Value="18" />
    </Style>
    <Style x:Key="lb2" TargetType="ListBoxItem" BasedOn="{StaticResource lb1}">
        <Setter Property="Foreground" Value="Blue" />
    </Style>
    <Style x:Key="lb3" TargetType="ListBoxItem" BasedOn="{StaticResource lb1}">
        <Setter Property="Foreground" Value="Green" />
    </Style>
    <Style x:Key="lb4" TargetType="ListBoxItem" BasedOn="{StaticResource lb1}">
        <Setter Property="Foreground" Value="Yellow" />
    </Style>
    <Style x:Key="lb5" TargetType="ListBoxItem" BasedOn="{StaticResource lb1}">
        <Setter Property="Foreground" Value="Cyan" />
    </Style>
    <Style x:Key="ekleButon" TargetType="Button">
        <Setter Property="Foreground" Value="DarkBlue"/>
        <Setter Property="Background" Value="LightSkyBlue"/>
        <Setter Property="FontSize" Value="15"/>
        <Setter Property="FontFamily" Value="French Script MT"/>
    </Style>
    <Style x:Key="duzenleButon" TargetType="Button" BasedOn="{StaticResource ekleButon}">
        <Setter Property="Foreground" Value="DarkGreen"/>
    </Style>
    <Style x:Key="silButon" TargetType="Button" BasedOn="{StaticResource ekleButon}">
        <Setter Property="Foreground" Value="Red"/>
    </Style>
</Window.Resources>

Değişikleri yaptıktan sonra kodlarımızın ne kadar azaldığına görüyoruz. Bu sayede hem çalışma alanımızın boyutu küçüldü hem de bizler tekrardan stilleri düzenlemek istediğimizde çok daha kolay bir biçimde bu işlemi yapabilir duruma geldik.

Yaptığımız değişiklikler sonucunda ekran görüntüsünde ise herhangi bir değişiklik olmamıştır.



Son olarak butonlara iki farklı renkten oluşan arka plan stili ayarlayacağız. Bunu yapabilmemiz için stil sınıfında Background özelliğinin alt özelliklerinden olan LinearGradientBrush yararlanacağız. Ayrıca bir buton üzerinden değişiklik yaptığımız diğer butonlar o butonun özelliklerine bağlı olduğu için değişiklikler otomatik olarak aktarılacaktır. Bu sebepten ötürü yalnızca ekleButon stili üzerinde değişiklik yapıyoruz.

<Style x:Key="ekleButon" TargetType="Button">
    <Setter Property="Foreground" Value="DarkBlue"/>
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientStop Offset="0" Color="CornflowerBlue"/>
                <GradientStop Offset="1" Color="Bisque"/>
            </LinearGradientBrush>
        </Setter.Value>
    </
Setter>
    <Setter Property="FontSize" Value="15"/>
    <Setter Property="FontFamily" Value="French Script MT"/>
</Style>

Yapmış olduğumuz değişiklik sonucunda ekran görüntümüz ise aşağıdaki gibi olmuştur.



Stil işlemleri ile birlikte tasarımlarımızı ekleyebileceğimiz iki yöntem daha bulunmaktadır. Kısaca bu iki yönteme değinmeye çalışalım. Bunlardan birincisi yazımızda da değinmiş olduğumuz window.resource çalışma alanımızın özkaynaklarıdır. Bu sınıf içerisinde style dahil olmak üzere birçok özelliği saklayabilmemiz mümkündür. En sık olarak kullanılan yöntemde yaptığımız tasarımları özkaynak olarak saklamaktır. Çünkü uygulama çalıştırıldığında bu sınıf içerisindeki değerler kullanılmak üzere belleğin bir köşesinde tutulduğundan ötürü animasyon ve tasarım işlemlerinin kullanılması esnasından bu iki işlemden kaynaklanan performans kaybını minimuma indirgeyecektir.

Kullanabileceğimiz bir diğer yöntem ise ControlTemplate ‘dir. Kullanıcı arayüzünde sıklıkla kullanılacak olan kontrolleri stilleri ile birlikte tanımlamamıza olanak tanımaktadır. İşlevi ise UserControllere oldukça fazla benzemektedir. Daha sonraki yazılarımızda ControlTemplate 'e ilişkin özelliklere değinmeye çalışacağız.

Sonuç olarak yazdıklarımızı toparlamak gerekirse, stil işlemlerini neden kullanmamız gerektiğine değinerek yazımıza başlamıştık. Sonrasında en acemi yöntem ile kontrollerimize tasarımsal özellikler ekledik. Bu özellikleri eklediğimizde XAML kod tarafının ne kadar karmaşıklaştığını ve kullanacak olduğumuz kontrol sayısının 3 - 5 değil de 100-200 olduğu durumlarda içinden çıkılamayacak bir durum oluşacağını göz önüne alarak kullanmış olduğumuz tasarım özelliklerini stil sınıfının özelliklerine nasıl kullanacağımıza değindik. En son olarak stil sınıflarında benzer olarak kullanılan özelikleri yalnızca bir kez tanımlayarak diğer stil sınıflarına nasıl miraslayacağımız gördük.

Umarım yararlı olmuştur.

Turhal Temizer
turhal.temizer@yurticikargo.com
http://turhal.blogspot.com
Yazımızda değinilen uygulamaların kaynak kodlarına ulaşabilirsiniz.