Category: programming

C#’ta ListBox ve CheckedListBox

Windows Formlarıyla çalışırken listbox(bundan sonra lb olarak anılacak) ve checkedlistbox’ları(bundan sonra chlb olarak anılacak) çok kullanıyorsanız bunlardaki eleman ekleme, çıkarma, seçme v.s gibi işlemleri ilk başlarda çok karışık bulabilirsiniz. Umarım bu gönderim bu konuya yeni girenler için faydalı olur.

Not:Aşağıda hem chlb hem lb’den herhangi birini kastetmek için Control ifadesini kullandım.

Edit:Kodlardaki kucuk buyuk isaretleri ve turnak isareti defalarca duzeltmeme ragmen garip cikiyor. Free uyelik oldugu icin bunlarin duzelmesini saglayan kodu da ekleyemiyorum malesef. Copy paste yaptiktan sonra kendiniz de replace edebilirsiniz.

İyi kodlamalar

A)Giriş

Aşağıdaki gibi bir form tasarlıycaz, en alttaki linkte kaynak solution dosyasına ait link bulunmaktadır. Soldaki gibi bir chlb’mız olacak  ve buna rastgele sayılar ekleyip çıkaracağız, sağda ise bir lb olacak, buna da çeşitli harfleri ekleyip çıkarıcağız, ayrıca soldaki kutudan buna transfer yapacağız.

chlb-ve-lb

B)Nedir, nasıl yapılır?

1.Kritik üyeler

1.1.Her iki Control için de ortak üyeler

Item: Control içindeki elemanın kendisidir. Dönüş değeri objedir, çünkü liste içindeki elemanlar belirli bi veri tipinden olmak zorunda değil; bi eleman integer iken bir diğeri string olabilir. Item, bir obje olduğu için bununla ilgili stringsel bir işlem yapılmadan önce ToString ile string değeri elde edilmelidir. Keza eğer hepsi numerikse ve matematiksel işlem yapılacaksa da Convert sınıfı ile uygun sayı tipine dönüştürülmelidir.

Items: Tüm elemanların koleksiyonudur. Genelde eleman ekleme, çıkarma ve sayma için kullanılır.

Index: Elemanların liste içindeki sırasıdır, tek başına bir kullanımı yok hatta böyle bir member bile yok, ancak SelectedIndices gibi bazı propertyler içine parametre olarak gider.

SelectedItem: Seçili elemanın kendisidir.

SelectedItems: Seçili elemanların koleksiyonudur.

SelectedIndex: Seçili olan(işaretli değil) kaydın indexini verir, integer döndürür. Genelde checkedListBox1.Items.RemoveaAt(…) içinde veya bir seçim yapılmış mı diye kontrol etmek için veya herhangi bir seçim varsa seçimi sıfırlamak için  (chlb.selectedindex = -1) kullanılır.

SelectedIndices: Seçili elemanların indexlerinin toplam grubunu verir, genelde kullanım şekli bu koleksiyonun dizi numarasını vererek bunu lb’tan çıkarma veya for/while/until/if ile bunun belli bir değerde olup olmadığını kontrol etme şeklindedir.

listbox1.Items.RemoveAt(listbox1.SelectedIndices[0])  veya

for (int i = listBox1.SelectedIndices.Count – 1; i >= 0; i–) gibi

ClearSelected:Tüm seçimleri kaldırır.

GetSelected(index): Verilen indexteki elemanın seçili olup olmadığını verir.

SetSelected(index,boolvalue): Verilen indexteki elemanı seçer(true ise), veya seçimi kaldırır(false ise)

1.2.Sadece cheklistbox için geçerli olan üyeler

CheckedItems: İşaretli elemanların bir koleksiyonunu verir.

ChekecedIndices: İşaretli elemanların indexlerinin bir koleskiyionunu verir

GetItemChecked(index): Verilen indexli elemanını işaretli olup olmadığını döndürür.

GetItemCheckState(index): Verilen indexli elemanını işaret durumunu gösterir (3 durumdan 1’i, seçili, seçil değil, gri seçili(yarı seçili yarı seçimsiz))

