当绑定的DataView按.NET中的不同列排序时,在DataGridView中找到行

时间:2010-10-21 16:14:25

标签: c# winforms sorting datagridview datatable

我有一个DataGridView,DataTable设置为DataSource。 DataTable有两列。用户有一个TextBox,动态地(在每次按键之后)在第一列中搜索匹配。 我想在每个键输入后跳转到匹配的记录(如果有的话),所以它需要很快。 我在DataTable的DefaultView上使用Find()方法。然后我定位货币管理器,这会导致DataGridView跳转到正确的记录。

但是,当用户选择按第二列排序时,这一切都会中断。这会更改DefaultView中的排序,而Find()无法再搜索第一列。

如果我创建第二个始终按第一列排序的DataView,我总是可以执行Find(),但后来我不知道如何识别DataGridView中的相应记录。

有没有办法在DataTable中的列上使用Find(),尽管绑定的DataView按不同的列排序,仍然跳转到DataGridView中找到的行?

2 个答案:

答案 0 :(得分:0)

再次考虑问题,当数据未在第一列上排序时(即使是由框架完成)线性搜索O(n)最适合您的问题。使用这个我实现了以下演示代码来解决您的问题,只需添加DataGridView& TextBox到你的表单,设置事件处理程序,你应该看到你正在寻找下面代码的行为。 This is not production quality code, rather directon on howto solve your problem in smaller context

using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form2 : Form
    {
        /// <summary>
        /// You can optimize this functionality only when the first column is sorted. 
        /// If not there is no faster way other than linear search, even if it would be done by framework, in my opinion linear search is the best posssible solution when the first column is not sorted.
        /// This piece of code is for demo purposes on how to do something, should be refined to fit your production cases.
        /// </summary>
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            string text = textBox1.Text.Trim();
            int index = dataGridView1.CurrentCell.RowIndex;
            CurrencyManager cm = dataGridView1.BindingContext[dataGridView1.DataSource] as CurrencyManager;
            DataView view = cm.List as DataView;

            if (string.IsNullOrEmpty(text)) return;

            //If sorted on first column
            if (view.Sort.Contains("First")) //column will be "[First]"
            {
                index = source.DefaultView.Find(text);
                SetIndex(cm, index);
            }
            //if not
            else if (view.Sort.Contains("Second")) //column will be "[Second]"
            {
                for (int i = 0; i < dataGridView1.Rows.Count; i++)
                {
                    if (dataGridView1.Rows[i].Cells["First"].Value.ToString().StartsWith(text))
                    {
                        index = i; break;
                    }
                }
                SetIndex(cm, index);
            }
        }

        private void SetIndex(CurrencyManager cm, int index)
        {
            if (index >= 0 && index < source.Rows.Count)
            {
                cm.Position = index;
            }
        }

        private void CreateData()
        {
            source.Columns.Add("First", typeof(string));
            source.Columns.Add("Second", typeof(string));

            var f = from first in Enumerable.Range('a', 26)
                    select new string(new char[] { (char)first });

            var s = f.Reverse();

            var c1Enumerator = f.GetEnumerator();
            var c2Enumerator = s.GetEnumerator();

            for (int i = 0; i < f.Count(); i++)
            {
                DataRow dr = source.NewRow();
                c1Enumerator.MoveNext();
                c2Enumerator.MoveNext();

                dr[0] = c1Enumerator.Current;
                dr[1] = c2Enumerator.Current;
                source.Rows.Add(dr);
            }
        }

        DataTable source = new DataTable();

        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            CreateData();
            dataGridView1.DataSource = source;
        }
    }
}

答案 1 :(得分:-1)

如果你使用BindingSource,它会更简单:

using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;

public class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    BindingSource source;

    public Form1()
    {
        Controls.Add(new DataGridView { Name = "DGV", Dock = DockStyle.Fill, TabIndex = 2 });
        Controls.Add(new TextBox { Name = "Find", Dock = DockStyle.Top, TabIndex = 1 });

        DataTable table = CreateData();
        source = new BindingSource(table, null);
        (Controls["DGV"] as DataGridView).DataSource = source;
        source.Sort = "First";

        Controls["Find"].TextChanged += (s, e) =>
            {
                int index = source.Find("First", (s as Control).Text);
                if (index >= 0)
                    source.Position = index;
            };
    }

    private DataTable CreateData()
    {
        DataTable table = new DataTable { Columns = { "First", "Second" } };
        foreach (var o in Enumerable.Range('a', 26).Select(ch => new { F = new String((char)ch, 1), S = new String((char)('z' - (ch - 'a')), 1)}))
        {
            DataRow dr = table.NewRow();
            dr[0] = o.F;
            dr[1] = o.S;
            table.Rows.Add(dr);
        };
        return table;
    }
}