Arşiv

Etiketlenen yazılar ‘override’

C# ile Form’a gölge efekti verelim ve titreme sorununu düzeltelim

Windows Forms uygulamalarında Form‘un gölge efektine sahip olmasını istiyorsak, öncelikle Form‘un FormBorderStyle özelliğini None yapmalıyız.

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

Form sınıfının CreateParams özelliğini override etmemiz gerekiyor. CreateParams özelliği geriye CreateParams tipinde bir nesne döndürür.

protected override CreateParams CreateParams
{
	get
	{
		CreateParams cp = base.CreateParams;

		cp.ClassStyle |= 0x20000;

		return cp;
	}
}

CreateParams sınıfının ClassStyle özelliğine 0×20000 değerini ekliyoruz. Böylece formumuz çalışmaya başladığında etrafında gölge gözüküyor.

Gölgeli Form

Form üzerine çok fazla kontrol eklediğimizde, özellikle eğer kontroller hafızada çok yer kaplayan 3.parti kontrollerden ise; formumuzda titreme diyebileceğimiz bir efekt oluşmaya başlar.

Çoğu zaman bu durum rahatsızlık oluşturma derecesine kadar varır.

Bu sorunu çözmek için, kontrollerin DoubleBuffered özelliğini true değerine ayarlamamız gerekmektedir.

Fakat DoubleBuffered özelliği Form sınıfının değil Control sınıfının bir özelliği olduğundan dolayı, Form’un titremesini gidermek için kullanamayız.

Form sınıfının CreateParams özelliğinde bu sorunu da çözebiliriz;

protected override CreateParams CreateParams
{
	get
	{
		CreateParams cp = base.CreateParams;

		cp.ExStyle |= 0x02000000;

		return cp;
	}
}

Bu sefer CreateParams sınıfının ExStyle özelliğine 0×02000000 değerini eklememiz gerekiyor.

Örnek uygulamanın tüm kodu;

protected override CreateParams CreateParams
{
	get
	{
		CreateParams cp = base.CreateParams;

		cp.ClassStyle |= 0x20000;

		cp.ExStyle |= 0x02000000;

		return cp;
	}
}

C# Programımızın Ekrandaki Yerini Hatırlaması

10 Mart 2010 Engin POLAT 1 Yorum

C# ile yazdığınız uygulamanın her açılışta bir önceki kapatıldığı yerde açılmasını isteyebilirsiniz.

Aslında gayet basit olan bu işi yaparken düşünmemiz gereken bazı detaylar var. Mesela;

Ya uygulama kapatıldıktan sonra kullanıcı windows’un çözünürlüğünü değiştirdiyse?

Kullanıcı birden fazla monitör kullanıyorsa, ve uygulama kapatıldıktan sonra monitörlerin ayarlarını değiştirdiyse?

Hem bu noktaları gözönünde bulunduracak, hem de kolay şekilde programlanacak bir çözümü aşağıda kodladım;

Öncelikle formumuz kapatılırken, tam olarak bulunduğu noktayı bir yere kaydetsin. Bunu uygulamanın Settings penceresine iki tane özellik ekleyerek yapalım;

FormLocation ve FormSize

Formumuzun base class‘ı olan Form class‘ından gelen OnClosing virtual method’unu override edelim;

protected override void OnClosing(CancelEventArgs e)
{
	Properties.Settings.Default.FormLocation = this.Location;
	Properties.Settings.Default.FormSize = this.Size;
	Properties.Settings.Default.Save();

	base.OnClosing(e);
}

Uygulamamızın Settings penceresinden eklediğimiz property‘lere

Properties.Settings.Default

ile ulaşabiliriz.

Şimdi, form’umuzun base’den gelen OnLoad virtual method‘unu override edelim ve açıldığında eski yerine konumlanmasını sağlayalım;

protected override void OnLoad(EventArgs e)
{
	base.OnLoad(e);

	Point konum = Properties.Settings.Default.FormLocation;
	Size boyut = Properties.Settings.Default.FormSize;

	bool isOnScreen = false; /// Formun gözükür olup-olmadığını kontrol edelim
	foreach (Screen screen in Screen.AllScreens)
		if (screen.WorkingArea.Contains(konum))
			isOnScreen = true;

	if (!isOnScreen) ///Eğer formumuz görünür değilse, görünür yapalım
		this.SetDesktopLocation(Screen.PrimaryScreen.WorkingArea.Left, Screen.PrimaryScreen.WorkingArea.Top);

	if (boyut.Width < 10 || boyut.Height < 10) /// Formun boyutları çok küçükse, normal hale geri getirelim
		this.Size = new Size(300, 300);
}

Yukarıdaki kod parçalarını sizler de kendi uygulamalarınızda kullanabilirsiniz.

Kalıtımı engellemek (sealed anahtar kelimesi)

