Mehmet KORDACI

Uygulama geliştirirken OOP prensiplerine yaklaştıkça nesneler arasındaki ilişkilerin önemi de gitgide artıyor.  Ben de tasarım desenlerine verdiğim kısa arada çok karıştırılan iki kavramdan bahsetmek istiyorum. Nesneler arasındaki iki ilişki türü : Aggregation, Association

Aggregation : Bu tür ilişki de nesnelerin yaşam döngüleri birbirlerinden ayrıdır. Bir nesne diğerinden bağımsız olarak da yaşamını sürdürebilir. Yani aralarında bir sahiplik ilişkisi (has-a ) vardır. Örneğin Dizüstü Bilgisayarınız ile onun çantası arasında böyle bir ilişki vardır. Çantayı ayrı olarak ya da laptop’u ayrı olarak düşünebiliriz. Yaşam döngüleri ortak değildir. UML diagramında gösterimi ve koda dökülmüş bir örneği aşağıdaki gibidir.

public class Canta
{

}
public class Laptop {
private Canta _canta;
public Laptop(Canta canta)
{
_canta = canta;
}
}

Composition : Bu tür ilişki de nesnelerin yaşam döngüleri birbirleriyle bağlantılıdır. Bir nesne diğerinden bağımsız olarak kullanılamaz. Aralarındaki ilişki parçası olma(is-a-part-of ) ilişkisidir. Az önceki örneğimizden gidersek dizüstü bilgisayarımız ile ekranı arasında bu tarz bir ilişki vardır. UML diagramında gösterimi ve koda dökülmüş bir örneği aşağıdaki gibidir.

public class Ekran
{

}
public class Laptop
{

Ekran _ekran = new Ekran();
}

Şu aralar daha önceden üzerinden geçtiğim tasarım desenleri ile uğraşıyorum tekrar. Ama bu sefer biraz daha pratik şekilde ilerlemeye çalışıyorum. İlerdikçe de burada hem bana ilerde hatırlamam için not olması hem de ihtiyacı olanların faydalanması için paylaşmaya çalışıyorum.

Son yazımda Strateji tasarım deseninden bahsetmiştim. Bu kez ise Observer tasarım deseninden bahsetmeye çalışacağım. Örneğin bir alışveriş sitesinin kampanyalarından haberdar olmak için maillist’ine kayıt olduğunuzu düşünün, daha sonra bir başkasının da aynı listeye abone olduğunu düşünelim. Bir kampanya olduğunda siteden abone olan herkese bu kampanya gönderilir.  Daha sonradan artık kampanya bilgilerini almak istemezseniz listeden çıkarsınız ve artık yeni kampanya bilgileri diğer abonelere gönderilir.

Observer tasarım deseni de uygulamalarımızdaki bu tarz işlemlerimizi yapmamızı kolaylaştıran bir desendir. Örneğin bir nesnenin durumu değiştiğinde uyarılacak nesneler listesine eklenmiş nesnelerimiz otomatik olarak uyarılır.

Bu desen ile ilgili örneğimi bir önceki strateji deseni örneğim üzerinden yapacağım. Böyle olması biraz daha karışık olmasına sebep oldu ama ezbere kaçmayı önlememi sağladı. Ayrıca iki deseni bir örnek de birleştirmiş oldum. Öncelikle eklememiz gereken yeni arayüz ve sınıfları vereceğim, daha sonra değişiklik yapmamız gereken kısımlardan bahsedeceğim.

İlk olarak biri yayıncı(subject) biri de dinleyici (subscriber,observer) olmak üzere iki interface tanımlayacağım. Daha sonra kullanacağım bütün dinleyici ve yayıncı sınıfları bu sınıflardan türeteceğim.

public interface IYayinci
{
void dinleyiciKaydet(IDinleyici dinleyici);
void dinleyiciCikar(IDinleyici dinleyici);
void dinleyicileriUyar();
}
public interface IDinleyici
{
void guncelle(ArrayList args);
}

Burada IYayinci arayüzümüzde üç adet metodumuz var bunlar uyarılacak nesneleri eklememizi, çıkarmamızı ve nesnenin durumu değiştiğinde listemizdeki nesnelerin uyarılmasını sağlıyor. IDinleyici arayüzündeki metodumuz ise durum değişikliği olduğunda yapılması gereken işlemleri içeren metoddur.

İkinci olarak yayıncı sınıfımızı oluşturuyoruz. Bu sınıfımızda arayüzden aldığı metodları implemente ediyoruz. Ayrıca ben bir adet renkDegisti metodu ekledim ki bu metodu da renk değişimi olduğunda kullanacağız.

