Makale Özeti

WPF ile user control kavramını incelemeye çalışıyoruz.

Makale

Windows Presentation Foundation ‘ın bizlere kattığı yenilikleri ve maksimum kullanıcı deneyimini günler geçtikçe daha iyi anlamaya başladık. Bu avantajları sağlayan en önemli etmenlerden biride özelleştirilebilir kullanıcı kontrolleri olmuştur. Bizlere sunulan kullanıcı kontrollerini dilediğimiz şekilde kullanarak son kullanıcıların hoşlarına giden uygulamalar hazırlayabiliyoruz. Fakat bazı noktalarda bu kontroller işlerimizi tam anlamıyla göremeyebiliyorlar. Bu durumlarda bizlerin yapması gereken ise kendi kullanıcı kontrollerimizi oluşturmak oluyor.

Kendilerimizin hazırlamış olduğu kullanıcı kontrollerini oluştururken Visual Studio (VS) ve Expression Blend (EB) ‘den yararlanabilmemiz mümkündür. EB ile hazırlamış olduğumuz kullanıcı kontrollerine işlevliğin yanı sıra birçok güzel animasyonda ekleyebilmemiz mümkün oluyor. EB ile tasarımını bitirmiş olduğumuz kontrolleri de rahatlıkla VS üzerinden kullanabilmemiz mümkün oluyordu. Bir diğer seçeneğimiz ise hiç işin tasarım ve animasyon yanlarına girmeden VS ile de sade tasarımlar oluşturabilmemiz mümkün oluyor. İşte biz bu yazımızda kendi kullanıcı kontrollerimizi (UserControl) nasıl oluşturacağımıza değinmeye çalışıyor olacağız. Konumuzu incelerken de örnek üzerinden değinerek daha akılda kalmasına olanak tanınacaktır.

Kendi kullanıcı kontrollerimizi geliştirme gereksinime ihtiyaç duymamız birçok sebepten ötürü doğmuştur. Bunlar kontrollerin yapmak istediğimiz işlemleri yerine getiremememizden tutunda yetersiz gördüğümüz özelliklerine kadar daha birçok düşünce aklımıza gelebilir. Bu durumda yapmamız gereken kendi isteklerimizi karşılayacak olan bir kontrol geliştirmek olacaktır.

Kullanıcı kontrollerimizi geliştirmeye başlarken ilk yapmamız gereken VS ‘den bir WPF uygulaması açmak olacaktır. Daha sonra yapmamız gereken ise oluşturmuş olduğumuz uygulamaya bir kullanıcı kontrolü eklemek olacaktır. İşlemimiz için iki yol vardır. Project-->AddUserControl yolunu takip etmektir.



Diğer yol ise Project-->Add NewItem yolunu takip edip karşımıza çıkan menüden UserControl (WPF) seçeneğini seçerek oluşturabiliriz.



İki farklı UserControl ekleme yolu gördük. Bu iki seçeneğin bir birinden farklı yerlerde olmasının içerik açısından hiçbir farklılığı yoktur. Sadece kolaylık olması açısından UserControl seçeneği ek olarak ayrı bir seçenek olarak sunulmuştur.

UserControl ümüzü yukarıda bahsettiğimiz iki yöntemden biri ile ekleyerek karşımıza gelen XAML dosyayı incelemeye başlayabiliriz. Ben bu uygulama için UserControl e “KontrolTurhal” adını verdim. Sizler istediğiniz ismi verebilirsiniz.



Eklenmiş olan kullanıcı kontrolüne değinelim. Karşımıza çıkan bir XAML dosyanın UserControl olduğunu anlayabilmemizin en kolay yolu ilk tag a bakmamız olacaktır. Burada UserControl yazdığına dikkat ediniz. Bunun anlamı ise yapmış olduğumuz işlemlerin diğer XAML dosyalar ve C# kod tarafında UserControl olarak algılanacağıdır. UserControl dışında Window, Page en çok kullanılan formlardır. User Control ise bu formlarda kullanılacak olan bileşenleri hazırlamamıza olanak tanır. Yukarıdaki resimde eklemiş olduğumuz UserControl ‘ün hangi sınıfa ait olduğunu yani hangi projede kullanılacağını belirtildiği yer ise x:Class bölümüdür. Oraya dikkat ederseniz KullaniciKontrol projesinin içerisine KontrolTurhal UserControl ‘ünün oluşturulduğunu rahatlıkla görebilirsiniz.

