Veri kaynağını değiştirmeden DataGridView'e filtre uygulama


98

C # Visual Studio 2010'da kullanıcı denetimi geliştiriyorum - veri görünümüne filtre uygulamak için bir tür "hızlı bul" metin kutusu. 3 tür datagridview veri kaynağı için çalışmalıdır: DataTable, DataBinding ve DataSet. Benim sorunum DataGridView'da görüntülenen DataSet nesnesinden DataTable'ı filtrelemekle ilgili.

3 durum olabilir (üzerinde DataGridView ve TextBox bulunan standart WinForm uygulaması örnekleri) - ilk 2 çalışıyor, tamam, 3. bir ile sorunum var:

1. datagridview.DataSource = dataTable:
ayarlayarak filtreleyebileceğim şekilde çalışıyor : dataTable.DefaultView.RowFilter = "ülke GİBİ '% s%'";

DataTable dt = new DataTable();

private void Form1_Load(object sender, EventArgs e)
{
    dt.Columns.Add("id", typeof(int));
    dt.Columns.Add("country", typeof(string));

    dt.Rows.Add(new object[] { 1, "Belgium" });
    dt.Rows.Add(new object[] { 2, "France" });
    dt.Rows.Add(new object[] { 3, "Germany" });
    dt.Rows.Add(new object[] { 4, "Spain" });
    dt.Rows.Add(new object[] { 5, "Switzerland" });
    dt.Rows.Add(new object[] { 6, "United Kingdom" });

    dataGridView1.DataSource = dt;
}

private void textBox1_TextChanged(object sender, EventArgs e)
{
    MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString());

    dt.DefaultView.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);

    MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString());
} 

2. datagridview.DataSource = bindingSource: Çalışıyor,
böylece ayarlayarak filtreleyebilirim: bindingSource.Filter = "ülke LIKE '% s%'";

DataTable dt = new DataTable();
BindingSource bs = new BindingSource();

private void Form1_Load(object sender, EventArgs e)
{
    dt.Columns.Add("id", typeof(int));
    dt.Columns.Add("country", typeof(string));

    dt.Rows.Add(new object[] { 1, "Belgium" });
    dt.Rows.Add(new object[] { 2, "France" });
    dt.Rows.Add(new object[] { 3, "Germany" });
    dt.Rows.Add(new object[] { 4, "Spain" });
    dt.Rows.Add(new object[] { 5, "Switzerland" });
    dt.Rows.Add(new object[] { 6, "United Kingdom" });

    bs.DataSource = dt;
    dataGridView1.DataSource = bs;
}

private void textBox1_TextChanged(object sender, EventArgs e)
{
    MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString());

    bs.Filter = string.Format("country LIKE '%{0}%'", textBox1.Text);

    MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString());
}

3. datagridview.DataSource = dataSource; datagridview.DataMember = "TableName": çalışmıyor
Designer kullanarak bir tablo tasarladığınızda gerçekleşir: DataSet'i toolbox'tan forma koyun, dataTable'ı ekleyin ve ardından datagridview.DataSource = dataSource; ve datagridview.DataMember = "TableName".
Aşağıdaki kod, bu işlemleri varsayar:

DataSet ds = new DataSet();
DataTable dt = new DataTable();

private void Form1_Load(object sender, EventArgs e)
{
    dt.Columns.Add("id", typeof(int));
    dt.Columns.Add("country", typeof(string));

    dt.Rows.Add(new object[] { 1, "Belgium" });
    dt.Rows.Add(new object[] { 2, "France" });
    dt.Rows.Add(new object[] { 3, "Germany" });
    dt.Rows.Add(new object[] { 4, "Spain" });
    dt.Rows.Add(new object[] { 5, "Switzerland" });
    dt.Rows.Add(new object[] { 6, "United Kingdom" });

    ds.Tables.Add(dt);
    dataGridView1.DataSource = ds;
    dataGridView1.DataMember = dt.TableName;
}

private void textBox1_TextChanged(object sender, EventArgs e)
{
    MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString());  
    //it is not working
    ds.Tables[0].DefaultView.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);

    MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString());
}

Test ederseniz - datatable filtrelenmiş olmasına rağmen (ds.Tables [0] .DefaultView.Count değişiklikleri), datagridview güncellenmez ... Uzun zamandır herhangi bir çözüm arıyordum, ancak sorun şu ki DataSource yapamıyor değişiklik - ek bir kontrol olduğu için, programcının kodunu karıştırmasını istemiyorum.