public class RenkYayinci : IYayinci
{
ArrayList _dinleyiciler;
ArrayList _args;
public RenkYayinci()
{
_dinleyiciler = new ArrayList();
_args = new ArrayList();
}
public void dinleyiciKaydet(IDinleyici dinleyici)
{
_dinleyiciler.Add(dinleyici);
}
public void dinleyiciCikar(IDinleyici dinleyici)
{
int i = _dinleyiciler.IndexOf(dinleyici);
if (i >= 0)
{
_dinleyiciler.RemoveAt(i);
}
}
public void dinleyicileriUyar()
{
for (int i = 0; i < _dinleyiciler.Count; i++)
{
IDinleyici dinleyici = (IDinleyici)_dinleyiciler[i];
dinleyici.guncelle(_args);
}
}
public void renkDegisti(string renk)
{
_args.Clear();
_args.Add(renk);
dinleyicileriUyar();
}
}

Burada renkDegisti metoduna renk değişkenini almama rağmen bunu arraylist’e atma sebebim IDinleyici arayüzünün sadece renk için özelleşmesini engellemek ve daha sonra da kullanmak istememdir. Daha sonra dinleyicileriUyar() metodunu çağırıyoruz ve bütün ekli nesneleri haberdar ediyoruz.

Artık eski sınıflarımızda değişiklik yapmaya başlayabiliriz. Öncelikle Daire ve Kare Sınıflarımızı aşağıdaki şekle getiriyoruz.

public class Kare : Sekil, IDinleyici
{
private RenkYayinci _renkYayinci;
public Kare(Dictionary<string, int> degerler, RenkYayinci renkYayinci)
{
_cevre = new KareCevre();
_degerler = degerler;
this._renkYayinci = renkYayinci;
this._renkYayinci.dinleyiciKaydet(this);
}
public void guncelle(ArrayList args)
{
Console.WriteLine(“\nKare kenar renkler değişti ” + args[0].ToString());
}
}

public class Daire : Sekil, IDinleyici
{
private RenkYayinci _renkYayinci;
public Daire(Dictionary<string, int> degerler, RenkYayinci renkYayinci)
{
_cevre = new DaireCevre();
_degerler = degerler;
this._renkYayinci = renkYayinci;
this._renkYayinci.dinleyiciKaydet(this);
}
public void guncelle(ArrayList args)
{
Console.WriteLine(“\nDaire çember içi renkler değişti” + args[0].ToString());
}
}

Sınıf tanımlamalarımızda koyu ile işaretli yerleri değiştiriyoruz. Burada öncelikle constructor metodumuzda parametre olarak aldığımız yayıncıya nesnemizi ekliyoruz. Daha sonra dinleyici arayüzünden alınan guncelle metodunu implemente ediyoruz.

Artık desenimizi deneyebiliriz. Önceki yazımızda bulunan örnekteki main metodunu aşağıdaki şekilde değiştiriyoruz.

static void Main(string[] args)
{
Dictionary<string, int> dd = new Dictionary<string, int>();
dd.Add(“BirKenar”, 4);
RenkYayinci renkYayinci = new RenkYayinci();
Sekil sk = new Kare(dd, renkYayinci);
renkYayinci.renkDegisti(“mavi”);
Console.WriteLine(sk.cevreHesapla(dd).ToString());
Console.ReadLine();
}

Programımızı derleyip çalıştırdığımızda karşımızda

Kare kenar renkler değişti mavi

16

çıktısını görebiliriz.

Strateji tasarım deseni geliştirdiğimiz uygulama içinde algoritmaları sınıflandırmamızı ve çalışma anında kullanacağımız algoritmayı seçmemizi sağlar. Bu algoritmalar kendi içinde kapsüllenerek (encapsulate) programın geri kalanından soyutlanır ve uygulamamızın loosely coupled bir yapıda olmasına yardım eder. Örneğin bir maliyet hesabında LIFO mu yoksa FIFO mu kullanacağımızı çalışma anında belirlemek istiyorsak strateji tasarım desenini kullanarak bunu nesne yönelimli programlama ilkeleri doğrultusunda yapabiliriz.

Algoritmaların seçim işlemini if else blogları ile yapabilirdik. Ancak küçük bir değişiklikte uygulamamızın içine müdahale etmek zorunda kalırdık. Ayrıca yeni algoritmalar ekledikçe bu if else bloglarımız gittikçe uzayacaktı. Ya da işlemi kalıtım yolu ile de gerçekleştirebilirdik. Bir metodu üst bir sınıfta tanımlayıp, alt sınıflarda bu metodu override edebilirdik. Ancak bu durumda da bir değişiklik durumunda bütün alt sınıflarda kodu tekrar düzenlememiz gerekecekti. Ya da eklediğimiz her yeni sınıf için yeniden metodu override etmemiz gerekecekti. Bu durumda kodların yeniden kullanılabilirliği konusunda başarısız olacaktık.

