Makale Özeti

Bu makalede sizlerle birlikte adını searchbox olarak belirlemenin uygun olacağı bir kontrolü yazacağız. Bu kontrol ilk bakışta bir ComboBox gibi gözüksede F2 tuşuna bastığımızda karşımıza detaylı bir arama ekranı çıkmakta ve istediğimiz kayıdı burda kriterlerimizi beliryerek rahatlıkla arayabilmekteyiz. ComboBox içinde çok fazla verinin olduğu durumlarda çözüm olarak kullanılabilecek olan bu kontrolü kullanmak için hiçbir ek kod yazmanıza gerek yoktur ve çok genel bir yapı olduğundan her form üzerinde rahatlıkla kullanılabilir.

Makale

         Merhabalar,

          SearchBox kontrolümüz ComboBox'tan türemiş olduğunu ve KeyDown event'ı ezilerek F2 tuşuna basıldığı zaman showSearchBox() metodunu sayesinde genel arama ekranımız olan frmSearch formumuzu göstermekte olduğunu. Bu formumuz'un şekillenebilmesi için yapıcı metodun nasıl yazıldığını bu makalenin ilk kısmında incelemiştik. İlk önce arama formumuzun neye benzeyeceğini görelim ve daha sonra kodlamasına başlayalım.
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
 
namespace SearchBoxComponent
{
    public partial class frmSearch : Form
    {
        private string memDisplayMember;
        private string memValueMember;
        private DataView memDataSource;
        private ComboBox memOpenerControl;
        private CriteriaCollection memCriteriaCollection;
        public CriteriaCollection proCriteriaCollection
        {
            get {return memCriteriaCollection;}
            set { memCriteriaCollection = value; }
        }
        private Criteria memCriteria;
        public Criteria proCriteria
        {
            get { return memCriteria; }
            set { memCriteria = value; }
        }
          Formumuzun içine yazdığımız değişkenler ve propertyler yukarıda gözükmektedir. Şimdi bu property ve değişkenlerin amaçlarını inceleyelim. Burada DisplayMember,ValueMember,DataSource,OpenerControl SearchBox tarafından formumuzun bir örneği alınırken yapıcı metodda gönderilen değerlerdir. Bu değerlerin ne işe yaradıklarını SearchBox içinden form'u açan metodda tanımlamıştık. Burada bulunan memDataSource değişkeni DataView tipindendir ve filitrelere göre sorgulama yapacağımız verileri taşıyacaktır. Bunun dışında CriteriaCollection ve Criteria propertyleri ise bizim kriterlerimizi ve ekle tuşuna basarak daha önceden sakladığımız kriterleri saklayacak propertyler ve değişkenlerdir.
 
        public frmSearch()
        {
            InitializeComponent();
        }
        public frmSearch(ComboBox parOpenerControl,DataTable parDataSource, string parDisplayMember, string parValueMember)
        {
            InitializeComponent();
           memDataSource = new DataView(parDataSource);
            memDisplayMember = parDisplayMember;
            memValueMember = parValueMember;
            memOpenerControl = parOpenerControl;
            memCriteria = new Criteria();
            memCriteriaCollection = new CriteriaCollection();
        }
          Formumuzun yapıcı metodları iki tanedir. Bizim bileşenimiz ise 2. yapıcı metodu kullanmaktadır ve Bu metodda gelen değişkenler uygun propertylere veya form üzerinde bulunan değişkenlere aktarılmaktadır. Ancak parDataSource DataTable gelirken DataView nesnesine çevrilerek local değişkene atanmaktadır ki RowFilter özelliği kullanılarak filitreleme yapılabilsin.
 
  private void frmSearch_Load(object sender, EventArgs e)
        {
            dgvSearch.AutoGenerateColumns = false;
            dgvSearch.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dgvSearch.MultiSelect = false;
            dgvSearch.DataSource = memDataSource;
            foreach (DataColumn column in memDataSource.Table.Columns)
            {
                DataGridViewTextBoxColumn a = new DataGridViewTextBoxColumn();
                a.Name = column.Caption;
                a.DataPropertyName = column.Caption;
                a.SortMode = DataGridViewColumnSortMode.Automatic;
                a.HeaderText = column.Caption;
                a.ReadOnly = true;
                dgvSearch.Columns.Add(a);
                cmbAlan.Items.Add(column.Caption);
            }
            cmbAlan.SelectedItem = memDisplayMember;
            dgvSearch.Rows[memOpenerControl.SelectedIndex].Cells[0].Selected=true;
            spcMain.SplitterDistance= 30;
           
        }
          Formumuz yüklenirken DataGridView'imizin kolonlarının otomatik olarak oluşturulmayacağını, seçim modunu belirtiyoruz ve DataSource propertysine formumuzun bir örneği oluşturulurken parametre olarak yapıcı metodda alıp daha sonra DataView'e çevirip depoladığımız DataView'i veriyoruz. DataView içinde bulunan Tablonun her kolonunun ismini ise cmbAlan isimli ComboBox'ımıza eklyoruz ve kullanıcıya kolaylık olması bakımından formu açtığında ilk arama yapmak isteyeceği kolon olan memDisplayMember olarak tanımlanmış yani SearchBox'ımızın DisplayMember property'sine atanmış kolonu seçiyoruz. Ve formumuzu açan SearchBox'ta seçili olarak bulunan nesneyi Formumuzda bulunan DataGridView üzerindede seçili hale getiriyoruz.
 