Yazdığınız bir sınıftan kalıtım yoluyla başka sınıflar üretilmesini engellemek istiyor olabilirsiniz.

Yapmanız gereken sınıfınızı sealed anahtar kelimesi ile “mühürlemek” olmalıdır. Böylece sınıfınızdan yeni sınıflar türetilemeyecektir.

sealed class AnaSinif
{
// Sınıf üyeleri
}

AnaSinif class‘ımız sealed olduğu için, yeni sınıf türetilirken base class olamayacaktır;

class TuretilmisSinif : AnaSinif
{
// Derleme zamanında hata oluşur (compile-time error)
}

Not : struct’lar her zaman sealed ile mühürlenmiş gibi davranırlar. struct’lar kalıtım (inheritance) desteklemez

Tüm sınıfın kalıtım yoluyla aktarılmasını engellemek yerine, tek bir method’un override edilmesini engellemek istiyor olabilirsiniz.

Bu durumda yapmanız gereken, sadece ilgili method‘u sealed ile “mühürlemek” olmalıdır;

class AnaSinif
{
	public virtual void Goster()
	{
	}
}

class TuretilmisSinif : AnaSinif
{
// Bu kodda problem yok
// AnaSinif'tan gelen Goster() method'unu override eder
// Aynı zamanda sealed ile "mühürler"
	public sealed override void Goster()
	{
	}
}

class TekrarTuretilmisSinif : TuretilmisSinif
{
// Bu kod derlenmez. Hata oluşur
// TuretilmisSinif class'ında Goster() method'u sealed anahtar kelimesi ile "mühürlenmişti"
	public override void Goster()
	{
	}
}

FileStream sınıfına Kaydet() ExtensionMethod’u yazalım

FileStream sınıfına yazacağımız Save() method’u sayesinde, aşağıdaki kodu kolaylıkla yazabilir olacağız. Üstelik bir tane de overload yazarak, varolan dosyanın üstüne yazmasını engelleyip, yeni bir dosya adı oluşturup yazma işlemine devam ettirebileceğiz.

fs.Kaydet("c:\\dosya_adi.uzanti");

Eğer aynı kodu, ikinci bir boolean parametreye true değeri vererek çağırırsak, klasörde dosya_adi.uzanti dosyası varsa dosya_adi[1].uzanti dosyasına yazmayı deneyecek, eğer bu dosya da varsa, dosya_adi[2].uzanti dosyasına deneyecek, vs..

fs.Kaydet("c:\\dosya_adi.uzanti", true);

İşte kodumuz;

namespace ExtensionManager
{
	public static class Extensions
	{
		public static string Kaydet(this FileStream Dosya, string Dizin)
		{
			return Dosya.Kaydet(Dizin, false);
		}

		public static string Kaydet(this FileStream Dosya, string Dizin, bool UstuneYaz)
		{
			int DosyaSayac = 1;

			string _Dizin = Path.GetDirectoryName(Dizin);

			if (!Directory.Exists(_Dizin))
				Directory.CreateDirectory(_Dizin);

			int DosyaBoyu = Convert.ToInt32(Dosya.Length);
			string DosyaAdi = Path.GetFileName(Dosya.Name);

			Byte[] b = new Byte[DosyaBoyu];
			Dosya.Read(b, 0, DosyaBoyu);

			string root = Path.GetDirectoryName(Dizin) + "\\" + Path.GetFileNameWithoutExtension(Dizin);

			while (!UstuneYaz && File.Exists(Dizin))
				Dizin = root + "[" + DosyaSayac++.ToString() + "]" + Path.GetExtension(Dizin);

			File.WriteAllBytes(Dizin, b);

			return Path.GetFileName(Dizin);
		}
	}
}

virtual olmayan method’ları override etmek

Base class‘ta tanımlanmış bir method‘u override etmemiz gerekiyor. Fakat method virtual yazılmamışsa, override edilemez. Türetilmiş class‘ta base class‘taki virtual olmayan method’u nasıl override edebiliriz?

Türetilmiş class’ta base class’taki method’u override etmek yerine new anahtar kelimesi ile baştan yazabiliriz. Böylece virtual yazılmamış ve dolayısıyla override edilemeyecek method’ları “bir çeşitoverride etmiş oluruz.

class Base
{
	public virtual void VirtualGoster()
	{
		Console.WriteLine(“Base.VirtualGoster”);
	}

	public void Goster()
	{
		Console.WriteLine(“Base.Goster”);
	}
}

class Derived : Base
{
	public override void VirtualGoster()
	{
		Console.WriteLine(“Derived.VirtualGoster”);
	}

	public new void Goster()
	{
		Console.WriteLine(“Derived.Goster”);
	}
}