Bu deseni nasıl uygulayabileceğimizi bir örnekle daha iyi gösterebiliriz. Ben nesne yönelimli programlama ile ilgili örnekler verirken daha anlaşılır ve daha uygulanabilir olması nedeniyle mümkün olduğunca şekiller üzerinden gitmeyi tercih ediyorum. Yine vereceğim bu örnekte Strateji tasarım desenini kullanarak Şekil sınıfından türeyen daire ve kare sınıflarının çevrelerini hesaplayan basit bir uygulama yazacağım.

Öncelikle çevre hesaplama algoritmalarını bir araya toplamam gerekiyor. Kapsülleme işlemini gerçekleştirmek ve çevre hesaplama algoritmalarını belli bir formatta tutmak için öncelikle bir interface yazıyorum.

public interface ICevre
{
int hesapla(Dictionary<string, int> degerler);
}

Bundan sonra çevre hesaplama algoritmalarımı tutacak bütün sınıfları bu interface’den türeteceğim. Bu interface’imiz bir adet hesapla metodu içeriyor. Interface’imizden sonra ise çevre hesaplayacak sınıflarımızı oluşturacağız.

public class DaireCevre : ICevre
{
private int cevresi = 0;
public int hesapla(Dictionary<string, int> degerler)
{
cevresi = 2*degerler["Pi"]*degerler["r"];
return cevresi;
}
}

DaireCevre sınıfımız ICevre interface’inden aldığı hesapla metodunu implemente ediyor. Aynı şekilde KareCevre sınıfını da yazıyoruz. Bu sınıf da kendine özgü algoritmasıyla çevre hesaplamasını yapıyor.

public class KareCevre : ICevre
{
private int cevresi = 0;
public int hesapla(Dictionary<string, int> degerler)
{
cevresi = degerler["BirKenar"]*4;
return cevresi;
}
}

Artık çevre ile ilgili hesaplamalarımızı yaptığımıza göre kullanacağımız sınıfları yazmaya geçebiliriz. İlk olarak şekillerimi türeteceğim bir Sekil sınıfı yazıyorum.

public class Sekil
{
public ICevre _cevre;
public Dictionary<string, int> _degerler;

public int cevreHesapla(Dictionary<string, int> degerler)
{
return _cevre.hesapla(degerler);
}
}

Bu sınıfımızda bütün algoritma sınıflarımızı kapsayabilmesi için bir adet ICevre interface’i nesnesi oluşturuyoruz. Böylece loosely coupled özelliğini de sağlamış oluyoruz. Yeni ekleyeceğimiz, çıkaracağımız ya da değiştireceğimiz algoritmalar uygulamanın geri kalanını etkilemiyor. Ayrıca parametreler için bir adet Dictionary nesnesi tanımladım. Burada gördüğümüz cevreHesapla metodu bizim dışarıdan erişeceğimiz ve hesaplama işlemlerini yaptıracağımız metod. Kendi içinde hangi şeklinde çevresi hesaplanacak ise ona ait metodu çağırıyor.

Artık kullanacağımız sınıfları yazabiliriz.

public class Kare : Sekil
{
public Kare(Dictionary<string, int> degerler)
{
_cevre = new KareCevre();
_degerler = degerler;
}
}

public class Daire : Sekil
{
public Daire(Dictionary<string, int> degerler)
{
_cevre = new DaireCevre();
_degerler = degerler;
}
}

Bu sınıflarımız da constructor metod çağrıldığında ICevre türünden olan nesnemize ilgili cevre sınıfı nesnesi(DaireCevre, KAreCevre) oluşturularak atanıyor. Böylece doğru hesapla fonksiyonunun çağrılması sağlanıyor.

Son olarak uygulamamızı deneyeceğimiz kısmı yazabiliriz.

static void Main(string[] args)
{
Dictionary<string,int> dd = new Dictionary<string,int>();
dd.Add(“BirKenar”,4);
Sekil sk = new Kare(dd);
Console.WriteLine(sk.cevreHesapla(dd).ToString());
Console.ReadLine();
}

Böyle bir denemede ekrana 16 yazacaktır.

www.mehmetkordaci.com

Geliştirdiğimiz ASP.NET uygulamalarında durum yönetimini ihtiyaçlarımıza göre birçok şekilde yapabiliriz. Bu seçeneklerden bir tanesi de ViewState yapısıdır. Hepimiz uygulamalarımızda bilinçli ya da bilinçsiz ViewState’leri kullanmışızdır. Bu bizi geleneksel asp ve php’deki kontrollerin durumunu korumak için yaptığımız ekstra işlerden kurtarır.

Ama ViewState’ler her zaman göründüğü kadar masum olamayabiliyor. Bazen ViewState’ler inanılmaz ölçülerde büyüyebiliyor ve bu durumda sayfa yükleme zamanlarınız farkedilir ölçüde artabiliyor. Bu yüzden ASP.NET uygulamalarımızda mümkün olduğunca durumunun tutulması gerekli olmayan kontrollerin ViewState’lerini kapatmamız gerekir.