Olası çözümlerin şunlar olduğunu biliyorum:
- DataTable'ı DataBinding kullanarak DataSet'ten bağlamak ve örnek 2 olarak kullanmak: ancak kod yazma sırasında programcıya bağlı,
- dataSource'u BindingSource, dataGridView.DataSource = dataSet.Tables [0] veya Programlı olarak DefaultView'a: Ancak, DataSource'u değiştirir. Yani çözüm:

private void textBox1_TextChanged(object sender, EventArgs e)
{
    MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());

    DataView dv = ds.Tables[0].DefaultView;
    dv.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);
    dataGridView1.DataSource = dv;

    MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());
}

MessageBox'ın dataSource'ta gördüğünüz gibi kabul edilemez ...

Bunu yapmak istemiyorum çünkü bir programcı şuna benzer bir kod yazabilir:

private void textBox1_TextChanged(object sender, EventArgs e)
{
    MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());

    DataSet dsTmp = (DataSet)(dataGridView1.DataSource);   //<--- it is OK 

    DataView dv = ds.Tables[0].DefaultView;
    dv.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);
    dataGridView1.DataSource = dv;   //<--- here the source is changeing from DataSet to DataView

    MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());

    dsTmp = (DataSet)(dataGridView1.DataSource);    //<-- throws an exception: Unable to cast object DataView to DataSet
}

Bunu tasarımcıda DataSet ve DataMember ile DataGridView'i tasarladığı için yapabilir. Kod derlenecek, ancak bir filtre kullandıktan sonra bir istisna atacak ...

Öyleyse soru şu: DataSet'te DataTable'ı nasıl filtreleyebilirim ve DataSource'u diğerine değiştirmeden DataGridView'de sonuçları nasıl gösterebilirim? DataTable'ı DataSet'ten filtrelemek çalışırken neden DataTable'ı doğrudan 1. örnekten filtreleyebilirim? Belki bu durumda DataGridView'e bağlı DataTable değildir?

Lütfen sorunumun sorunları tasarlamaktan kaynaklandığını, bu nedenle çözümün Örnek 3'te ÇALIŞMALIDIR.


1
Tüm değerli yorum ve çözümlere ek olarak 2 sentim. Burada, veriye bağlı DataGridView'i bu şekilde filtrelemenin artılarını ve eksilerini açıklayan ve bunu daha iyi nasıl yapacağınıza dair bazı fikirler veren bir makale .
TecMan

Tekrarı affedin ama teklifimin her seferinde işe yaramadığını düşünüyorum. Aslında, zaman zaman bir istisna kaldırılır, ki benim kodum pek olası değildir. Bir bindingSource ile filtrelemeye çalışmak, iyi kod yapmak için her şansa sahipsiniz. Like date: bindingSource.Filter = string.Format .....
KOUAKEP ARNOLD

TecMan yorumunu beğendim. Filtre özelliğini IBindingListView arabirimine (daha az çalışır, ancak yalnızca ADO.Net Datatable ile gerçekten kullanılabilir) veya tüm işi kendi kontrolünüzde yaparak (daha fazla çalışır, ancak herhangi bir şeyle çalışmalıdır) delege edebilirsiniz.
Marco Guignard

Yanıtlar:


148

Benzer bir problem için bir saatimi harcadım. Benim için cevap utanç verici derecede basit çıktı.

(dataGridViewFields.DataSource as DataTable).DefaultView.RowFilter = string.Format("Field = '{0}'", textBoxFilter.Text);

2
bu olayı metin kutusuna bağlama
Arun Prasad ES

7
Filtreleme sözdizimi burada bulunabilir: csharp-examples.net/dataview-rowfilter
Sal

Bir DataTable'ı kaynak olarak kullanmak msdn.microsoft.com/en-us/library/…IBindingListView
Jeremy Thompson

Bu hatayı alıyorum: Object reference not set to an instance of an object.GridView için.
Si8

Veri kaynağınız nedir? Örneğim bir DataTable kullandığınızı varsayar. Başka bir şey kullanıyorsanız, dökümünüzü kontrol edin. Örneğimde "DataTable olarak".
Brad Bruce

23

Filtreyi uygulamak için genel bir ifade geliştirdim:

