【问题标题】:How to move by code the BindingSource to a specific record如何通过代码将 BindingSource 移动到特定记录
【发布时间】:2023-03-06 16:21:01
【问题描述】:

使用绑定到绑定到LINQ to SQL类的BindingSource控件的datagridview,我想知道如何将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;
        }
    }

在程序类中:

    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
        }
    }

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

【问题讨论】:

标签: winforms c#-4.0 linq-to-sql datagridview bindingsource


【解决方案1】:

您可以将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;
    }
}

这当然取决于很多事情,例如绑定源的数据源所具有的 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
}

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


关于 .Net 的工作方式需要注意的一个关键点是对象的实际类型并不总是足够的 - 声明的类型是消费代码所知道的。

这就是为什么在调用 Find 方法时会出现 NotSupported 异常的原因,即使您的 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);

当您为绑定源设置数据源时,您包括扩展方法OrderBy - 选中此项表明它返回 IOrderedEnumerable,这是 MSDN 上描述的here 接口。注意这个接口没有 Find 方法,所以即使底层的FindableBindingList&lt;T&gt; 支持 Find 绑定源也不知道。

有几种解决方案(我认为最好的方法是扩展您的 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;

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

【讨论】:

  • 我已经按照之前的建议在我的项目中实现了 BindingList,现在我在查询查找之前将列表传递给 bindingsource 控件。当我在上面运行您的代码时,我再次遇到异常: System.NotSupportedException is unhandled Source=System StackTrace: at System.ComponentModel.BindingList1.FindCore(PropertyDescriptor prop, Object key) at System.ComponentModel.BindingList1.System.ComponentModel.IBindingList.Find(PropertyDescriptor prop, Object key), any请想一想?
  • 所以你得到了同样的异常——你还没有实现 find 方法。在这一点上,很难帮助您,您似乎正在做很多您没有告诉我们的事情,然后发布与您遇到的错误无关的问题。如果您有一个支持查找的绑定列表,那么您可以从该索引查找和索引并设置位置。
  • 我将回顾我的 BindingList 实现。大卫,可能正如你所说,有一些我在这里没有提到的东西会导致这个错误出现。我第一次发布了关于 Filter 方法的问题,第二次发布了关于 Find 方法的问题,我认为这没有什么坏处。而且我并不掩饰在这个线程中找到你的喜悦,因为多亏了你,我学到了有趣的东西。既然你确信你所说的,那么我请你耐心等待片刻。就我而言,我相信在您的帮助下,我们可以澄清这个问题。
  • @AlphaBird 如果您仍然无法让这一切正常工作,也许去聊天会更好?如果您在接下来的短时间内阅读此内容,我将在 c# 房间进行聊天(单击此页面顶部的链接)。
  • 对不起,我是在你离开聊天1小时后来到这里的,我在最初的问题中添加了使用的代码,请问如何实现find方法。顺便说一句,您对BindingListView 有什么想法。好像也很有趣。
【解决方案2】:

我采取了不同的方法。我想,以编程方式,必须检查每条记录,直到找到匹配项,所以我只是使用 MoveNext 方法进行迭代,直到找到匹配项。不确定起始位置是否是第一条记录,所以我使用了 MoveFirst 方法来确保它是。

有一个假设,那就是您要搜索的内容在该列中是唯一的。在我的例子中,我希望匹配一个 Identity 整数。

int seekID;        
this.EntityTableBindingSource.MoveFirst();
if (seekID > 0)
{
     foreach (EntityTable sd in EntityTableBindingSource)
     {
         if (sd.ID != seekID)
         {
             this.t_EntityTableBindingSource.MoveNext();
         }
         else
         {
             break;
         }
      }
 } 

【讨论】:

    【解决方案3】:

    我并不真正关心提供的任何一个答案。这是我为我的问题想出的:

    // Create a list of items in the BindingSource and use labda to find your row:
    var QuickAccessCode = customerListBindingSource.List.OfType<CustomerList>()
        .ToList().Find(f => f.QuickAccessCode == txtQAC.Text);
    
    // Then use indexOf to find the object in your bindingSource:
    var pos = customerListBindingSource.IndexOf(QuickAccessCode);
    if (pos < 0)
    {
        MessageBox.Show("Could not find " + txtQAC.Text);
    }
    else
    {
        mainFrm.customerListBindingSource.Position = pos;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-11
      • 1970-01-01
      相关资源
      最近更新 更多