Artık kullanıcı kontrolümüzü oluşturmaya başlayabiliriz. Kullanıcı kontrollerini oluştururken dikkat etmemiz gereken en önemli özellik kullanıcıların neleri yapacağını düşünerek hareket etmemiz olacaktır.

Kullanıcı kontrolümüzü oluşturmaya başlarken ilk olarak DockPanel alanına ilişkin özellikleri tanımlıyoruz daha sonrada bir Border element tanımlayıp ona ait özellikleri belirlemeye başlıyoruz. Belirlediğimiz bu özellikler aşağıda görülmektedir.

KontrolTurhal.xaml
<UserControl x:Class="KullaniciKontrol.KontrolTurhal"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DockPanel LastChildFill="True">
        <Border DockPanel.Dock="Top" CornerRadius="4,4,0,0" Width="Auto"
                    Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                    Background="Beige" BorderBrush="Brown" BorderThickness="1">
            <TextBlock x:Name="txt_baslik" Width="Auto" Height="Auto"
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></TextBlock>
        </Border>
        <Border DockPanel.Dock="Top" CornerRadius="0,0,4,4" Width="Auto"
                    Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                    BorderBrush="Brown" BorderThickness="1,0,1,1" MinWidth="100px" MinHeight="100px">
            <TextBlock x:Name="txt_icerik" Width="Auto" Height="Auto"
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></TextBlock>
        </Border>
    </DockPanel>
</UserControl>

Belirmiş olduğumuz özelliklerin sonucunda kontrolümüzün aldığı ilk görüntü aşağıdaki gibi olmuştur.

Hazırlamış olduğumuz form kontrolüne dikkat ederseniz başlık ve içerik bölümlerinden oluşmakta ve bu bölümlere TextBlock yardımı ile yazı yazabilmekteyiz. Böyle bir kontrol tasarlamamızın amacı uygulamalarımızda başlık ve içerikten oluşan bu bölüm kullanacağımız zaman tek tek kontrolleri birleştirip oluşturmak yerine daha kullanışlı olması açısından böyle bir uygulama geliştirilmesine karar verilmiştir.

Şimdi içeriklerinin daha dinamik bir biçimde değiştirilebilmesi için C# kod tarafına özellikleri belirtmeye başlıyoruz. Özelliklerimiz başlıktan ve içerikten gelecek olan değerler için olacaktır. Hazırlamış olduğumuz C# kodu aşağıdaki gibidir.

KontrolTurhal.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;

namespace KullaniciKontrol
{

    public partial class KontrolTurhal : UserControl
    {
        public KontrolTurhal()
        {
            InitializeComponent();
        }

        public string BaslikTxt
        {
            get {
                return this.txt_baslik.Text;
            }
            set {
                this.txt_baslik.Text = value;
            }
        }

        public string IcerikTxt
        {
            get {
                return this.txt_icerik.Text;
            }
            set {
                this.txt_icerik.Text = value;
            }
        }
    }
}

Yukarıda hazırlamış olduğumuz kod bloğunu kısaca açıklamak gerekirse, başlık ve içeriğe ilişkin özellikleri tanımladık. Ayrıca hazırlamış olduğumuz bu sınıfta dikkat edilecek olan bir nokta kullanılacağı projede kullanılabilecek olduğunun belirtilmiş olmasıdır. Bu bahsettiğimiz duruma namespace ile tanımlanmış bölümde görebilirsiniz. Ayrıca bu belirtme sayesinde XAML dosyamızda hazırladığımız kontrolü rahatlıkla kullanabileceğiz.

UserControl ümüzü bu şekilde ana uygulamamıza çağırmak istersel yapmamız gereken başlıca şey onu uygulamaya eklemek olacaktır. Bunun için ise kullanacağımız yöntem xmlns ile yapılacaktır. xmlns:… üç nokta ile belirttiğimiz yere kontrolü tanımlamımız gerekecektir. Bunun için yapmamız gerekecek User Control Custom ‘ı uccustom olarak belirtmek olacaktır. Sonrasında bizden CLR ‘ı belirtmemizi isteyecektir. Bizde elimizde bulunan isim alanlarını tanımlayarak işlemi bitirmiş olacağız. Dikkat ederseniz biraz önce bahsetmiş olduğumuz sınıftaki nameSpace ‘i kullanmış olacağız.

