BindingSource.Find throws NotSupportedException (DataSource is BindingList<T>)
Asked Answered
M

3

6

I've got a BindingSource with a BindingList<Foo> attached as the data source. I'd like to work with the BindingSource's Find method to look up an element. However, a NotSupportedException is thrown when I do the following, even though my data source does implement IBindingList (and no such exception is documented in MSDN):

int pos = bindingSource1.Find("Bar", 5);

I attached a short example below (a ListBox, a Button and a BindingSource). Could anybody help me getting the Find invocation working?

public partial class Form1 : Form
{
    public Form1() { InitializeComponent(); }

    private void Form1_Load(object sender, EventArgs e)
    {
        var src = new BindingList<Foo>();
        for(int i = 0; i < 10; i++)
        {
            src.Add(new Foo(i));
        }

        bindingSource1.DataSource = src;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        int pos = bindingSource1.Find("Bar", 5);
    }
}

public sealed class Foo
{
    public Foo(int bar)
    {
        this.Bar = bar;
    }

    public int Bar { get; private set; }

    public override string ToString()
    {
        return this.Bar.ToString();
    }
}
Metonymy answered 13/6, 2012 at 14:12 Comment(0)
N
0

BindingList<T> does not support searching, as is. In fact bindingSource1.SupportsSearching returns false. The Find function is there for other classes that want to implement the IBindingList interface that do support searching.

To get a value, you should do bindingSource1.ToList().Find("Bar",5);

Natka answered 13/6, 2012 at 14:18 Comment(4)
OK, SupportsSearching is false, thank you. I rebuilt my code a little different, however: bindingSource1.List.OfType<Foo>().First(f => f.Bar == 5); does return the object properly, which is fine as well.Metonymy
I want to use the find method as described above, but when I try it I get the following error 'System.Windows.Forms.BindingSource' does not contain a definition for 'ToList'Conveyancer
@kirsteng I think you did either use .NET 2.0 or have no using System.Linq at the beginning of your code file. The latter makes the LINQ extension methods available in the code.Metonymy
Why the downvote on this, it is actually right, and partially helpfulBuie
C
23

I was able to solve my similar problem using

var obj = bindingSource1.List.OfType<Foo>().ToList().Find(f=> f.Bar == 5);
var pos = bindingSource1.IndexOf(obj);
bindingSource1.Position = pos;

this has the benefit of seeing the position as well as finding the object

Conveyancer answered 4/1, 2013 at 6:10 Comment(0)
N
0

BindingList<T> does not support searching, as is. In fact bindingSource1.SupportsSearching returns false. The Find function is there for other classes that want to implement the IBindingList interface that do support searching.

To get a value, you should do bindingSource1.ToList().Find("Bar",5);

Natka answered 13/6, 2012 at 14:18 Comment(4)
OK, SupportsSearching is false, thank you. I rebuilt my code a little different, however: bindingSource1.List.OfType<Foo>().First(f => f.Bar == 5); does return the object properly, which is fine as well.Metonymy
I want to use the find method as described above, but when I try it I get the following error 'System.Windows.Forms.BindingSource' does not contain a definition for 'ToList'Conveyancer
@kirsteng I think you did either use .NET 2.0 or have no using System.Linq at the beginning of your code file. The latter makes the LINQ extension methods available in the code.Metonymy
Why the downvote on this, it is actually right, and partially helpfulBuie
B
0

The answer to this problem is hinted at by the accepted answer. Find is not implemented on the IBindingList. You need to inherit IBindingList in your own class and implement find. You also need to signal that find is supported using and override of SupportsSearchingCore. This is an actual answer to the question e.g. how do you get Find working on the BindingList.

public class EfBindingList<T> : BindingList<T>
    where T : class
{
    public EfBindingList(IList<T> lst) : base(lst)
    {
    }

    protected override bool SupportsSearchingCore
    {
        get { return true; }
    }

    protected override int FindCore(PropertyDescriptor prop, object key)
    {
        var foundItem = Items.FirstOrDefault(x => prop.GetValue(x) == key);
        // Ignore the prop value and search by family name.
        for (int i = 0; i < Count; ++i)
        {
            var item = Items[i];
            if (prop.GetValue(item).ToString() == key.ToString()) return i;
        }
        return -1;
    }
}

After implementing this class, the following works

bsOrder.DataSource = new EfBindingList<OrderDto>(lstOrder);
var oldIndex = bsOrder.Find(keyName, id);
Buie answered 11/2, 2020 at 22:34 Comment(1)
foundItem is never used.Fournier

© 2022 - 2024 — McMap. All rights reserved.