SetItemChecked(index,boolvalue): Verilen indexli elemanın işaretler veya işaretsiz bırakır

SetItemCheckState(index, checkstate): Verilen indexli elemana verilen işaret durumunu atar(3 durumdan 1’i)

1.3.Sadece listbox için geçerli olan üyeler

SelectionMode: Bir seferde tek eleman mı yoksa çoklu eleman mı seçileceğini belirtir. Çoklu seçimde kendi içinde ikiye ayrılır: Shift tuşuyla peşpeşe seçim yapılabilecekse MultiExtended, tek tek çoklu seçim yapılacaksa MultiSingle seçilir.

2.Çeşitli İşlemler

İşlemleri aşağıdaki gibi 3 gruba ayırabiliriz

  • Eleman ekleme-çıkarma(Tekli,çoklu,tüm)
  • Eleman seçme-seçimi kaldırma(Tekli,çoklu,tüm)
  • Bilgi edinme(Seçim durumu, işaret durumu, belirli bir eleman listede mi?)

2.1.Eleman ekleme

Her iki kontrol için de yöntem basit ve aynıdır:

Control.Items.Add(eleman)

veya bir List öğesi içindeki tüm elemanlar da her iki Controle eklenebilir.

var listem=new List<String>();
listem.Add("elma");
listem.Add("armut");
listem.Add("karpuz");
listBox1.SourceControl=listem

2.2.Eleman çıkarma

Remove: Parametre olarak elemanın kendisini alır

RemoveAt: Parametre olarak elemanın index numarasını alır. (index numarası genelde direkt bir numara değil de bun numarayı veren dolaylı bir ifade olur)

2.2.1.Tekil eleman çıkarma

Chlb’de işaretli elemanın listeden çıkarılması sözkonusyken, Selectedindexin benzeri bir Checkedindex özelliği olmadığı için RemoveAt yerine Remove kullanırız. Keza yine SelectedItem’a benzer bir CheckedItem olmadığı için chlb’da işaretli elamanı silmenin en basit yolu, onu işaret index nosu ile yakalayıp silmektir, yani ilk index no olan 0 ile.

checkedListBox1.Items.Remove(checkedListBox1.CheckedItems[0]);

lb’ta ise seçili elemanı çıkarma konusunda birden çok yöntem karşımıza çıkar. chlb için de seçili elemanın çıkarılma yöntemleri aynıdır, ama chlb’ta seçili elemandan ziyade daha çok işaretli elemanla ilgili işlemler yapılmaktadır.


//1.yöntem:seçilenin indexine göre
listBox1.Items.RemoveAt(listBox1.SelectedIndex);

//2.yöntem:zorlama bir yöntem ama teorik olarak olur. chlb'ta checkliler için de aynı mantıkla yapıyoruz
listBox1.Items.RemoveAt(listBox1.SelectedIndices[0]);

//3.yöntem:selecteditem
listBox1.Items.Remove(listBox1.SelectedItem);

//4.yöntem:yine zorlama bi yol, selecteditems ile
listBox1.Items.Remove(listBox1.SelectedItems[0]);

2.2.2.Çoklu eleman çıkarma

Eleman çıkarma konusunda MSDN bizi foreach döngüsü kullanmamamız gerektiği konusunda uyarıyor, foreach sadece elemanların üzerinden tek tek geçmek için kullanılmalı diyor. Çünkü foreach’te arkaplandaki collectionun içeriğini her defasında değiştirmiş ve enumaratorü bozmuş oluyoruz.

Normal for döngüsünde ise elemanların kendisi üzerinde değil indeksleri üzerinde hareket ettiğimiz için böyle bir sorunumuz olmuyor, bu yüzden normal for döngüsü veya aşağıda göreceğimiz diğer yöntemler kullanılabilir.

chlb için


for (int s = 0; s < checkedListBox1.CheckedItems.Count; s++)
{
checkedListBox1.Items.Remove(checkedListBox1.CheckedItems[s]);
s--;
}