class Program
{
	static void Main(string[] args)
	{
		Base base = new Derived();
		base.VirtualGoster();
		base.Goster();

		Console.WriteLine();

		Derived derived = new Derived();
		derived.VirtualGoster();
		derived.Goster();
	}
}

Çıktı :
Derived.VirtualGoster
Base.Goster
Derived.VirtualGoster
Derived.Goster

C# ile Kes-Kopyala-Yapıştır Olaylarını Fırlatan Textbox

.Net Framework’ün Textbox‘ı bir çok kullanışlı event‘i kullanımımıza sunmuştur. Böylece programcılar olarak kod yazmak için seçebileceğimiz geniş bir olay kütüphanesi vardır. Mesela TextChanged olayına ayrı, KeyDown olayına ayrı, KeyUp olayına ayrı kod yazabiliriz.

Fakat nedense, textbox’tan metin kopyalarken/keserken veya textbox’a metin yapıştırırken fırlatılan bir olay yoktur. Çeşitli sebeplerle projelerimizde Kes-Kopyala-Yapıştır olaylarını fırlatan bir textbox’a ihtiyaç duyabiliriz.

Textbox kontrolüne özel event’ler eklemek için, yeni bir class oluşturup, Textbox class’ından türemesini sağlamalıyız.

public partial class GelismisTextBox : TextBox
{
}

Windows‘un sunduğu Kes-Kopyala-Yapıştır olaylarını GelismisTextbox class’ımızda yönetebilmek için WndProc() method’unu override etmemiz lazım.

private const int WM_CUT = 0x0300;
private const int WM_COPY = 0x0301;
private const int WM_PASTE = 0x0302;

protected override void WndProc(ref Message m)
{
	switch(m.Msg)
	{
		case WM_CUT:
			/// Kes komutu olayını fırlat
			break;
		case WM_COPY:
			/// Kopyala komutu olayını fırlat
			break;
		case WM_PASTE:
			/// Yapıştır komutu olayını fırlat
			break;
		default:
			base.WndProc(ref m);
			break;
	}
}

Şimdi yapmamız gereken, GelismisTextbox class’ımıza olayları fırlatacak kodu eklemek.

public class ClipboardEventArgs : EventArgs
{
	private string clipboardText;
	public string ClipboardText
	{
		get { return clipboardText; }
		set { clipboardText = value; }
	}

	public ClipboardEventArgs(string clipboardText)
	{
		this.clipboardText = clipboardText;
	}
}
public delegate void ClipboardEventHandler(object sender, ClipboardEventArgs e);

public event ClipboardEventHandler CutText;
public event ClipboardEventHandler CopiedText;
public event ClipboardEventHandler PastedText;

Artık GelismisTextbox kontrolünü projemizde kullanabiliriz. GelismisTextbox kontrolünde yapılacak Kes-Kopyala-Yapıştır işlemleri esnasında fırlatılacak olaylara ilişkin kodlarda yazabiliriz. Örneğin;

private void txtOrnek_CutText(object sender, ClipboardEventArgs e)
{
	MessageBox.Show("Gelişmiş Textbox'tan kesilen : " + e.ClipboardText);
}
private void txtOrnek_CopiedText(object sender, ClipboardEventArgs e)
{
	MessageBox.Show("Gelişmiş Textbox'tan kopyalanan : " + e.ClipboardText);
}
private void txtOrnek_PastedText(object sender, ClipboardEventArgs e)
{
	MessageBox.Show("Gelişmiş Textbox'a yapıştırılan : " + e.ClipboardText);
}

GelismisTexbox class’ının kodu;

public partial class GelismisTextBox : TextBox
{
	private const int WM_CUT = 0x0300;
	private const int WM_COPY = 0x0301;
	private const int WM_PASTE = 0x0302;

	public delegate void ClipboardEventHandler(object sender, ClipboardEventArgs e);

	public event ClipboardEventHandler CutText;
	public event ClipboardEventHandler CopiedText;
	public event ClipboardEventHandler PastedText;

	protected override void WndProc(ref Message m)
	{
		switch(m.Msg)
		{
			case WM_CUT:
				if (CutText != null)
					CutText(this, new ClipboardEventArgs(this.SelectedText));
				break;
			case WM_COPY:
				if (CopiedText != null)
					CopiedText(this, new ClipboardEventArgs(this.SelectedText));
				break;
			case WM_PASTE:
				if (PastedText != null)
					PastedText(this, new ClipboardEventArgs(Clipboard.GetText()));
				break;
			default:
				base.WndProc(ref m);
				break;
		}
	}
}

public class ClipboardEventArgs : EventArgs
{
	private string clipboardText;
	public string ClipboardText
	{
		get { return clipboardText; }
		set { clipboardText = value; }
	}

	public ClipboardEventArgs(string clipboardText)
	{
		this.clipboardText = clipboardText;
	}
}