Bu işlemi ASP.NET 4.0′dan önce EnableViewState özelliği ile yapıyorduk.  Böylece durumu tutulmasını istemediğimiz kontrollerin bu özelliğini false yaparak bu sorundan kurtulabiliyorduk. Ama EnableViewState’lerde tasarımı ile ilgili bir bug vardı. Eğer sayfamızda 100 kontrol içinden sadece 10 tanesinin durumunu tutmak istiyorsak, sayfamızın EnableViewState özelliğini false yapıp sadece bu 10 kontrolün özelliğini true yapmamız yeterli olmalıydı ama olmuyordu. Bu işlemi ancak sayfanın EnableViewState özelliğini true yapıp 90 kontrolün özelliklerini false yaparak sağlayabiliyorduk. Bunun da oluşturacağı zaman ve iş kaybını tahmin edebilirsiniz.

Ancak ASP.NET 4.0 ile gelen ViewStateMode özelliğini bizi bu sıkıntıdan kurtarmaktadır. Bu özellik parent kontrolün durumuna bakmaksızın kontrollerin durumlarını tutup tutmamamızı belirlememizi sağlar. ViewStateMode durumunu üç şekilde belirleyebiliriz.

  1. Inherit : Bu durumda kontrol parent kontrolün aynı şekilde davranacaktır.
  2. Enabled : Bu durumda parent kontrolün değeri disabled olsa bile kontrolün durum bilgileri tutulacaktır.
  3. Disabled : Bu durumda ise parent kontrolün durumu enabled olsa bile kontrolün durum bilgileri tutulmayacaktır.

NOT: TextBox,CheckBox ve RadioButton kontrollerinde EnableViewState özelliğini false yapsanız bile bu kontroller bazı durumlarını tutmaya devam etmektedir. İlgili bilgiyi buradan bulabilirsiniz.

www.mehmetkordaci.com

Bir regular expression’da parantez arasına alınmış ifadeler grupları oluştururlar. Örneğin

(\w+)\s\d*

ifadesinde (\w+) bir grup oluşturur. İfadenin tamamı varsayılan olarak 0 indisli ilk gruptur. Grupların sıralaması dıştan içe doğru ve soldan sağa doğrudur. Yani en kampsamlı grup varsayılan gruptan sonra gelecektir. Daha sonra iç gruplarda soldan sağa doğru artan indisler alacaktır. Bir gruba şu şekilde isim verebiliriz.

(?<firstWord>\w+)\s\d*

Düzenli ifademizdeki tüm grupların değerlerine ve indislerine Match tipinde bir nesne üzerinden aşağıdaki örnekteki gibi ulaşabiliriz.

Match match = Regex.Match(input, pattern);

string degeri = match.Groups[1].Value;

int indis = match.Groups[1].Index;

Grupların en çok işimize yarayacağı durum backreference’ların kullanımıdır. Backreference’ler bir regular expression içinde tekrar eden yapıların gruplar vasıtasıyla tekrar yazılmadan kullanılmasını sağlayan yapılardır. Temel de iki çeşit backreference vardır.

Numbered Backreference :

Numbered backreference’da daha önce belirttiğimiz grubu tekrar yazmak yerine bir sayı aracılığıyla refere ederiz. Bir örnek vermek gerekirse

(\w+)\s\1

Bu regular expression’da \1  (\w+) grubunu refere etmektedir. Yani ifade (\w+)\s(\w+) şeklinde düşünebilir.

Eğer örneğimizde \1 yerine \2 yazmış olsaydık, ikinci bir grubumuz olmadığı için compiler bir hata mesajı verecek ve uygulamamızı derlememize engel olacaktı.

Numbered backreference ile karşılaşacağımız bir sıkıntı kullandığımız rakamların gerçek değerler ile çakışması ihtimalidir. Yani kullandığımız rakam bir backreference da olabilir bir octal kod da. Bu yüzden rakamların yorumlanmasında bir takım kurallar mevcuttur.

  1. \1 ve \9 arasındaki değerler herzaman backreference olarak yorumlanır.
  2. Birden fazla basamaklı bir sayının ilk rakamı 8 veya 9 ise (\81, \90 vb) normal değer olarak yorumlanır.
  3. \10 dan büyük değerler grup var ise backreference yok ise octal kod olarak yorumlanır.

Named Backreference :

Named backreference yukarıda bahsettiğimiz rakam karmaşıklıklarından kurtulamamızı sağlar. Named Backreference’da grubumuza bir isim veririz ve önceki örnekde rakamla ulaştığımız gibi bu kez grubumuza grubun ismiyle ulaşırız. Bir önceki örneğin named backreference gösterimi aşağıdaki gibi olacaktır.

(?<grubum>\w+)\s\k<grubum>

bu kez gördüğümüz gibi grubum adını verdiğimiz gruba ulaşmak için \k<grubum> şeklinde bir yapı kullandık.

www.mehmetkordaci.com

