Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move by code the BindingSource to a specific record

Using datagridview bound to BindingSource control bound to a LINQ to SQL class, I wonder how to position the bindingSource to a specific record, that is, when I type a Product name in a textbox, the bindingsource should move to that specific product. Here is my code:

In my form 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;
        }
    }

In the program class:

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

How can I implement the find method to make it work?

like image 876
Sami-L Avatar asked Jul 30 '12 00:07

Sami-L


People also ask

Which property is set to move to the next record in the data binding position?

Position Property (System.

What is BindingSource C#?

The BindingSource component acts as an intermediary that provides binding and currency management services. At design time or run time, you can bind a BindingSource component to a complex data source by setting its DataSource and DataMember properties to the database and table, respectively.


1 Answers

You can combine the BindingSource.Find() method with the Position property.

For example, if you have something like this in your TextBox changed event handler:

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

This of course will depend on a lot of things like the particular implementation of the Find method the data source for the binding source has.

In a question you asked a little while ago I gave you an implementation for Find which worked with full matches. Below is a slightly different implementation that will look at the start of the property being inspected:

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
}

Do note that the above method is case sensitive - you can change StartsWith to be case insensitive if you need.


One key thing to note about the way .Net works is that the actual type of an object is not sufficient all the time - the declared type is what consuming code knows about.

This is the reason why you get a NotSupported exception when calling the Find method, even though your BindingList implementation has a Find method - the code that receives this binding list doesn't know about the Find.

The reason for that is in these lines of code:

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);

When you set the data source for the binding source you include the extension method OrderBy - Checking this shows that it returns IOrderedEnumerable, an interface described here on MSDN. Note that this interface has no Find method, so even though the underlying FindableBindingList<T> supports Find the binding source doesn't know about it.

There are several solutions (the best is in my opinion to extend your FindableBindingList to also support sorting and sort the list) but the quickest for your current code is to sort earlier like so:

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;

In WinForms there are no entirely out of the box solutions for the things you are trying to do - they all need a little bit of custom code that you need to put together to match just your own requirements.

like image 179
David Hall Avatar answered Sep 25 '22 01:09

David Hall