我有我使用LINQ to SQL中的其中非常简单的数据库。 我有一个DataGridView以显示表的内容。 我希望用户能够过滤出现在DataGridView行,如果可能的话未做另一个数据库查询(我是真的资源低,因此该解决方案必须尽可能快)。
我想过使用的BindingSource类中的过滤性能,所以我创建一个DataSource属性设置为LINQ to SQL的表达。 当用户添加了一个过滤器,我设置了Filter属性。 像半一小时后,我发现,这BindingSource的不支持筛选。 该死的,伟大的; 那么是什么呢? 再花半小时使用谷歌和发现基本没什么可用之后,我deceided使用System.Collections.Generic.List存储行,因为我能够筛选。 这是所有的权利,但我也需要存储原始列表(万一用户删除一个过滤器),我还需要支持多个过滤器。
所以,我有两个解释:一个查询结果的所有行和一个与满足过滤器的条件的行。 我没有以多个滤波器测试,虽然。
这工作,虽然它不是一个非常好的解决方案(至少我没有发现它吸引人),但是这是所有我已经得到了。 我deceided写一个包装类,因为我可能需要在以后重新使用该解决方案随时随地。 我认为有关创建FilteredList类(后我做了一些搜索与谷歌,并没有发现任何现有的实现),基于以下原理:
- 我与存储在表中的所有行的列表,
- 我保存的过滤器(这是Predictate表达式)在的BindingList(这样我就可以知道,如果列表改变和重新筛选行)
- 将过滤后的行存储在一个列表,作为一个高速缓存时,有没有源列表或过滤器上进行修改,
- 我保持一个布尔值(_NeedsRefiltering)意味着现有的过滤器是否没有施加在源行再生缓存,
- 这个类必须实现IList接口,因此它可以作为DataGridView的数据源。
这里说到我FilteredList类的源代码:
public class FilteredList<T> : IList<T>
{
private bool _NeedsReFiltering = false;
private BindingList<Predicate<T>> _Filters;
public BindingList<Predicate<T>> Filters
{
get
{
if (this._Filters == null)
{
this._Filters = new BindingList<Predicate<T>>();
this._Filters.RaiseListChangedEvents = true;
this._Filters.ListChanged += delegate(object sender, ListChangedEventArgs e)
{
this._NeedsReFiltering = true;
};
}
return this._Filters;
}
set
{
this._Filters = value;
this._NeedsReFiltering = true;
}
}
private List<T> _Source;
public List<T> Source
{
get
{
return this._Source;
}
set
{
this._Source = value;
this._NeedsReFiltering = true;
}
}
private List<T> __FilteredSource = new List<T>();
private List<T> _FilteredSource
{
get
{
if (this._NeedsReFiltering)
{
this._NeedsReFiltering = false;
this.Refilter();
}
return this.__FilteredSource;
}
set
{
this.__FilteredSource = value;
}
}
public List<T> FilteredSource // Only for setting it as the DataGridView's DataSource - see my comments after the code
{
get
{
return this._FilteredSource;
}
}
public FilteredList()
{
this._Source = new List<T>();
}
public FilteredList(int capacity)
{
this._Source = new List<T>(capacity);
}
public FilteredList(IEnumerable<T> source)
{
this._Source = new List<T>(source);
this._NeedsReFiltering = true;
}
public void Refilter()
{
this.__FilteredSource = this._Source;
if (this._Filters == null)
{
return;
}
foreach (var filter in this._Filters)
{
this.__FilteredSource.RemoveAll(item => !filter(item));
}
}
public int IndexOf(T item)
{
return this._FilteredSource.IndexOf(item);
}
public void Insert(int index, T item)
{
this._FilteredSource.Insert(index, item);
this._Source.Add(item);
}
public void RemoveAt(int index)
{
//this._Source.RemoveAt(index);
this._Source.Remove(this.__FilteredSource[index]);
this._NeedsReFiltering = true;
}
public T this[int index]
{
get
{
return this._FilteredSource[index];
}
set
{
this._Source[this._Source.FindIndex(item => item.Equals(this._FilteredSource[index]))] = value;
this._NeedsReFiltering = true;
}
}
public void Add(T item)
{
this._Source.Add(item);
this._NeedsReFiltering = true;
}
public void Clear()
{
this._Source.Clear();
this._FilteredSource.Clear();
this._NeedsReFiltering = false;
}
public bool Contains(T item)
{
return this._FilteredSource.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
this._FilteredSource.CopyTo(array, arrayIndex);
}
public int Count
{
get { return this._FilteredSource.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
var r = this._Source.Remove(item);
this._FilteredSource.Remove(item);
return r;
}
public IEnumerator<T> GetEnumerator()
{
return this._FilteredSource.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this._FilteredSource.GetEnumerator();
}
}
我曾因为两个列表(源列表和过滤列表)的一些问题,但我想我已经正确地处理它们。 或者,也许我没有,因为DataGridView中似乎并不接受它作为数据源:未见异常抛出,简单地说,似乎没有什么(似乎没有一个空的DataGridView,但什么都没有 - 而不是列,也不是一个空行来添加更多项目)。 好吧,好吧,那是不可思议。 我试图直接设置_FilteredSource作为数据源,这是很好 - 直到我加入了筛选,并试图当我得到的错误向下滚动:System.IndexOutOfRangeException:索引180不具有价值。
截图: 替代文字http://shadow.crysis.hu/dgv_error.png
说实话,我不知道什么是错的。 我曾试着拨打的DataGridView的一个invalidate,更新和刷新方法 - 同样的结果。
所以...
- 我怎么能高效过滤器使用的LINQ to SQL在DataGridView出现的结果吗?
- 为什么我不能用我的FilteredList作为DataGridView的数据源?
- 什么是与上面的代码的问题?
非常感谢您的宝贵时间(如果你读这一切)和帮助(提前)!
所以,我试图遵循什么马克Gravell建议,并实施了System.Collections.IList接口,而不是普通的一个。 它的工作,这样我就可以把它绑定到DataGridView的DataSource属性,它显示的所有行,但我添加了一个过滤器,并开始向下滚动(出于某种原因,列表不会刷新,直到我开始滚动 - 无效(),刷新()和Update()不帮助它),它开始给那些怪异IndexOutOfRangeException-S作为DataError-S。
任何想法如何做到这一点的东西? 我不能相信,LINQ用的datagridview为sql吸这么辛苦(抱歉,但这是越来越ridicolous)...