lb için


//1.yöntem:for dögüsü. liste içeriğini değiştirme işlemleri for eachle olmuyor, foreach buna uygun değil, o yüzden normal for döngüsü yapıyoruz

for (int i = listBox1.SelectedItems.Count - 1; i <= 0; i--)
{
listBox1.Items.RemoveAt(listBox1.SelectedIndices[i]);
}

//2.yöntem while ile
while (listBox1.SelectedItems.Count < 0)
{
listBox1.Items.Remove(listBox1.SelectedItems[0]);//çoklu seçimlerde ilk seçili olan 0 indekslidir, biz de her defasında bu ilk seçili olanı siliyoruz, ta ki seçili kalmayana kadar
}

//3.yöntem yine while ile ama farklı türlü
while (listBox1.SelectedIndex != -1) //seçili kayıt olmayadığ sürece demek
{
listBox1.Items.RemoveAt(listBox1.SelectedIndex);
}

//4.yöntem
ListBox.SelectedObjectCollection secililer = new ListBox.SelectedObjectCollection(listBox1);
secililer = listBox1.SelectedItems;

for (int i = secililer.Count - 1; i <= 0; i--)
{
listBox1.Items.Remove(secililer[i]);
}

//5.yöntem:geçici olarak bi listte toplamak

ArrayList gecicidizi = new ArrayList();
foreach (object obj in listBox1.SelectedItems)
{
listBox2.Items.Add(obj);
gecicidizi.Add(obj);
}
foreach (object obj in gecicidizi.ToArray())
{
listBox1.Items.Remove(obj);
}

//6.yöntem:5.yönteme benzer şekilde geçici bir dizide toplamak
object[] silinecekler = new object[listBox1.SelectedItems.Count];
listBox1.SelectedItems.CopyTo(silinecekler, 0);

foreach (object item in silinecekler)
{
listBox1.Items.Remove(item);
}

2.2.3.Tüm elemanları çıkarma(Listeyi boşaltma)

//iki kontrol için de aynıdır
Control.Items.Clear();

2.3.Eleman seçme/işaretleme

2.3.1.Tek elemanı işaretleme ve seçme

İşaretleme:checkedListBox1.SetItemChecked(index, boolvalue): Sadece chlb’de geçerli. İlgili elemanı belirtilen check durumuna getirir, yani işaretli veya işaretsiz. Seçim için boolvalue olarak true demeliyiz. Buna benzer bir de SetItemCheckState(index, chekstate) var, bunun ikinci parametresi ise 3’lü enum değerleridir:seçili, seçimsiz, undetermined(gri seçimli)

Seçme: Her iki kontrolde de SetSelected(index,boolvalue) şeklinde kullanılır. boolvalue true olursa seçer, false olursa seçimi kaldırır

2.3.2.Çoklu Seçme/işaretleme

chlb’larda selectionmode özelliği multi yapılamıyor, o yüzden çoklu seçim yapamıyoruz, sadece işaretlemenin multisini yapacağız.

chlb’ın multi işaretlemesi şöyle(3-9 arası indexli elemanlar işaretlenecek)

for (int i = 3; i < 10; i++)
{
checkedListBox1.SetItemChecked(i, true);
}

lb’ın multi seçimi ise şöyle(chlb için de aynıdır)

for (int i = 3; i < 10; i++)
{
listBox1.SetSelected(i, b);
}

2.3.3.Tüm elemanları seçme/işaretleme

Bunun için özel bir metod yok, çoklu yöntemi kullanılır.

for (int i = 0; i < checkedListBox1.Items.Count; i++)
{
checkedListBox1.SetItemChecked(i, true);
}

2.4.Seçim/İşaret Kaldırma

2.4.1.Tek elemandaki seçimini/işaretlemeyi kaldırma

Her iki kontrolde de seçme/işaretleme sırasında true atadığımız parametreyi false atarız.

2.4.2.toplu seçim/işaret kladıma