string rowFilter = string.Format("[{0}] = '{1}'", columnName, filterValue);
(myDataGridView.DataSource as DataTable).DefaultView.RowFilter = rowFilter;

Köşeli parantezler sütun adında boşluklara izin verir.

Ayrıca, filtrenize birden çok değer eklemek isterseniz, her ek değer için aşağıdaki satırı ekleyebilirsiniz:

rowFilter += string.Format(" OR [{0}] = '{1}'", columnName, additionalFilterValue);

12

Daha basit bir yol, verileri enine çevirmek ve Visibleözelliği içeren satırları gizlemektir .

// Prevent exception when hiding rows out of view
CurrencyManager currencyManager = (CurrencyManager)BindingContext[dataGridView3.DataSource];
currencyManager.SuspendBinding();

// Show all lines
for (int u = 0; u < dataGridView3.RowCount; u++)
{
    dataGridView3.Rows[u].Visible = true;
    x++;
}

// Hide the ones that you want with the filter you want.
for (int u = 0; u < dataGridView3.RowCount; u++)
{
    if (dataGridView3.Rows[u].Cells[4].Value == "The filter string")
    {
        dataGridView3.Rows[u].Visible = true;
    }
    else
    {
        dataGridView3.Rows[u].Visible = false;
    }
}

// Resume data grid view binding
currencyManager.ResumeBinding();

Sadece bir fikir ... benim için çalışıyor.


A'yı manuel olarak dolduran biri olarak DataGridViewbu mükemmel çalıştı. :) Ben kullanmasına rağmen foreachdoğrudan atanmış row.Visible = showAll || <condition>;herhangi olmadan if. Bu showAll, filtre dizesi boşsa doğrudur.
Andrew

harika bir fikir çünkü bu durumda veri kaynağının türüne bağlı değiliz. ne de herhangi bir DataTable.
mshakurov

Mükemmel çalıştı ve arama mantığını iyileştirmek için if koşulunu dataGridView3.Rows [u] .Cells [4] .Value.ToString (). IndexOf ("The filter string")> = 0
Ali Ali

1

Veri kaynağınızdan bir DataView nesnesi oluşturabilirsiniz . Bu, veri kaynağını doğrudan değiştirmeden verilerinizi filtrelemenizi ve sıralamanızı sağlar.

Ayrıca, dataGridView1.DataBind();veri kaynağını ayarladıktan sonra aramayı da unutmayın .


2
Cevabın için teşekkür ederim. Evet, DataView nesnesi oluşturulabilir, ancak DataSource türünü değiştirir, lütfen son koda bakın. Önceki gönderide bundan kaçınmak istememin nedenini değiştirdim. dataGridView1.DataBind () yöntemi WinForms'da mevcut değil, sanırım ASP'den.
mj82

0

// "Yorum" Veri kümesini değiştirmeden veri kümesini filtreleyin, Mükemmel çalışır.

            (dg.ItemsSource as ListCollectionView).Filter = (d) =>
            {
                DataRow myRow = ((System.Data.DataRowView)(d)).Row;
                if (myRow["FName"].ToString().ToUpper().Contains(searchText.ToString().ToUpper()) || myRow["LName"].ToString().ToUpper().Contains(searchText.ToString().ToUpper()))
                    return true; //if want to show in grid
                return false;    //if don't want to show in grid
            };         

0

DataGridView'da otomatik aramayla ilgili daha net bir teklifim var

bu bir örnektir

private void searchTb_TextChanged(object sender, EventArgs e)
    {
        try
        {
            (lecteurdgview.DataSource as DataTable).DefaultView.RowFilter = String.IsNullOrEmpty(searchTb.Text) ?
                "lename IS NOT NULL" :
                String.Format("lename LIKE '{0}' OR lecni LIKE '{1}' OR ledatenais LIKE '{2}' OR lelieu LIKE '{3}'", searchTb.Text, searchTb.Text, searchTb.Text, searchTb.Text);
        }
        catch (Exception ex) {
            MessageBox.Show(ex.StackTrace);
        }
    }


-2

Bu sorunu çözmenin basit bir yolunu buldum. Datagridview bağlamada az önce yaptınız:datagridview.DataSource = dataSetName.Tables["TableName"];

Aşağıdaki gibi kodlarsanız:

datagridview.DataSource = dataSetName;
datagridview.DataMember = "TableName";

datagridview, filtreleme sırasında verileri bir daha asla yüklemeyecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.