Bu aralar ciddi anlamda kafayı regular expression’larla bozmuş durumdayım. Ne kadar yetenekli olduklarını gördükçe daha da ayrıntısına girmeye başladım. Ama artık bu ifadelerle boğulmak üzere olduğumu farkedince durmam gerektiğini hissettim. Ama durmadan önce de sizlere yararlı olabileceğini düşündüğüm birşeylerden bahsetmek istiyorum.

Lookaround’a isminden de anlaşılacağı üzere özetle bir regular expression’ın öncesi ya da sonrasını da kontrol etmemizi sağlayan yapı diyebiliriz. Vereceğimiz örnekle kafanızda daha net şekilde canlanacaktır. 2 çeşit lookaround’dan bahsedebiliriz. Bunlar Lookahead ve Lookbehind.

Lookahead :

Lookahead verilen regular expression’dan sonra neyin gelmesini ya da gelmemesini belirlemek istediğimizde kullandığımız yapıdır.  Örneğin input string’imiz “Kara Kartal Karşınızda” olsun. Ben bu string içinde Kar kelimesini aramak istiyorum ama bu Kar kelimesinden sonra a harfi gelmesini istemiyorum. Bu durumda kullanacağım regular expression

Kar(?!a)

şeklinde olacak. Bu şekilde kurduğumuz yapıya negatif  lookahead diyoruz. Negatif lookahead yapısını ?! karakterleriyle oluşturuyoruz ve sonra a harfi gelmemesini istediğimizi belirtiyoruz. a harfi yerine başka bir regular expression’da kullanabilirdik. Örneğimizde gerçekleşecek olan eşleşmeler Kartal’daki ve Karşınızda’daki Kar kelimeleridir.

Bu örneğimiz negatif lookahead olduğuna göre bunun bir de pozitifi olması gerekir. Pozitif lookahead’de ise sonrasında ne gelmesini istediğimizi belirtiyoruz. Bunu ise ?= karakterleri ile yapıyoruz. Önceki input’umuzda bu kez aşağıdaki regular expression’ı kullanalım.

Kar(?=a)

Bu durumda sadece Kara kelimesindeki Kar kısmını eşleyecektir.

Lookbehind :

Lookbehind, lookaround ile aynı mantıkta olmakla beraber bu kez verdiğimiz yapının  öncesinde ne olup olmamasını belirlememize yardım eder.

Bu kez input string’imiz “Kandırdım Sandım” olsun. İlk olarak negatif lookbehind yapalım. Negatif lookbehind yapmak için ?<! karakterlerini kullanırız. Regular expression’ımızı aşağıdaki şekilde düzenleyelim.

(?<!K)an

Bu durumda sadece Sandım kelimesindeki an eşleşecektir. Aynı şekilde pozitif lookahead yapmak için ?<= karakterlerini kullanırız. Bu kez aynı input için regular expression’ımızı aşağıdaki şekilde belirleyelim.

(?<=K)an

Bu durumda ise sadece Kandırdım kelimesindeki an regular expression’ımız ile eşleşecektir.

Bundan sonraki yazılarımda Groups ve Balancing Groups konularından bahsetmeyi planlıyorum. Bu ve diğer konularda sorularınız varsa yorum kısmından elimden geldiğince yardımcı olmaya çalışırım. Şimdilik bol kodlu günler.

www.mehmetkordaci.com

ASP.Net ile web uygulamalarımız geliştirirken kimi zaman kontrollerin çalışma şekillerini değiştirmek isteyebiliriz. Kontrollü biraz daha özelleştirmek isteyebiliriz. Bu işlemi kontrolü sayfamızın üstüne attıktan sonra sayfamızın koduna eklemeler yaparak gerçekleştirebiliriz. Ama peki başka bir sayfada daha aynı kontrolü kullanacaksak ne yapacağız. Böyle bir durumda kodları ilk sayfamızdan diğerine kopyalamamız gerekecek. Bu sorunu da böyle hallettikten sonra kontrolümüzü bir çok sayfada kullandık. Peki kontrolümüzün bir özelliğinde değişiklik yapacaksak ne olacak? Eklediğimiz bütün kodları teker teker değiştireceğiz. Daha sonra iş arkadaşınız kendi uygulamasında aynı özelleşmiş kontrolü kullanmak istediğinde ona kontrolün arkasına yazdığımız kodları göndermemiz gerekecek. İşte bu ve buna benzer sorunlardan kurtulmak için kendi ASP.Net Server Kontrollerimizi yazarız.

Bu makalede uygularımızda kullanabilmek için Sayısal Textbox kontrolü oluşturucağım. Sayısal karakterlerin tesbitinde javascript kullanacağım için, javascript bilginiz olması bir avantaj olacaktır. Amacımız custom kontrolleri oluşturmayı anlamak olduğu için çok ayrıntılı bir kontrol yapmayacağım, ama siz bu başlangıcın üzerine eklemeler yaparak istediğiniz hale getirebilirsiniz. Bu konuda karşınıza çıkacak sorunlarda yardımcı olmaya çalışırım.