Not: User Control Custom olarak belirttiğimiz bölümü istediğimiz biçimde tanımlayabilmemiz mümkündür. Benim böyle bir şeyi tercih etmemim sebebi yaptığımız işlemin harici kullanıcı kontrolü hazırlamak olduğundan ötürü akılda daha kalıcı olması açısından öyle belirttim. Sizler xmlns:turhal (isim örnek amaçlıdır) biçiminde yazarak ta kullanabilirsiniz. Bu durumda aşağıda anlatacak olduğumuz işlemleri belirttiğiniz isme göre yapmanız gerekecektir.

,

Artık harici kontrollerimizi uygulamamızın ana ekranında kullanabilir duruma gelmiş durumdayız. Şimdi yapacak olduğumuz diğer kontrolleri kullanırmış gibi uygulamamıza eklememiz olacaktır. Tabii bunu yaparken dikkat etmemiz gereken bir nokta var. hazırladığımız olan kontrol bileşen paletinde değilde uygulamamız içerisinde olduğundan ötürü xmlns ile tanımlamış olduğumuz isme göre işlemlerimiz yapmamız gerekmektedir. Şimdi bunu nasıl yapacağımızı göz atalım.



Kullanıcı sınıfımızı çağırdıktan sonra kod tarafında tanımlamış olduğumuz özellikleride kullanabiliyoruz.



Intellisence sonucunda bizim tanımlamış olduğumuz özellikleri de tanımlıyoruz. Oluşturduğumuz XAML kodu aşağıdadır.

<Window x:Class="KullaniciKontrol.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:uccustom="clr-namespace:KullaniciKontrol"
    Title="Kullanici Kontrolleri" Width="300" Height="300">
    <Grid>
        <uccustom:KontrolTurhal Width="200px" Height="150px"
                                        IcerikTxt="Icerigimizi giriyoruz."
                                        BaslikTxt="Basligi giriyoruz.">
        </uccustom:KontrolTurhal>
    </Grid>
</Window>

Uygulamamızı çalıştırdığımız zaman ekran görüntümüzde aşağıdaki gibidir.



Kontrolümüzün içerikleri istediğimiz şekilde gerçekleşti. Hazırlamış olduğumuz kontrolde başlık ve içerik bir biçimde tanımlamış olduğumuz özellikleri doldurarak oluşturduğumuz tasarımın içerisinde yazdıklarımızı görmüş oluyoruz. Ayrıca özelliklerimizi Properties penceresinden de görebiliyoruz.



Kontrolümüzü kullanma ile ilgili birkaç noktaya değinmeye çalışalım. İçerik ve başlık biçiminde yazılarımızı girebildiğimizden bahsetmiştik. Diğer kontrolleri göz önüne aldığımızda kendi içerik özelliklerinin dışından varsayılan olarak taglar arasında yazılanları kullanıcı kontrolü dâhilinde gösterebilmektedir. Bunların en bariz örneği de <TextBlock> kontrolüdür. Bu kontrolde Text=”deneme” biçiminde içeriğini belirlerken aynı zamanda <TextBlock>deneme</TextBlock> şeklinde de tanımlayabiliyoruz. Fakat bizim hazırlamış olduğumuz kontrolü göz önüne alırsak IcerikTxt=”” özelliğinin içeriğine yazmış olduğumuz yazıyı buradan kaldırıp ta <uccustom:KontrolTurhal>Deneme</uccustom:KontrolTurhal> biçiminde yazdığımızda hazırlamış olduğumuz kontrolü ortadan kaldırarak sadece yazmış olduğumuz deneme yazısı formumuzda gözükecektir. Kontrolümüzde yazdığımız kodları yokmuş gibi varsayacaktır. Ana amacımız bu durumu ortadan kaldırmak olmalıdır. Fakat daha önce bu durumun nasıl gerçekleştiğine dair ekran görüntüsüne göz atalım.



Kodumuzu bu şekilde düzenlediğimizde karşımıza çıkan ekran görüntüsüne göz atalım.



