Trapline Trapline - 29 days ago 11
ASP.NET (C#) Question

Filter ListView by TextBox with C#

I have a ListView Control that is displaying a list of jobs. I have a row of LinkButton controls that when clicked sorts the list by the various fields of the job.

I also have a TextBox Control and LinkButton Control on the page.

I want to enter a keyword to filter the ListView by in the TextBox. Upon clicking the LinkButton Control the ListView filter will only show results that have the keyword contained in one of the 4 Modes we are Sorting by (Date,Company,Title,Location).

There is other code and classes I haven't included here and I am new to C# so let me know if I left out a piece that is needed.

TextBox:

<asp:TextBox ID="txtKeySearch" CssClass="form-control" runat="server" />


Button:

<asp:LinkButton ID="lnkbtnKeySearch" runat="server" class="fancy" >
<span>Search <span class="ico-chevron-right"></span></span></asp:LinkButton>


Code Behind:

using Ektron.Custom.SmartForms;
using Ektron.Custom.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;

public partial class Source_Controls_Alumni_AlumniJobListing : System.Web.UI.UserControl
{

// Added Property
private long _containerId = 0;
public long ContainerID
{
get { return _containerId; }
set { _containerId = value; }
}
/////////

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadData(AJVMCompareMode.Date, AJVMSortOrder.ASC);
}
}
private void LoadData(AJVMCompareMode mode, AJVMSortOrder sort)
{
// Added inverted conditional to escape method
// if the _containerId is invalid.
if (_containerId <= 0) return;
///////////

var alumniJobPostManager = new AlumniJobPostManager();

// Whichever folder Id...
var jobs = alumniJobPostManager.GetList(_containerId);

if (jobs != null && jobs.Any())
{
List<AlumniJobPostViewModel> lst = new List<AlumniJobPostViewModel>(jobs);
AlumniJobPostViewModel.Mode = mode;
AlumniJobPostViewModel.SortOrder = sort;
lst.Sort();
uxPhotoGallery.DataSource = lst;
uxPhotoGallery.DataBind();
lblCount.Text = "" + uxPhotoGallery.Items.Count;
}
}
protected void lnkBtnCompany_Click(object sender, EventArgs e)
{
if (AlumniJobPostViewModel.Mode != AJVMCompareMode.Company || AlumniJobPostViewModel.SortOrder == AJVMSortOrder.DESC)
{
LoadData(AJVMCompareMode.Company, AJVMSortOrder.ASC);
}
else
{
LoadData(AJVMCompareMode.Company, AJVMSortOrder.DESC);
}

}
protected void lnkBtnTitle_Click(object sender, EventArgs e)
{
if (AlumniJobPostViewModel.Mode != AJVMCompareMode.Title|| AlumniJobPostViewModel.SortOrder == AJVMSortOrder.DESC)
{
LoadData(AJVMCompareMode.Title, AJVMSortOrder.ASC);
}
else
{
LoadData(AJVMCompareMode.Title, AJVMSortOrder.DESC);
}

}
protected void lnkBtnLocation_Click(object sender, EventArgs e)
{
if (AlumniJobPostViewModel.Mode != AJVMCompareMode.Location || AlumniJobPostViewModel.SortOrder == AJVMSortOrder.DESC)
{
LoadData(AJVMCompareMode.Location, AJVMSortOrder.ASC);
}
else
{
LoadData(AJVMCompareMode.Location, AJVMSortOrder.DESC);
}

}
}


ViewModel:

using System;
using System.Collections;