Öncelikle Visual Studio’da bir web uygulaması açalım. Daha sonra solution’a bir tane ASP.NET Server Control Projesi ekleyelim (Ben NumericTextbox adını verdim.) Kontrolümüzün adını da ServerControl1′den NumText’e değiştirdim.

Kontrolümüzün class dosyasını açtığımızda class’ımızın WebControl class’ından türediğini görebiliriz. Ama ben burada TextBox’ın özelleşmiş bir halini kullanacağım için ve TextBox kontrolünün birçok özelliğini kullanacağım için sınıfımı TextBox class’ından türeteceğim. Bu nedenler WebControl yerine TextBox yazıyoruz. Ayrıca class’ımıza bir adet property eklendiğini ve bu property’nin de default olarak atandığını görebiliriz. Ama biz bu propertyleri Textbox’dan alacağımız için DefaultProperty attribute’unu ve Text property’sini siliyoruz.

Class’ımızın hemen üstünde bulunan

[ToolboxData("<{0}:NumText runat=server>")]

attribute’u ise kontrolü sayfamıza attığımız da markup kodunda kontrolümüzün kodunun nasıl gözükeceğini belirtir. {0} yerine istediğimiz bir prefix yazabiliriz. Şimdilik biz bu şekilde bırakıp işleri ASP.Net’e bırakıyoruz.

Artık biraz kod yazma vakti geldi sanırım. Öncelikle bastığımız karakterleri kontrol edecek javascript kodumuzu yazalım. Javascript kodu ile ilgili işlemleri RegisterJavaScript fonksiyonu ile yapıyoruz.

?View Code JAVASCRIPT
        private void RegisterJavaScript()
        {
            string script = @"
          <SCRIPT language='javascript'>
          function GetNumeric(obj,event)
             {
                var unicode=event.charCode? event.charCode : event.keyCode;
                innerText=obj.value;          
		        if((unicode >= 48 && unicode <= 57) || // 0-9
                   (unicode >= 37 && unicode <= 40) || // yukarı,aşağı,sağ,sol
                   unicode == 8 || // backspace
                   unicode == 46)
		           {
                     event.returnValue=true; 
		           }
                   else if(unicode==9)
                   {
                     event.returnValue=true;              
                   }
                   else
                     event.returnValue=false;
 
             }
            </SCRIPT>";
            script += "\n<SCRIPT language='javascript'>\n";
            script += "function NumericTextBoxOnKeyDown(obj,event){\n";
            script += "GetNumeric(obj,event);\n";
            script += "}\n";
            script += "</SCRIPT>\n";
            if (!Page.ClientScript.IsClientScriptBlockRegistered(this.GetType(), "NumericTextBox"))
            {
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "NumericTextBox", script);
            }
        }

Bu fonksiyonda basılan karakter sayısal tuşler ise ya da yön tuşları ise işleme alan değilse almayan bir script yazdık. Daha sonra da bu script’i sayfamıza ekleyen kodu yazdık.

Klavye’de basılan tuşları masaüstü uygulamarında rahatça takip edebiliriz ama Asp.Net kontrollerinde bu işlemleri Web de yapmamızı sağlayacak Client eventleri yok. Bu yüzden kontrolün Render metodunu override edip, içinde keydown olayını kontrolümüze eklememiz gerekir.

?View Code CSHARP
        protected override void Render(HtmlTextWriter writer)
        {
            Attributes.Add("onkeydown", "NumericTextBoxOnKeyDown(this,event)");
            base.Render(writer);
        }

Bir şeyi dikkatinizi çekmiştir. NumericTextBoxOnKeyDown javascript fonksiyonunu kullanmamıza rağmen sayfamıza henüz eklemedik. Bunun için ise OnPreRender metodunu override edeceğiz ve RegisterJavaScript fonksiyonunu çağıracağız.

?View Code JAVASCRIPT
    protected override void OnPreRender(EventArgs e)
    {
      base.OnPreRender(e);
      RegisterJavaScript();
    }

Solution’ın tamamımını derledikten sonra web uygulamamızda bir sayfa açalım. Toolbox’a baktığımızda kontrolümüzün en üst kısımda eklendiğini görebiliriz. Kontrolü sayfamıza atalım ve uygulamamızı çalıştıralım. Gördüğümüz gibi artık içine sadece sayıları girebildiğimiz bir kontrolümüz oldu.

Şimdi de kontrolümüze bir property ekleyelim. Bu property kontrole kaç tane sayı girilebileceğini belirlesin. Böylece uygulama geliştiriciye design time’da kaç tane sayı girilebileceğini belirtme şansı vermiş oluruz.