2.4.2.1.lb’den toplu seçim kaldırma(chlb için de aynsı geçerli)

Seçili olanların seçimin iptal etmekle tüm kayıtları seçimsiz hale getirmek teorikte aynı şeydir, o yüzden tüm kayıtları seçimsiz hale getiren pratik kodlardan herhangi birini(aşağıdaki yöntemlerden ilk 2si) uygulayabiliriz, ancak seçimi kaldırırken başka işlemler de yapılacaksa döngü kullanmak gerekir.

//1.yöntem:inbulit metod ile
listBox1.ClearSelected();

//2.yöntem, olmayan kaydın seçimi
listBox1.SelectedIndex = -1;

//Bununla beraber seçimi kaldırırken aynı anda başka bir işlem de yapmak için for döngüsü kullanılabilir. Bu arada birçok yerde for döngüsünü listedeki tüm kayıtlar için yapıldığna dair örnek kodlar veriliyor, habluki doğrusu sadece seçili kayıtlar üzerinden gitmektir. küçük listelerde bu sorun teşkil etmez ama büyük bir liste varsa o zaman performans sorunu olabilir.
//3.yöntem:for döngüsü
for (int i = 0; i < listBox1.SelectedItems.Count; i++)
{
listBox1.SetSelected(listBox1.SelectedIndices[i], false);
i--;//i'nin hiç artmamasını sağlıyorum, böylece her iterasyonda hep 0. indexteki eleman üerinde işlem yapmış oluyorum
//burada diğer işlemler yapılabilir.
}
//4.yöntem:hep 0 indexli kaydın işaretini kaldırmanın bir yolu da while döngüsüdür
while (listBox1.SelectedItems.Count < 0)
listBox1.SetSelected(listBox1.SelectedIndices[0], false);
2.4.2.2.chlb için toplu İşareti kaldırma

chlb sözkonusu olduğunuda seçimleri kaldırırken kullandığımız ClearSelected gibi ClearChecked diye bir metod yok, ayrıca  -1’li indexi işaretlemek diye de bir seçenek yok, ama başka çözümler var tabiki, hemen aşağıda.

//1.çözüm:tüm kayıtların üzeirnden geçerek hepsindeki işareti kaldırmakak:dezanvantajı şu:yüzlerde kayıt varsa ve sen sadece seili olan 2-3 kayıttakini kaldımrak isityorsan boşuna tüm kayıltaır dolaşmış olursun, ama tabi yine de hepsi 1-2 sn'de seçilir
for (int i = 0; i < checkedListBox1.Items.Count ; i++)
{
checkedListBox1.SetItemChecked(i, false);
}
//2.çözüm:yinei for döngüsü ama bu sefer sadece seçil kayıtlar üzerinden geçmek
for (int i = 0; i < checkedListBox1.CheckedItems.Count; i++)
{
checkedListBox1.SetItemChecked(checkedListBox1.CheckedIndices[i], false);
i--;//i'nin hiç artmamasını sağlıyorum, böylece her iterasyonda hep 0. indexteki eleman üerinde işlem yapmış oluyorum
//burada diğer işlemler yapılabilir.
}

//3.yöntem:while döngüsü:hep işaretlilerden 0. indeksteki kaydın işaretini kadırıyoruz
while (checkedListBox1.CheckedIndices.Count < 0)
{
checkedListBox1.SetItemChecked(checkedListBox1.CheckedIndices[0], false);
}

 

C)Tüm Kod

Programın tamamına ait kodda başka bilgiler de var ancak nihai kod biraz uzun olduğu için buraya koymak yerine tüm solution dosyasını zipli olarak indirebileceğiniz bir link veriyorum, burdan indirebilirsiniz.

Duplike Finder

Selam Dostlar,

Bu gönderimde sizlerle ilk kapsamlı C# programımı paylaşmak istiyorum. İlk gönderimimde  belirttiğim rötuşlar da büyük ölçüde bitti. Yapılacak daha çok şey var tabii ki, ama bu haliyle de istenen sonuçlar elde edilebilmektedir. Buna beta sürümü diyorum zaten, bir sonraki sürümü inşallah WPF olarak hazırlıycam.