Ekran görüntüsüne dikkat ederseniz biraz önce bahsettiğimiz sorun gerçekleşmiş olacaktır. Bu durumun ortadan kaldırılması için yapacağımız işlemleri incelemeye çalışalım.

Kontrol.Turhal.xaml.cs kod bölümüne tekrar dönelim. Yaptığımız işlem Markup ‘ların dışarında olduğu için Markup isim alanını çağırmamız gerekecektir.



System.Windows.Markup isim alanını sınıfımıza ekledikten sonra bu isim alanına ait olan Attribute (öz nitelik) lerinden ContentPropery ‘i kullanarak Markup kodlamada taglar dışına yazılanları IcerikTxt gibi algılanmasını sağlayacağız. Bu işlemi yaparken ContentProperty özniteliğinin özelliğine IcerikTxt ‘yi atamamız gerekecektir. Ekleyecek olduğunuz öz niteliği kullanıcı kontrolüne ait olan sınıfın hemen üstüne yazmamız gerekmektedir. Yoksa hata verecek ve yaptığımız özelliği varsayılan olarak kullanamadığını bize bildirecektir.



Bu değişiklik sonrasından uygulamamızı tekrardan derlediğimizde içerik özelliği ile karşılaştığımız sorunu halletmiş olacağız.



Şimdi de uygulamamızda başka bir noktaya göz atalım. Hazırlamış olduğumuz kontrollerde varsayılan olarak gelen ve kullanıcı kontrolüne içerik eklememize olanak tanıyan Content özelliği bulunmaktadır. Bu özelliği kullanmak istediğimiz aynı biraz önce karşılaştığımız gibi bir sorun ile karşı karşıya kalırız. Yine boş bir ekranda yalnızda Content özelliğine yazılmış olan yazı bizleri karşılamaktadır.

Bu durumdan kurtulabilmemiz için yapmamız gereken işlem ise, kullanıcı kontrolümüzü tanımladığımız sınıfa tekrardan giderek aşırı yüklenmeye korumalı bir sınıf oluşturmamız gerekmektir.

Oluşturacak olduğumuz sınıf içerik değişikliklerini koruyacağı için onContentChanged üyesini seçerek işlemlerimizi yapabiliriz.



KontrolTurhal.xaml.cs ‘a eklemiş olduğumuz korumalı sınıfa ait kod bloğu aşağıdaki gibidir.

protected override void OnContentChanged(object oldContent, object newContent)
    {
        if (oldContent!=null)
        {
            throw new NotSupportedException("Kullanmis oldugunuz kontrole iki adet içerik giremezsiniz.");
        }
    }

Değişikliklerimizi yapıp Content özelliğine değer girdikten sonra uygulamamızı derlediğimizde biraz önce belirttiğimiz mesaj kullanıcılara hata olarak sunulmaktadır.



Bu hata mesajını verdirterek kullanıcıya aynı görevi yapan iki özelliği kullanmasını da engellemiş oluyoruz. Daha sonra Content özelliğine yazdığımız değerleri kaldırdıktan sonra uygulamamızı derlediğimizde kontrolümüzün sorunsuzca çalıştığını göreceğiz.

Sonuç olarak bu yazımızda nelere değindiğimizi kısaca toparlamak gerekirse, ilk olarak WPF uygulamalarına bir UserControl eklemek istediğimizde bunu nasıl yapacağımıza değindik. Daha sonra Uygulamamıza eklemiş olduğumuz UserControl ‘ün XAML ve C# içeriğini nasıl oluşturabileceğimize inceledikten sonra ana uygulamamızda kontrolümüzü nasıl kullanabileceğimize değindik. Son olarak ise diğer kontroller ile kendi kontrolümüzü karşılaştırarak ne tür eksikleri olduğuna göz attıktan sonra bu eksikleri nasıl düzeltebileceğimize değindik.

Umarım yararlı olmuştur.

Yazımızda değinmiş olduğumuz uygulamanın kaynak kodlarına download bölümünden erişebilirsiniz.

Turhal Temizer
turhal.temizer@yurticikargo.com
http://turhal.blogspot.com
Yazımızda değinmiş olduğumuz projenin kaynak kodlarına erişebilirsiniz