?View Code CSHARP
       private int _KacSayi = 10;
        public int KacSayi
        {
            get
            {
                return _KacSayi;
            }
            set
            {
                _KacSayi = value;
            }
        }

Bu property’i ekledikten sonra RegisterJavaScript fonksiyonunu biraz değiştirmemiz gerekli. GetNumeric javascript fonksiyonunu aşağıdaki hale getiriyoruz.

?View Code JAVASCRIPT
          function GetNumeric(obj,event)
             {
 
                var unicode=event.charCode? event.charCode : event.keyCode;
                innerText=obj.value;   
                if(innerText.length < "+ KacSayi + @" ) 
                { 
		        if((unicode >= 48 && unicode <= 57) || // 0-9
                   (unicode >= 37 && unicode <= 40) || // yukarı,aşağı,sağ,sol
                   unicode == 8 || // backspace
                   unicode == 46)
		           {
                     event.returnValue=true; 
		           }
                   else if(unicode==9)
                   {
                     event.returnValue=true;              
                   }
                   else
                     event.returnValue=false; 
                    }
                    else
                    {
                       event.returnValue=false; 
                    }
 
             }

Tekrar rebuild all ettikten sonra, sayfamızda kontrolümüze sağ tıklayıp özelliklerine baktığımızda eklediğimiz property’nin özellikler penceresine geldiğini görürüz.

Böylece kendi özelleşmiş kontrolümüzü yazmış oluyoruz. Yeni client side olaylar, property’ler ve fonksyisonlar ekleyerek çok daha güzel bir hale getirebilirsiniz. Gerisi ihtiyaçlarınıza ve hayal gücünüze kalmış.

Veritabanı Group_Concat,Concat,Replace,Trim Fonksiyonları

Uygulamalarımızda kimi zaman veritabanından gelen veriler üzerinde değişiklik yapma ihtiyacı duyarız. Bu değişiklikler uygulama tarafında yapılabilir. Ancak performans arttırmak gibi sebepler nedeniyle bunları veritabanı tarafında yapmak isteyebiliriz. Bu yüzden  veritabanından veri çekerken, gelen veriler üzerinde değişiklik yapmanızı sağlayacak ve işlerinizi kolaylaştıracak 4 fonksiyondan bahsetmek istiyorum.

GROUP_CONCAT :

Group_Concat fonksiyonu Oracle ve Mysql’de bulunmaktadır.  Veritabanı sorgusundan dönen satırları istediğimiz ayıraç ile ayırıp tek satır halinde göstermemizi sağlar.

Örneğin

my_id my_field my_type
1 alan1 1
2 alan2 1
3 alan3 2
4 alan4 1
5 alan5 2
6 alan2 1

SELECT my_field FROM my_table where my_type=1

Sorgusu

my_field
alan1
alan2
alan4
alan6

sonucunu döndürür.Ancak

SELECT GROUP_CONCAT(my_field SEPERATOR ‘,’) FROM my_table where my_type=1

sorgusu

alan1,alan2,alan4,alan6

sonucunu döndürür. Devamını okuyun »

NET ile Kullanıcı Kontrolleri

"http://www.w3.org/TR/html4/loose.dtd">

XPO ile O\R MAPPING -3

   Merhabalar, bu makale serimizde Object Relational Mapping kavramından ve DevExpress ürün ailesine ait XPO ile temel veritabanı işlemlerimizi nasıl yapabileceğimizden bahsedeceğiz.

İlişkiler:

Veritabanı uygulamalarımızda her zaman tek tabloyla çalışmadığımız için XPO’da da birden fazla tabloyla çalışmamızı ve aralarında ilişkiler kurmamızı sağlayan yapılar var. XPO’da tablolar arası ilişki kurmak istediğimizde bunu bu tablolara ait sınıflarımızı oluştururken Association anahtar sözcüğüyle oluşturuyoruz. Ancak bire bir ilişkiler de Association sözcüğünü kullanmak yerine ilişki içinde bulunan her iki sınıfta da diğer sınıf türünden bir nesne oluşturmamız yeterli oluyor.

Bu ilişkilerde cascading ise Association deyiminin içine yazacağımız Aggregated sözcüğü ile sağlıyoruz. Eğer Aggregated yazmassak silme ve güncelleme işlemlerini yapıyor. Yazdığımız takdirde ise diğer tablolarla ilişki içinde olduğu için bu işlemlere izin vermiyor.

 

[ Aggregated , Association ( "FK_Address_Person" , typeof ( Address ))]

 

Aggregated: Cascading’i sağlıyor.

FK_Address_Person: İlişkimizin ismi.

Address: Diğer sınıfın ismi. Bir nevi ilişki kurulacak tablo da denilebilir.

 

Bire bir ilişkiyi sınıfımızda gösterme:

İlişkideki ilk sınıfımız:

 

public class Ev : XPObject

