Incremental search on arrays or lists

EylonM
EylonM used Ask the Experts™
on
Hi
I have a list of countries in a list box that I want to do an incremental search on.  I have a text box above the list box and as I write I want the list of countries to be filter in accordance to the what I have written so far.  For each letter typed I could simply set the datasource of the list to the results of a linq to sql statement and redo the linq statement for every letter I type.  But, the interface will be used by many users and we want to avoid unnecessary round trips to the sql server.

So, I thought of doing the following:
1. On load, create an array that will hold the name of the country and its id using a linq statement
2. Set the datasource of the list to the array.
3. As I type, use linq to filter the array.  This way the filtering would be in memory without the round trips to the sql server.

I am need to know how to define the array properly, getting the list display member and  value member connect correctly to the array and using linq to filter the array as I type.

Thanks
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
Here is some non-working code to illustrate:

public partial class frmChooseCountry : Form
    {
        dcDataContext db = new dcDataContext();
        Array myCountries = Array.CreateInstance(typeof(String), 22);
        Array myCountries2 = Array.CreateInstance(typeof(String), 22);

public frmCountries()
        {
            InitializeComponent();
        }

 private void frmMycountriest_Load(object sender, EventArgs e)
        {
            myusers = (from c in db.countries
                        orderby c.country
                        select new
                        {
                            c.country,
                            c.countryid
                        }).ToArray();
                       listBox1.DataSource =myusers;

         }


        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
                myusers   = (from c in myusers2
                           where c.country.ToString().Substring(0, Math.Min(textBox1.Text.Length, c.country.Length))  == textBox1.Text
                           orderby c.lastname
                           select new
                           {
                               c.country,
                               c.countryid
                           }).ToArray();
                           listBox1.DataSource =myusers;
                    }
       }

Commented:
You can try to use List<(Of <(T>)>) Class which represents a strongly typed list of objects that can be accessed by index. It provides methods to search, sort, and manipulate lists. Converty the Linq result into List collection and bind it to dropdownlist. Then search on the List collection based on the text typed in the textbox.
To bind a dropdown list using List,
 
 

protected void BindContries() 
    {        
        DropDownList  ddlCountries;
        List<Country> countryList = new List<Country>(); 
 
        LINQYourDataContext db = new LINQYourDataContext(); 
 
        var mCountries = from p in db.Countries  
                        orderby 0 
                        select p; 
 
        countryList = mCountries.ToList<Country>();  
        
        ddlCountries.DataSource = countryList; 
        ddlCountries.DataTextField = "CountryName";
        ddlCountries.DataValueField = "CountryID";
 
    } 
//Here Country is a class with CountryName and CountryID properties.

Open in new window

Author

Commented:
Thanks

Doesn't compile on countryList = mCountries.ToList<Country>();
Bootstrap 4: Exploring New Features

Learn how to use and navigate the new features included in Bootstrap 4, the most popular HTML, CSS, and JavaScript framework for developing responsive, mobile-first websites.

Author

Commented:
The error message more or less:
'System.Linq.IQueryable<AnonymousType#1>' does not contain a definition for 'ToList' and the best extension method overload 'System.Linq.Enumerable.ToList<TSource>(System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments

Commented:
Could you please post the error message? Also have you defined a class named Country ?

Author

Commented:
Yes, I defined a class named Country.  

public class Country
    {
        public int nCountryid;
        public string cCountry;
    }

Fernando SotoRetired
Distinguished Expert 2017

Commented:
Hi EylonM;

Try it like this, I think this should work for you.

Fernando
public partial class frmChooseCountry : Form
{
    dcDataContext db = new dcDataContext();

    public frmCountries()
    {
        InitializeComponent();
    }

    private void frmMycountriest_Load(object sender, EventArgs e)
    {
        var myusers = (from c in db.countries
                       orderby c.country
                       select new Country
                       {
                           cCountry = c.country,
                           nCountryid = c.countryid,
                           cLastname = c.lastname
                       }).ToList();
                    
        listBox1.DisplayMember = "cCountry";
        listBox1.ValueMember = "nCountryid";
        listBox1.DataSource =myusers;
     }


    private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
         var myusers = (from c in listBox1.DataSource as List<Country>
                        where c.cCountry.Substring(0, Math.Min(textBox1.Text.Length, c.cCountry.Length))  == textBox1.Text
                        orderby c.lastname
                        select new
                        {
                            cCountry = c.country,
                            nCountryid = c.countryid,
                            cLastname = c.lastname
                        }).ToList();
                        
         listBox1.DisplayMember = "cCountry";
         listBox1.ValueMember = "nCountryid";
         listBox1.DataSource =myusers;
    }
}

public class Country
{
    public int nCountryid { get; set; }
    public string cCountry { get; set; }
    public string cLastname { get; set; }
}

Open in new window

Author

