如何通过代码将BindingSource移动到特定记录

Sam*_*i-L 6 datagridview bindingsource linq-to-sql winforms c#-4.0

使用绑定到绑定到LINQ to SQL类的BindingSource控件的datagridview ,我想知道如何将bindingSource定位到特定记录,也就是说,当我在文本框中键入产品名称时,bindingsource应该移动到该特定产品.这是我的代码:

以我的形式FrmFind:

    NorthwindDataContext dc;
    private void FrmFind_Load(object sender, EventArgs e)
    {
        dc = new NorthwindDataContext();

        var qry = (from p in dc.Products
                   select p).ToList();

        FindAbleBindingList<Product> list = new FindAbleBindingList<Product>(qry);

        productBindingSource.DataSource = list.OrderBy(o => o.ProductName);
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        TextBox tb = sender as TextBox;

        int index = productBindingSource.Find("ProductName", tb.Text);

        if (index >= 0)
        {
            productBindingSource.Position = index;
        }
    }
Run Code Online (Sandbox Code Playgroud)

在程序类中:

    public class FindAbleBindingList<T> : BindingList<T>
    {

        public FindAbleBindingList()
            : base()
        {
        }

        public FindAbleBindingList(List<T> list)
            : base(list)
        {
        }

        protected override int FindCore(PropertyDescriptor property, object key)
        {
            for (int i = 0; i < Count; i++)
            {
                T item = this[i];
                //if (property.GetValue(item).Equals(key))
                if (property.GetValue(item).ToString().StartsWith(key.ToString()))
                {
                    return i;
                }
            }
            return -1; // Not found
        }
    }
Run Code Online (Sandbox Code Playgroud)

如何实现find方法使其工作?

Dav*_*all 13

您可以将BindingSource.Find()方法与Position属性组合使用.

例如,如果在TextBox更改的事件处理程序中有类似的内容:

private void textBox1_TextChanged(object sender, EventArgs e)
{
    TextBox tb = sender as TextBox;
    int index = bs.Find("Product", tb.Text);

    if (index >= 0)
    {
        bs.Position = index;
    }
}
Run Code Online (Sandbox Code Playgroud)

这当然将取决于很多事情,比如绑定源的数据源的Find方法的特定实现.

在你刚才问的一个问题中,我给了你一个Find的实现,它与完全匹配一起工作.下面是一个稍微不同的实现,它将查看被检查属性的开头:

protected override int FindCore(PropertyDescriptor property, object key)
{
    // Simple iteration:
    for (int i = 0; i < Count; i++)
    {
        T item = this[i];
        if (property.GetValue(item).ToString().StartsWith(key.ToString()))
        {
            return i;
        }
    }
    return -1; // Not found
}
Run Code Online (Sandbox Code Playgroud)

请注意,上述方法区分大小写 - 如果需要,可以将StartsWith更改为不区分大小写.


关于.Net工作方式的一个关键注意事项是对象的实际类型始终不够 - 声明的类型是消费代码所知道的.

这就是为什么NotSupported在调用Find方法时遇到异常的原因,即使您的BindingList实现具有Find方法 - 接收此绑定列表的代码也不知道Find.

原因在于这些代码行:

dc = new NorthwindDataContext();

var qry = (from p in dc.Products
           select p).ToList();

FindAbleBindingList<Product> list = new FindAbleBindingList<Product>(qry);

productBindingSource.DataSource = list.OrderBy(o => o.ProductName);
Run Code Online (Sandbox Code Playgroud)

为绑定源设置数据源时,包括扩展方法OrderBy- 选中此选项表示它返回IOrderedEnumerable,并在MSDN上描述此处所述的接口.请注意,此接口没有Find方法,因此即使底层FindableBindingList<T>支持查找绑定源也不知道它.

有几种解决方案(在我看来,最好的是扩展你的FindableBindingList以支持对列表进行排序和排序)但是你当前代码的最快速度是先排序,如下所示:

dc = new NorthwindDataContext();

var qry = (from p in dc.Products
           select p).OrderBy(p => p.ProductName).ToList();

FindAbleBindingList<Product> list = new FindAbleBindingList<Product>(qry);

productBindingSource.DataSource = list;
Run Code Online (Sandbox Code Playgroud)

在WinForms中,没有完全开箱即用的解决方案可用于您正在尝试的事情 - 它们都需要一些自定义代码,您需要将它们组合在一起以满足您自己的要求.