namespace Ektron.Custom.ViewModels
{
public enum AJVMCompareMode
{
Date,
Company,
Title,
Location
}
public enum AJVMSortOrder
{
ASC,
DESC
}


/// <summary>
/// Provides the fields necessary to display a PressPhoto Smart Form to the site.
/// </summary>
public class AlumniJobPostViewModel : IComparable<AlumniJobPostViewModel>
{
static public AJVMCompareMode Mode { get; set; }
static public AJVMSortOrder SortOrder { get; set; }
public int CompareTo(AlumniJobPostViewModel other)
{
switch (Mode)
{
case AJVMCompareMode.Date:
if (SortOrder == AJVMSortOrder.ASC)
{
return (this.alumniJobDateSub.CompareTo(other.alumniJobDateSub));
}
else
{
return (other.alumniJobDateSub.CompareTo(this.alumniJobDateSub));
}
case AJVMCompareMode.Company:
if (SortOrder == AJVMSortOrder.ASC)
{
return (this.alumniJobCompany.CompareTo(other.alumniJobCompany));
}
else
{
return (other.alumniJobCompany.CompareTo(this.alumniJobCompany));
}
case AJVMCompareMode.Title:
if (SortOrder == AJVMSortOrder.ASC)
{
return (this.alumniJobTitle.CompareTo(other.alumniJobTitle));
}
else
{
return (other.alumniJobTitle.CompareTo(this.alumniJobTitle));
}
case AJVMCompareMode.Location:
if (SortOrder == AJVMSortOrder.ASC)
{
return (this.alumniJobLocation.CompareTo(other.alumniJobLocation));
}
else
{
return (other.alumniJobLocation.CompareTo(this.alumniJobLocation));
}
}
return 0;
}
public string ContentUrl { get; set; }
public long ContentId { get; set; }
public bool alumniJobPostExtranet { get; set; }
public string alumniJobDateSub { get; set; }
public string alumniJobClientNum { get; set; }
public string alumniJobContactAtt1 { get; set; }
public string alumniJobContactAtt2 { get; set; }
public string alumniJobTitle { get; set; }
public string alumniJobCompany { get; set; }
public string alumniJobLocation { get; set; }
public string alumniJobDescription { get; set; }
public string alumniJobCompanyName { get; set; }
public string alumniJobContactName { get; set; }
public string alumniJobContactEmail { get; set; }
public string alumniJobContactPhone { get; set; }
public AlumniJobPostViewModel()
{

}
static AlumniJobPostViewModel()
{
Mode = AJVMCompareMode.Date;
SortOrder = AJVMSortOrder.ASC;
}
}
}

Answer

If you wanted a way to easily integrate such a filter into your existing code, I'd go with a LINQ query right before DataBinding.

Assuming you can get the value and make it available to your LoadData method with sanitation and without help, let's peek at your code that binds the data to the control.

List<AlumniJobPostViewModel> lst = new List<AlumniJobPostViewModel>(jobs);
AlumniJobPostViewModel.Mode = mode;
AlumniJobPostViewModel.SortOrder = sort;
lst.Sort();
uxPhotoGallery.DataSource = lst;
uxPhotoGallery.DataBind();
lblCount.Text = "" + uxPhotoGallery.Items.Count;

Now let's assume we have a variable filterText that contains the string you'd like to use to filter the data set so that it only includes matches against one of your four properties: alumniJobDateSub, alumniJobCompanyName, alumniJobTitle, alumniJobLocation.

List<AlumniJobPostViewModel> lst = new List<AlumniJobPostViewModel>(jobs);
AlumniJobPostViewModel.Mode = mode;
AlumniJobPostViewModel.SortOrder = sort;
lst.Sort();

// Filtering code
lst = lst.Where(x =>
    (x.alumniJobDateSub.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
    (x.alumniJobCompanyName.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
    (x.alumniJobTitle.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
    (x.alumniJobLocation.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1)).ToList();


uxPhotoGallery.DataSource = lst;
uxPhotoGallery.DataBind();
lblCount.Text = "" + uxPhotoGallery.Items.Count;

Assuming the list isn't too large and you already have it in memory (cache) this should perform well enough to meet a basic need.

Added: The above works if you're certain each of the properties you'll be searching have a value (are not null). If one of them is null, you'll see the error above.

To rectify this, change that section so each test has a null check as well as the IndexOf search:

if (!string.IsNullOrEmpty(filterText))
{
    lst = lst.Where(x =>
        (x.alumniJobDateSub != null && x.alumniJobDateSub.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
        (x.alumniJobCompanyName != null && x.alumniJobCompanyName.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
        (x.alumniJobTitle != null && x.alumniJobTitle.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
        (x.alumniJobLocation != null && x.alumniJobLocation.IndexOf(filterText, 0, StringComparison.CurrentCultureIgnoreCase) > -1)).ToList();
}
Comments