Filter functionality Project using C# I am simply implementing a filter function for one my forms. I'd like to hear some reviews where I can improve in my code or my functionality  :)
Summary
I have 1 textbox and 2 comboboxes (See image below):

Category options

Status options

Code
public MainView()
{
    InitializeComponent();
    categoryText.SelectedIndex = 0;
    statusText.SelectedIndex = 0;

    RefreshData();
}

List&lt;ConcessionModel&gt; concessionList = new List&lt;ConcessionModel&gt;();
public void RefreshData()
{
    DataAccess db = new DataAccess();
    concessionList = db.LoadConcessionLog();
    dataGrid.DataSource = concessionList;

    dataGrid.Columns[&quot;Id&quot;].Visible = false;
    dataGrid.Columns[&quot;PersonCompletingID&quot;].Visible = false;
}


private void searchBtn_Click(object sender, EventArgs e)
{
    dataGrid.DataSource = Filter(productText.Text, categoryText.Text, statusText.Text);
}

private List&lt;ConcessionModel&gt; Filter(string product, string category, string status)
{
    if (category == &quot;All&quot; &amp;&amp; status != &quot;All&quot;)
    {
        return concessionList
                .Where(x =&gt; x.Product
                .IndexOf(product, StringComparison.InvariantCultureIgnoreCase) &gt;= 0 &amp;&amp; x.Status
                .IndexOf(status, StringComparison.InvariantCultureIgnoreCase) &gt;= 0)
                .ToList();
    }
    else if (category != &quot;All&quot; &amp;&amp; status == &quot;All&quot;)
    {
        return concessionList
                .Where(x =&gt; x.Product
                .IndexOf(product, StringComparison.InvariantCultureIgnoreCase) &gt;= 0 &amp;&amp; x.Category
                .IndexOf(category, StringComparison.InvariantCultureIgnoreCase) &gt;= 0)
                .ToList();
    }
    else if(category == &quot;All&quot; &amp;&amp; status == &quot;All&quot;)
    {
        return concessionList
                .Where(x =&gt; x.Product
                .IndexOf(product, StringComparison.InvariantCultureIgnoreCase) &gt;= 0).ToList();
    }
    else
    {
        return concessionList
                .Where(x =&gt; x.Product
                .IndexOf(product, StringComparison.InvariantCultureIgnoreCase) &gt;= 0 &amp;&amp; x.Category
                .IndexOf(category, StringComparison.InvariantCultureIgnoreCase) &gt;= 0 &amp;&amp; x.Status
                .IndexOf(status, StringComparison.InvariantCultureIgnoreCase) &gt;= 0)
                .ToList();
    }
}

public void ClearConcessionFilter()
{
    productText.Clear();
    categoryText.SelectedIndex = 0;
    statusText.SelectedIndex = 0;
    dataGrid.DataSource = concessionList;
}

ConcessionModel
public class ConcessionModel
{
    public int Id { get; set; }

    [DisplayName(&quot;Date Created&quot;)]
    public DateTime DateCreated { get; set; }

    public int PersonCompletingID { get; set; }
    public string Product { get; set; }

    [DisplayName(&quot;Batch Number&quot;)]
    public string BatchNumber { get; set; }

    [DisplayName(&quot;Quantity Affected&quot;)]
    public string QuantityAffected { get; set; }

    [DisplayName(&quot;Reason For Concession&quot;)]
    public string ReasonForConcession { get; set; }

    public string Category { get; set; }
    public string Status { get; set; }
}
Let me focus on the Filter method.

There are a lot of repetitions in that method, which makes your code

harder to maintain

for example: replacing IndexOf to Equals
or by changing the StringComparison option to another


and more error-prone

for example: it is easy to misspell the All at one of the occurrences.





There are a couple of useful techniques that can make your code less error-prone and easier to change:

Using constants, like: const string all = &quot;All&quot;;
Using single return, like: return concessionList.Where(predicate).ToList();
Extracting common logic, like:

static bool IsPresent(string source, string target)
   =&gt; source.IndexOf(target, StringComparison.InvariantCultureIgnoreCase) &gt;= 0;


Using default values instead of fallback,

like: predicate can have default value instead of relying on a
final else block.



With these in our hand the Filter method could be rewritten like this:
private List&lt;ConcessionModel&gt; Filter(string product, string category, string status)
{
    const string all = &quot;All&quot;;

    static bool IsPresent(string source, string target) 
        =&gt; source.IndexOf(target, StringComparison.InvariantCultureIgnoreCase) &gt;= 0;

    Func&lt;ConcessionModel, bool&gt; predicate = model =&gt;
        IsPresent(model.Product, product) &amp;&amp;
        IsPresent(model.Category, category) &amp;&amp; 
        IsPresent(model.Status, status);

    if (category == all &amp;&amp; status != all)
    {
        predicate = model =&gt;
            IsPresent(model.Product, product) &amp;&amp;
            IsPresent(model.Status, status);
    }
    else if (category != all &amp;&amp; status == all)
    {
        predicate = model =&gt;
            IsPresent(model.Product, product) &amp;&amp;
            IsPresent(model.Category, category);
    }
    else if (category == all &amp;&amp; status == all)
    {
        predicate = model =&gt;
            IsPresent(model.Product, product);
    }
    
    return concessionList.Where(predicate).ToList();
}


predicate: I've defined a function variable (Func&lt;TInput, TOutput&gt;)

It receives a ConcessionModel (as TInput)
and will return with a bool (as TOutput).


So, I have defined a function which implementation varies based on the input parameters.
We use this function as a filter condition (Where) against the data source (concessionList)

Here I have used the short form, but could be written like this:

return concessionList.Where(model =&gt; predicate(model)).ToList();