I originally set the datasource of the DGV to a SortableBindingList. When I run the program, I am able to click any column header and sort ascending or descending by the column.
I have implemented a Filter textbox that filters the data in the DGV using LINQ. After I filter the list with LINQ. I rebind the filtered list to the DGV, but the previously sorted column is no longer sorted.
Should the DGV keep sorting even after I rebind a new datasource?
The only workaround I have come up with for this is to store the current SortedColumn Index and current SortOrder into variables and then reset those properties when binding the new datasource.
private void PopulateGrid()
{
var gridSource = new MySortableBindingList<Case>(_caseList);
dataGridView_Cases.DataSource = gridSource;
ConfigureGrid();
}
private void ApplyFilter(string fString)
{
MySortableBindingList<Case> msbList = new MySortableBindingList<Case>(_caseList.Where(x => (x.StudentLastName.IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0) || (x.StudentIDDisplay.ToString().IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0)).ToList());
dataGridView_Cases.DataSource = msbList;
}
Update 1: (New Code)
private MySortableBindingList<Case> _gridSource = new MySortableBindingList<Case>();
BindingSource _caseBindingSource = new BindingSource();
private void PopulateGrid()
{
_gridSource = new MySortableBindingList<Case>(_caseList);
_caseBindingSource.DataSource = _gridSource;
dataGridView_Cases.DataSource = _caseBindingSource;
ConfigureGrid();
}
private void ApplyFilter(string fString)
{
_gridSource.Clear();
foreach (var fCase in _caseList.Where(x => (x.StudentLastName.IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0) || (x.StudentIDDisplay.ToString().IndexOf(fString, StringComparison.OrdinalIgnoreCase) >= 0)).ToList())
{
_gridSource.Add(fCase);
}
_caseBindingSource.ResetBindings(false);
}
Update 2: (Additional Code)
/// <summary>
/// Source: http://www.codeproject.com/Articles/31418/Implementing-a-Sortable-BindingList-Very-Very-Quic
/// </summary>
/// <typeparam name="T"></typeparam>
public class MySortableBindingList<T> : BindingList<T>
{
// reference to the list provided at the time of instantiation
List<T> originalList;
ListSortDirection sortDirection;
PropertyDescriptor sortProperty;
// function that refereshes the contents
// of the base classes collection of elements
Action<MySortableBindingList<T>, List<T>>
populateBaseList = (a, b) => a.ResetItems(b);
// a cache of functions that perform the sorting
// for a given type, property, and sort direction
static Dictionary<string, Func<List<T>, IEnumerable<T>>>
cachedOrderByExpressions = new Dictionary<string, Func<List<T>,
IEnumerable<T>>>();
/// <summary>
/// Create a sortable binding list
/// </summary>
public MySortableBindingList()
{
originalList = new List<T>();
}
/// <summary>
/// Create a sortable binding list
/// </summary>
public MySortableBindingList(IEnumerable<T> enumerable)
{
originalList = enumerable.ToList();
populateBaseList(this, originalList);
}
/// <summary>
/// Create a sortable binding list
/// </summary>
public MySortableBindingList(List<T> list)
{
originalList = list;
populateBaseList(this, originalList);
}
/// <summary>
/// Look for an appropriate sort method in the cache if not found .
/// Call CreateOrderByMethod to create one.
/// Apply it to the original list.
/// Notify any bound controls that the sort has been applied.
/// </summary>
/// <param name="prop"></param>
/// <param name="direction"></param>
protected override void ApplySortCore(PropertyDescriptor prop,
ListSortDirection direction)
{
/*
Look for an appropriate sort method in the cache if not found .
Call CreateOrderByMethod to create one.
Apply it to the original list.
Notify any bound controls that the sort has been applied.
*/
sortProperty = prop;
var orderByMethodName = sortDirection ==
ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
var cacheKey = typeof(T).GUID + prop.Name + orderByMethodName;
if (!cachedOrderByExpressions.ContainsKey(cacheKey))
{
CreateOrderByMethod(prop, orderByMethodName, cacheKey);
}
ResetItems(cachedOrderByExpressions[cacheKey](originalList).ToList());
ResetBindings();
sortDirection = sortDirection == ListSortDirection.Ascending ?
ListSortDirection.Descending : ListSortDirection.Ascending;
}
private void CreateOrderByMethod(PropertyDescriptor prop,
string orderByMethodName, string cacheKey)
{
/*
Create a generic method implementation for IEnumerable<T>.
Cache it.
*/
var sourceParameter = Expression.Parameter(typeof(List<T>), "source");
var lambdaParameter = Expression.Parameter(typeof(T), "lambdaParameter");
var accesedMember = typeof(T).GetProperty(prop.Name);
var propertySelectorLambda =
Expression.Lambda(Expression.MakeMemberAccess(lambdaParameter,
accesedMember), lambdaParameter);
var orderByMethod = typeof(Enumerable).GetMethods()
.Where(a => a.Name == orderByMethodName &&
a.GetParameters().Length == 2)
.Single()
.MakeGenericMethod(typeof(T), prop.PropertyType);
var orderByExpression = Expression.Lambda<Func<List<T>, IEnumerable<T>>>(
Expression.Call(orderByMethod,
new Expression[] { sourceParameter,
propertySelectorLambda }),
sourceParameter);
cachedOrderByExpressions.Add(cacheKey, orderByExpression.Compile());
}
/// <summary>
/// RemoveSortCore
/// </summary>
protected override void RemoveSortCore()
{
ResetItems(originalList);
}
private void ResetItems(List<T> items)
{
base.ClearItems();
for (int i = 0; i < items.Count; i++)
{
base.InsertItem(i, items[i]);
}
}
/// <summary>
/// SupportsSortingCore
/// </summary>
protected override bool SupportsSortingCore
{
get
{
// indeed we do
return true;
}
}
/// <summary>
/// Ascending or descending
/// </summary>
protected override ListSortDirection SortDirectionCore
{
get
{
return sortDirection;
}
}
/// <summary>
/// A property
/// </summary>
protected override PropertyDescriptor SortPropertyCore
{
get
{
return sortProperty;
}
}
/// <summary>
/// List has changed
/// </summary>
/// <param name="e"></param>
protected override void OnListChanged(ListChangedEventArgs e)
{
originalList = base.Items.ToList();
}
}