Commented:
I get the following error:
(I also tried to remove the where clause - didn't help)

System.ArgumentNullException was unhandled
  Message="Value cannot be null.\r\nParameter name: source"
  Source="System.Core"
  ParamName="source"
  StackTrace:
       at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate)
       at MerozOfranManage.Forms.frmTest.textBox1_TextChanged(Object sender, EventArgs e) in C:\Clients\Ofran\OfranManage\OfranManage\Forms\frmTest.cs:line 38
       at System.Windows.Forms.Control.OnTextChanged(EventArgs e)
       at System.Windows.Forms.TextBoxBase.OnTextChanged(EventArgs e)
       at System.Windows.Forms.TextBoxBase.WmReflectCommand(Message& m)
       at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
       at System.Windows.Forms.TextBox.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
       at System.Windows.Forms.Control.WmCommand(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Control.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WmKeyChar(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.TextBoxBase.WndProc(Message& m)
       at System.Windows.Forms.TextBox.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at MerozOfranManage.Program.Main() in C:\Clients\Ofran\OfranManage\OfranManage\Program.cs:line 35
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

public partial class frmTest : Form
    {
        dcDataContext db = new dcDataContext();

        public frmTest()
        {
            InitializeComponent();
        }

        private void frmTest_Load(object sender, EventArgs e)
        {
             var kuku = (from c in db.users
                       orderby c.lastname
                       select new
                       {
                           cLastname = c.lastname, 
                            nUserid = c.userid

                        }).ToList();
            listBox1.DisplayMember = "cLastname";
            listBox1.ValueMember = "nUserid";
            listBox1.DataSource = kuku;
        }
       
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            var kuku = (from c in listBox1.DataSource as List<myUser>
                        where c.cLastname.Substring(0, Math.Min(textBox1.Text.Length, c.cLastname.Length))
                        == textBox1.Text
                        orderby c.cLastname
                        select new
                        {
                            cLastname = c.cLastname,
                            nUserid = c.nUserid

                        }).ToList();

            listBox1.DisplayMember = "cLastname";
            listBox1.ValueMember = "nUserid";
            listBox1.DataSource = kuku;
        }

        public class myUser
        {
            public int nUserid { get; set; }
            public string cLastname { get; set; }
        }

    }

Open in new window

Retired
Distinguished Expert 2017
Commented:
Hi EylonM;

In this line of code in textBox1_TextChanged :

var kuku = (from c in listBox1.DataSource as List<myUser>

You are referencing a non-existing List, List<myUser>. In my original code I created the List in the frmTest_Load event with this line:

select new myUser
{
    cLastname = c.lastname,
    nUserid = c.userid
}).ToList();

Note that I create a concrete class of myUser which creates a List<myUser>. By leaving out the class name myUser after the key word new you are creating an Anonymous class which creates a List<Anonymous-Type>. Try adding the class name in.

Fernando

Author

Commented:
In your original code int the load you create:
var myusers

At the bottom you create:
public class Country

int eh kerpress you write:
var myusers = (from c in listBox1.DataSource as List<Country>

I confused things by changing the names, but do you mean that in your original code you should have written in the key press:

var myusers = (from c in listBox1.DataSource as List<myusers>
(and my code should be  var kuku = (from c in listBox1.DataSource as List<kuku>)
like you created in the load or

var myusers = (from c in listBox1.DataSource as List<Country>
where you use the class defined at the end?
(in which my code seems to be like you suggested:
 var kuku = (from c in listBox1.DataSource as List<myUser>
where myUser is a class defined at the end.)

Author

Commented:
Oops.  Ok, I understand.  Nice.  I will give it a try.

Author

Commented:
Works! Great! Thanks
I hade to make some changes:
In textBox1_TextChanged I added "Country" after new:
 select new Country
                           {
                               cCountry = c.cCountry,
                               nCountryid = c.nCountryid,
                           }).ToList();

I also saved the original list so when I backspace I can roll bak to the original:
 List<Country> OriginalList = new List<Country>();
and
 OriginalList = myusers;

Then in textBox1_TextChanged i did the Linq on the OriginalList:
from c in OriginalList as List<Country>
insteaqd of on the datasource of  listBox1



public partial class frmTest : Form
    {
        dcTestDataContext db = new dcTestDataContext();
        List<Country> OriginalList = new List<Country>();
        public frmTest()
        {
            InitializeComponent();
        }

        private void frmTest_Load(object sender, EventArgs e)
        {
            var myusers = (from c in db.countries
                          orderby c.country1
                          select new Country
                          {
                              cCountry = c.country1,
                              nCountryid = c.countryid,
                              
                          }).ToList();
            OriginalList = myusers;
            listBox1.DisplayMember = "cCountry";
            listBox1.ValueMember = "nCountryid";
            listBox1.DataSource = myusers;
 
        }

        public class Country
        {
            public int nCountryid { get; set; }
            public string cCountry { get; set; }
            
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //listBox1.DataSource
            var myusers = (from c in OriginalList as List<Country>
                           where c.cCountry.Substring(0, Math.Min(textBox1.Text.Length, c.cCountry.Length)) == textBox1.Text
                           orderby c.cCountry
                           select new Country
                           {
                               cCountry = c.cCountry,
                               nCountryid = c.nCountryid,
                           }).ToList();

            listBox1.DisplayMember = "cCountry";
            listBox1.ValueMember = "nCountryid";
            listBox1.DataSource = myusers;

        }
    }

Open in new window

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial