Link to home
Start Free TrialLog in
Avatar of EylonM
EylonM

asked on

Incremental search on arrays or lists

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
Avatar of EylonM
EylonM

ASKER

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

Avatar of EylonM

ASKER

Thanks

Doesn't compile on countryList = mCountries.ToList<Country>();
Avatar of EylonM

ASKER

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
Could you please post the error message? Also have you defined a class named Country ?
Avatar of EylonM

ASKER

Yes, I defined a class named Country.  

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

Avatar of Fernando Soto
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

Avatar of EylonM

ASKER

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

ASKER CERTIFIED SOLUTION
Avatar of Fernando Soto
Fernando Soto
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of EylonM

ASKER

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

Avatar of EylonM

ASKER

Oops.  Ok, I understand.  Nice.  I will give it a try.
Avatar of EylonM

ASKER

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