        private void funSetCriteria()
        {
            this.memCriteria.proSearchType = (Helper.enmSearchType)cmbTip.SelectedItem;
            this.memCriteria.proCriteria = txtAranacak.Text;
            this.memCriteria.proColumnName = cmbAlan.SelectedItem.ToString();
        }
        private void funExecuteQuery()
        {
            string queryExpression = "";
            queryExpression = this.proCriteriaCollection.getQuery() + this.proCriteria.getCriteria();
            if (queryExpression != "")
            {
                if (queryExpression.Substring(queryExpression.Length - 5) == " AND ")
                {
                    queryExpression = queryExpression.Substring(0, queryExpression.Length - 5);
                }
            }
            memDataSource.RowFilter = queryExpression;
            dgvSearch.DataSource = memDataSource;
        }
          Burada yazılan iki metoddan ilki olan funSetCriteria() metodunda Formumuzda property olarak tutulan Criteria nesnesinin propertylerine form üzerinde bulunan değerleri atıyoruz. funExecuteQuery() metodunda ise Collectionumuzda ve nesnemizde bulunan değerlerde göre sorguları oluşturtup bunları birleştirerek DataView'in RowFilter property'sine veriyoruz ve daha sonrasında DataGridView'imizin DataSource propertysine bu DataView nesnesini atayarak sadece keriterlerimize uyan kayıtları DataGridView'de gösteriyoruz.
 
        private void txtAranacak_TextChanged(object sender, EventArgs e)
        {
            this.funSetCriteria();
            this.funExecuteQuery();
        }
        private void cmbTip_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.funSetCriteria();
            this.funExecuteQuery();
        }
        private void cmbAlan_SelectedIndexChanged(object sender, EventArgs e)
        {
            object cmbTipEskiDeger = null;
            if (cmbTip.SelectedItem != null)
            {
                cmbTipEskiDeger = cmbTip.SelectedItem;
            }
            cmbTip.Items.Clear();
            if (memDataSource.Table.Columns[cmbAlan.SelectedItem.ToString()].DataType == typeof(String))
            {
                cmbTip.Items.Add(Helper.enmSearchType.Like);
                cmbTip.Items.Add(Helper.enmSearchType.Equal);
                cmbTip.Items.Add(Helper.enmSearchType.NotEqual);
            }
            else
            {
                cmbTip.Items.Add(Helper.enmSearchType.Equal);
                cmbTip.Items.Add(Helper.enmSearchType.NotEqual);
                cmbTip.Items.Add(Helper.enmSearchType.Greater);
                cmbTip.Items.Add(Helper.enmSearchType.Smaller);
            }
            if (cmbTipEskiDeger != null && cmbTip.Items.IndexOf(cmbTipEskiDeger) > -1)
            {
                cmbTip.SelectedItem = cmbTipEskiDeger;
            }
            else
            {
                cmbTip.SelectedIndex = 0;
            }
            this.funSetCriteria();
            this.funExecuteQuery();
        }
          Arama yapılacak değerin yazıldığı TextBox, arama yapılacak kolonun seçildiği ComboBox ve arama tipinin seçildiği ComboBox daki değerler değiştiği zaman sorgumuzun çalışması kullanıcın hiçbir tuşa basmadan verileri sorgulayabileceği anlamına gelmekte ve kolaylık ve hız sağlamaktadır. Bunun için bu üç kontrolünde uygun eventlarında biraz önce yazmış olduğumuz funSetCriteria() ve funExecuteQuery() metodlarını çağırıyoruz. Burada biraz daha farklı bir kod yapısı sadece Kolon isimlerinin saklandığı ComboBox'tadır. Burda seçilen değere göre hangi tiplerde arama yapılacağı belirlenmektedir. Çünkü integer veri taşıyan bir field için like ile veya string değer taşıyan bir field için büyüktür ve küçüktür ile sorgu yapılamamaktadır.
 
        private void dgvSearch_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex != -1)
            {
                memOpenerControl.SelectedValue=dgvSearch.Rows[e.RowIndex].Cells[memValueMember].Value;
                this.Close();
            }
        }
          Kayıtların gösterildiği DataGridView'de bir satıra çift tıklanıldığı zaman o satırdaki verlerden ValueMember kolonuna ait olan veriyi alıyor ve arama formumuzu açan SearchBox kontrolümüzün SelectedValue property'sine atayarak seçtiğimiz değerin SearchBox kontrolümüzdede seçili hale gelmesini sağlıyoruz ve arama formumuzu kapıyoruz.
 
        private void btnEkle_Click(object sender, EventArgs e)
        {
            if (txtAranacak.Text == "")
            {
                MessageBox.Show("Aranacak Metni Giriniz");
                return;
            }
            uctCriteria a = new uctCriteria();
            this.proCriteriaCollection.Add(this.memCriteria);
            a.proCriteria = this.memCriteria;
            this.memCriteria = new Criteria();
            a.Top = pnlUserControl.Controls.Count * 30;
            pnlUserControl.Controls.Add(a);
            if (pnlUserControl.Controls.Count < 4)
            {
                spcMain.SplitterDistance = 30 + pnlUserControl.Controls.Count * 30;
            }
            txtAranacak.Text = "";
            txtAranacak.Focus();
        }
        private void pnlUserControl_ControlRemoved(object sender, ControlEventArgs e)
        {
            this.proCriteriaCollection.Remove(((uctCriteria)e.Control).proCriteria);
            funExecuteQuery();
            {
                for (int i = 0; i < pnlUserControl.Controls.Count; i++)
                {
                    pnlUserControl.Controls[i].Top = i * 30;
                }
            }
            if (pnlUserControl.Controls.Count < 4)
            {
                spcMain.SplitterDistance = 30 + pnlUserControl.Controls.Count * 30;
            }
        }
    }
}
          Ekle butonuna tıklandığında şu an işlem yapılan Criteria nesnemizi Collectionda saklamaya başlıyor ve Criteria nesnemizi sıfırlıyoruz. Hangı krıterlerı kullandığımızı kullanıcıya göstermek için yazdığımız ve biraz sonra inceleyeceğimiz uctCriteria isimli User Control'ün bir örneğini alıyoruz ve bunu Formumuz üzerindeki bir panele lokasyonunu belirterek ekliyoruz. Bu panelde bulunan uctCriteria kontrollerinden biri panelden silindiğinde ise Bu UserControl'e ait Criteria nesnemizi Collectiondan siliyoruz.

        Şimdi ise uctCriteria isimli UserControl'umuzu görelim ve kodunu yazalım.
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
 
namespace SearchBoxComponent
{
    public partial class uctCriteria : UserControl
    {
        public uctCriteria()
        {
            InitializeComponent();
        }
        private Criteria memCriteria;
        public Criteria proCriteria
        {
            get{return memCriteria;}
            set{memCriteria = value;}
        }
        private void btnSil_Click(object sender, EventArgs e)
        {
            this.Parent.Controls.Remove(this);
        }
        private void uctCriteria_Load(object sender, EventArgs e)
        {
            lblText.Text = memCriteria.getCriteria();
        }
    }
}
          Bu UserControl bir Label ve bir Button'dan oluşuyor ve içinde Criteria nesnesinin saklandığı bir property barındırıyor. Sil butonu sayesinde Parent Controlünden kaldırılıyor.

         Şimdi ise yazdığımız bu kontrolü örnek bir uygulama ile test edelim.
 
 

         Şimdi ise bu kontrolü uygulamamızın ne kadar kolay olduğunu inceleyelim. Formumuzun Load event'inde yazdığımız kodun bir combobox için yazılan kod ile tamamen aynı olduğunu göreceksiniz.
        private void Form1_Load(object sender, EventArgs e)
        {
            DbProviderFactory ProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
            DbConnection Connection = ProviderFactory.CreateConnection();
            Connection.ConnectionString = @"data source=tameroz;initial catalog=DENEME;integrated security=SSPI";
            DbCommand cmd = ProviderFactory.CreateCommand();
            cmd.CommandText = "Select * FROM MenuItems";
            cmd.Connection = Connection;
            DbDataAdapter da = ProviderFactory.CreateDataAdapter();
            da.SelectCommand = cmd;
            DataTable dt = new DataTable();
            da.Fill(dt);
 
            searchBox1.DataSource = dt;
            searchBox1.DisplayMember = "Text";
            searchBox1.ValueMember = "MenuItemId";
        }
         
         Bu makalede yazdığımız kontrolü her çeşit windows uygulamasında çok fazla veri olan ve kullanıcının seçim yapması gerektiği seneryolarda kullanıcıların bu veriler arasında kaybolmadan rahatça seçim yapablmesi için kullanabilirsiniz.

oztamer@hotmail.com
tamer.oz@yazgelistir.com
oztamer@hotmail.com
Ornek Kodlar