Herşey annemin “Oğlum bilgisayarımda birbirinin aynısı birsürü dosya var, şunları bi temizle bakalım” demesiyle başladı. Bu tür mükerrer(duplike) dosyaları bulan ve silen programlardan iki tanesini kurdum, ilki onlarca dosya buldu(toplam alanı 2 GB kadar) ama silmek için ücretli(PRO) versiyona geçmemi istedi, yani hiç sildirmedi. İkincisi ise hiç bulamadı 🙂 İkisini de kurduğum gibi kaldırdım, ve bunu acaba C# üzerinde yapabilir miyim diye düşündüm ve birkaç gün içinde bu kadar kolay olacağını düşünmediğim ana kodu yazdım. Ancak bunu daha görsel, daha işlevsel ve gerek görsellik gerek kod açısından daha zarif hale getirmem 2 ayımı aldı, tabiki bilfiil 2 ay değil, fırsat buldukça bakmaya çalıştım.

Neyse uzun lafın kısası programın beta sürümü şuan hazır ve buradan indirebilirsiniz. Öneri ve yorumlarınızı bekliyorum. (Not: Programı çalıştırdığınızda Windowsun guvenlik aracı engelleyebilir, bunun için çıkan pencerede Ek bilgi dugmesine basip devam edebilirsiniz.)

Genel Bakış

Giriş

İlk açılış ekranımız aşağıdaki gibidir. Burada sizden 3 ana bölümde seçme yapmanız bekleniyor.

1-Kriter Seçimi

Arama kriterini sizin yerinize hazır olarak seçtim. Temel olarak dosyanın değiştirilme tarihinin ve boyutunun aynı anda eşit olması dosyaların da büyük ihtimalle eşit olması anlamına gelecektir.(ilk başta oluşturma tarihi olarak yola çıktım ama sonra yaptığım testlerde bir dosyayı bir klasörden başka klasöre taşıyınca oluşturma tarihinin hemen o anın tarihine döndüğünü gördüm, o yüzden değiştirilme tarihini kullanmak daha mantıklı geldi)

Dosya adı alanını da ekledim ama bazen dosyaların isimlerini değiştirebiliyoruz, o yüzden bunları kaçırmış oluruz, ancak siz yine de “ben dosya adına göre de ararım” diyorsanız bunu da seçebilirsiniz.

Bir de Süper Arama seçeneği var. Yukarıda boyut ve tarih seçmeniz durumunda büyük ihtimalle aynı olacaktır demiştim, ama kesin olarak değil. Tesadüfen ikisi de aynı olduğu halde dosyalar farklı olabilir. Ancak bu süper arama seçeneği ise neredeyse kesine yakın(matematiksel olarak hata payı 10 üzeri 32’de 1) bir şekilde tarama yapar. Bu tarama türü, kesin eşleştirmeyi sağlayacak tek yöntem olan dosyayı “Byte Byte okumaya” göre daha efektiftir ama yine de ilk tarih-boyut taramasına göre daha yavaş çalışacaktır. Tarama sonunda her dosya için 29-B4-1C-B3-54-F3-14-19-16-EE-0D-6A-F5-73-56-9F-DA-3F-D5-47 gibi bir hashcode üretilir ve bunlar karşılaştırılır.

Örnek bir klasörde tarama yapıp kendi PC’niz için hızını farklı kombinasyonlar için test edebilirsiniz.

NOT: Birbirinin aynısı olup da bir şekilde boyutu faklı olan dosyalar var olabilir. Ör: iki şarkı da aynı şarkıcının aynı şarkısıdır ama biri CD’den mp3’e çevrilirken biri Youtube’dan dönüştürülmüş olabilir ve bir şekilde boyutları farklı çıkmıştır. Zaten böyle durumları ne benim ne de başka bir programın yakalaması mümkün değildir.

2-Klasör Seçimi