{

public Ev() {

}

public Ev( Session session) :

base (session) {

}

 

 

[ Aggregated , Association ( "FK" , typeof ( Insan ))]

Insan owner = null ;

public Insan Owner

{

get { return owner; }

set

{

if (owner == value )

return ;

Insan prevOwner = owner;

owner = value ;

 

if (prevOwner != null && prevOwner.House == this )

prevOwner.House = null ;

 

if (owner != null )

owner.House = this ;

}

}

}

Diğer sınıf:

public class Insan : XPObject

{

 

public Insan() {

}

public Insan( Session session) :

base (session) {

}

 

 

[ Aggregated , Association ( "FK" , typeof ( Ev ))]

Ev house = null ;

public Ev House

{

get { return house; }

set

{

if (house == value )

return ;

 

Ev prevHouse = house;

house = value ;

 

if (prevHouse != null && prevHouse.Owner == this )

prevHouse.Owner = null ;

 

if (house != null )

house.Owner = this ;

}

}

}

1 e Çok ilişki:

public class Person : XPBaseObject

{

private int fId;

[ Key ( true )]

public int ID

{

get { return fId; }

set

{

if ( value == ID) return ;

fId = value ;

}

}

 

public Person()

{

Name = "" ;

}

public string Name;

[ Aggregated , Association ( "FK_Address_Person" , typeof ( Address ))]

public XPCollection Addresses

{

get { return GetCollection( "Addresses" ); }

}

}

Diğer Sınıf:

public class Address : XPBaseObject

{

private int fId;

[ Key ( true )]

public int AID

{

get { return fId; }

set

{

if ( value == AID) return ;

fId = value ;

}

}

 

 

public Address()

{

AddressInfo = "" ;

}

public Address( string addr)

{

AddressInfo = addr;

}

[ Association ( "FK_Address_Person" )]

public Person ID;

public string AddressInfo;

}

Bire çok ilişkinin bire bir ilişkiden farkı Association kullanmamız. Association sözcüğünün hemen altında da diğer sınıfa ait nesnemiz var. 1 çok ilişkide bir diğer ayırt edici özellikte Çok olan kısımda bir XPCollection kullanmamız böylece bir tablodaki bir veri için diğer tablodan birden fazla veri getirebiliyoruz.

Çoka Çok İlişki:

Çok çok ilişkide aynı bire çok ilişki gibidir. Tek farkı bu sefer iki sınıfta da Association’ın iki ucuda XPCollection’dır. Bireçok ve çokaçok ilişkilerdeki bu XPCollection’lar diğer sınıf türündedir.

 

Transaction:

XPO’da transaction’ı sessionlar aracılığıyla yapıyoruz. Bu işlemi yaparken 3 metod kullanıyoruz. Bunlardan ilki transaction’ı başlatmamızı sağlayan BeginTransaction, bundan sonra ekleme silme güncelleme işlemlerimizi yaptıktan sonra CommitTransaction metodu ile tamamlıyoruz. Eğer bir problem olursa bunu yakalayıp RollbackTransaction metodu ile yaptığımız değişiklikleri geri alıyoruz.

 

using (Session session = new Session()) {

session.BeginTransaction();

try {

// ekleme silme güncelleme işlemleri

session.CommitTransaction();

}

catch {

session.RollbackTransaction();

throw;

}

}

Validation:

XPO ile validation işlemlerinde öncelikle Exception sınıfından türeyen bir sınıf oluşturuyoruz. Bu sınıfımızda da constructor metodumuzda vereceğimiz uyarıyı belirtiyoruz.

Daha sonra XPO ile bize sağlanan OnDeleted, OnDeleting, OnLoaded, OnLoading, OnSaved, OnSaving metodlarından birini tekrar yazarak kontrolü ne zaman yapacağımızı, hangi kontrolü yapacağımızı ve oluşturacağımız exception’ı belirliyoruz.

public class RequiredPropertyValueMissing: Exception

{

public RequiredPropertyValueMissing(XPObject theObject, string propertyName):

base(String.Format("The {0} property of the {1} object with id {2} must have a

value", propertyName, theObject.GetType().Name, theObject.Oid))

{

}

}

 

public class Company : Person {

public string Name = "";

protected override void OnSaving() {

if (Name == "")

throw new RequiredPropertyValueMissing(this, "Name");

}

}

 

        Bu makale serimizde O/R Mapping kavramından ve bunun XPO ile nasıl yapılabilceğinden bahsetmeye çalıştım. Konuyla ilgili veya diğer her türlü sorunuz için mail adresimden bana ulaşabilirsiniz. Bir başka makalede buluşmak üzere.

 

Her türlü sorunuzu metkor@gmail.com dan iletebilirsiniz.

Referans: www.devexpress.com/XPO


© 2010 bilyaz.com , Programlama Makaleleri, Yazılım Makaleleri , Örnek Kodlar , Eğitim Videoları , C#,ASP.NET,SQL,PHP Suffusion WordPress theme by Sayontan Sinha