0

I have created a Search button and an associated texbox in Windows Forms to search through a DataGridView. The DGV shows information in a BindingList. The BindingList has the properties PartID, Name, Price, Instock, Min and Max which are of the types int, string, decimal, int, int and int. I can get the search to function properly but the code itself looks clunky. How can I make my 'for' loop search through the BindingList with less code?

for (int i = 0; i < Inventory.AllParts.Count; i++)
{
    //I would like to condense this if statement into one line of code
    if (Inventory.AllParts[i].PartID.ToString().Contains(partsSearchTextBox.Text.ToString())
        || Inventory.AllParts[i].Name.ToString().Contains(partsSearchTextBox.Text.ToString())
        || Inventory.AllParts[i].Price.ToString().Contains(partsSearchTextBox.Text.ToString())
        || Inventory.AllParts[i].Instock.ToString().Contains(partsSearchTextBox.Text.ToString())
        || Inventory.AllParts[i].Min.ToString().Contains(partsSearchTextBox.Text.ToString())
        || Inventory.AllParts[i].Max.ToString().Contains(partsSearchTextBox.Text.ToString()))
    {
        dgvParts.Rows[i].Selected = true;
        found = true;
    }
}
Chap
  • 61
  • 9

1 Answers1

2

You can for example refactor like this:

bool CheckOR(Func<string, bool> predicate, params object[] values)
{
  //if ( predicate == null ) return false;
  foreach ( object value in values )
    if ( predicate(value.ToString()) )
      return true;
  return false;
}

for ( int i = 0; i < Inventory.AllParts.Count; i++ )
{
  if ( CheckOR(s => s.Contains(partsSearchTextBox.Text)
               Inventory.AllParts[i].PartID,
               Inventory.AllParts[i].Name,
               Inventory.AllParts[i].Price,
               Inventory.AllParts[i].Instock,
               Inventory.AllParts[i].Min,
               Inventory.AllParts[i].Max) )
  {
    dgvParts.Rows[i].Selected = true;
    found = true;
  }
}

Using Linq:

bool CheckOR(Func<string, bool> predicate, params object[] values)
{
  return values.Any(v => predicate(v.ToString()));
}

Simplified to:

for ( int i = 0; i < Inventory.AllParts.Count; i++ )
{
  var values = new object[]
  {
    Inventory.AllParts[i].PartID,
    Inventory.AllParts[i].Name,
    Inventory.AllParts[i].Price,
    Inventory.AllParts[i].Instock,
    Inventory.AllParts[i].Min,
    Inventory.AllParts[i].Max
  };
  if ( values.Any(v => v.ToString().Contains(partsSearchTextBox.Text)) )
  {
    dgvParts.Rows[i].Selected = true;
    found = true;
  }
}

More detail is needed to further improve in case it is possible, and maybe reflection can be used because if all fields are checked we can parse properties. Or a predefined array with names of properties could be used.

Also you can use filters using this BindingListView that works fine and great.

There is BindingSource.Filter, but it does not work on the standard BindingList.

Related questions

Applying a filter to a BindingSource, but it doesn't work

Filter BindingSource when DataSource is a BindingList

DataGridView Filter a BindingSource with a List of object as DataSource

Filtering BindingList

Filtering BindingSource and DataGridView

C# filter objects with BindingSource in DataGridView

  • Thank you. I wasn't familiar with LinQ or refractoring. – Chap Jun 13 '21 at 04:44
  • 1
    [Linq 1](https://www.tutorialspoint.com/linq/index.htm) | [Linq 2](https://www.webtrainingroom.com/linq) | [LINQ (MSDocs)](https://learn.microsoft.com/dotnet/csharp/programming-guide/concepts/linq/) | [Deferred Execution of LINQ Query](https://www.tutorialsteacher.com/linq/linq-deferred-execution) | [Deferred Vs Immediate Query Execution in LINQ](https://www.c-sharpcorner.com/UploadFile/rahul4_saxena/deferred-vs-immediate-query-execution-in-linq/) | [Deferred execution and lazy evaluation](https://learn.microsoft.com/dotnet/standard/linq/deferred-execution-lazy-evaluation) –  Jun 13 '21 at 04:47