Hangi klasörlerde tarama yapmak istiyorsanız onları buraya ekleyin. Genelde müzik, resim veya video klasörlerini taramak iyi fikir olacaktır ancak isterseniz tüm diskinizi bile tarayabilirsiniz. Listeye birden fazla klasör ekleyebilirsiniz.

3-Dosya türleri(uzantı seçimi)

Hangi tür dosyaları aramak istiyorsanız onları seçtiğin kutudur.

Tüm seçimleri yapıp “Taramaya Başla” düğmesine bastıktan sonra ilerleme çubuğunun bir süre hareketsiz kaldığını göreceksiniz(bu süreç klasör tarama sürecidir), akabinde(süresi tarattığınız klasördeki dosya sayısına göre değişir) dosyaların karşılaştırılması sürecine geçilir ki burada ilerleme çubuğunda %sel gelişimin hareketlendiğini göreceksiniz.

4-Dosya boyutu(Opsiyonel)

Minimum ve maksimum dosya boyutu vererek tarama listenizi daraltabilirsiniz.

Çıktı

Tarama sonrasında ekran görüntüsü aşağıdaki gibi olacaktır. Resim dosyaları için bulunan mükerrer dosyanın kendisini ve orijinalinin aynı olup olmadığını da test etme imkanınız da olmaktadır.(2.fazda müzik ve video dosyaları için de aynı seçenek olacaktır) Bu arada orijinal dosya olarak ilk gördüğü dosyayı almaktadır. Sonra gördüklerini mükerrer olarak ele alır. SİL dediğinizde bu mükerrerleri silmiş olursunuz. Halbuki programın orijinal olarak belirlediği dosya çok alakasız, yedeğin de yedeği bir klasörde yer alıyor olabilir. Bir sonraki versiyonda hem orjinali hem de mükerrerleri TreeView şeklinde göstermeyi planlıyorum, böylece orijinal olarak belirlenen dosyayı silmek için işaretleyip, mükerreri seçmeyebilirsiniz.

Örnek vermek gerekirse benim laptopta yaptığım bu tarama yaklaşık 15 sn sürmüştür. ama Süper tarama seçerek yaparsam 10 dk civarı sürüyor.

taramasonucu

Neler kullandım (Programcılara Özel)

Programın kendisi yerine yazdığım kodla ilgilenen kişilere, kullandığım kod parçaları hakkında da bilgi vermek isterim.

  • İlk olarak global field olarak aşağıdaki dictionary’leri tanımladım, açıklamaları zaten yanlarında var.
    dictkod
  • Görmüş olacağınız üzere ProgressBar ve Backgroundworker kullandım.
  • Uzantıları aşağıdaki gibi bir List içine aldım ve tarama sonrasında foreach ile her dosya türü için tarama yaptım.
extlist.jpg
  • Boyut-tarih-ad kriterlerine göre tarama sonucunu döndürmek için aşağıdaki metodu oluşturdum
kriterdondur
  • Klasör taraması yapmak için ilk başta Directory.GetFiles((string)lstKlasorler.Items[i], x, SearchOption.AllDirectories) şekline ilerlemeye çalıştım ancak erişim yetkimin olmadığı klasörler karşıma çıkınca program hata veriyordu, ve inanın sandığınızdan çok sayıda böyle klasör var PC’nizde, tamam resim klasörü gibi klasörlerde yok ama tüm disk taraması yapmak istediğiniz karşınıza kesin çıkacaktır. Bu nedenle küçük bir Google araştırması sonucunda bir kod bulup aşağıdaki gibi kendi ihtiyacıma göre revize ettim.
klasortara

Kodum toplamda yorumlarla birlikte 657 satır. İlk gönderimde belirttiğim gibi C# dünyasına yeni adım atmış sayılırım, eminim şuan yolu uzatarak yaptığım bazı yerler olabilir, 2.fazı yaparken bir yandan da bunları daha kısa nasıl yaparım diye de düşüneceğim.

İlgilenen olursa tüm kodu da paylaşabilirim.

Saygı ve Sevilerimle