gpt4 book ai didi

c# - Linq to sql,在datagridview中过滤结果

转载 作者:行者123 更新时间:2023-11-30 17:24:19 26 4
gpt4 key购买 nike

我有一个非常简单的数据库,正在使用linq to sql。
我有一个datagridview来显示表的内容。我希望用户能够过滤出现在datagridview中的行,如果可能的话,无需对数据库进行另一个查询(我的资源确实很低,所以解决方案必须尽可能快)。

我考虑过使用BindingSource类的Filter属性,因此我创建了一个,将DataSource属性设置为linq to sql表达式。当用户添加过滤器时,我设置了Filter属性。半个小时后,我发现BindingSource不支持过滤。地狱,太好了;但是那又是什么呢?在使用Google再花了半个小时之后,发现基本上没有可用的东西之后,我决定使用System.Collections.Generic.List来存储行,因为我能够过滤这些行。没关系,但是我还需要存储原始列表(以防用户删除过滤器),并且我还需要支持多个过滤器。

因此,我有两个列表:一个包含查询结果的所有行,另一个包含满足过滤条件的行。不过,我没有使用多个过滤器进行测试。

那行得通,尽管这不是一个很好的解决方案(至少我没有发现它具有吸引力),但这就是我所能得到的。我决定编写一个包装器类,因为以后可能需要重用此解决方案。我基于以下理论,考虑创建一个FilteredList类(在我用Google进行了一些搜索并且没有找到任何现有的实现之后):


我将列表中的所有行存储在列表中,
我将过滤器(即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似乎没有接受它作为DataSource:没有抛出异常,简单地,什么也没出现(没有出现一个空的datagridview,但是什么也没出现-没有列,也没有添加任何内容的空行项)。好吧,好吧,这很奇怪。我尝试将_FilteredSource直接设置为数据源,这很好-直到我添加过滤器并尝试向下滚动时出现错误:System.IndexOutOfRangeException:索引180没有值。

屏幕截图:
alt text http://shadow.crysis.hu/dgv_error.png

老实说,我不知道怎么了。我试图调用DataGridView的Invalidate,Update和Refresh方法-相同的结果。

所以...


我如何使用linq to sql有效地过滤出现在DataGridView中的结果?
为什么我不能将FilteredList用作DataGridView的数据源?
上面的代码有什么问题?


非常感谢您的时间(如果您已阅读所有内容)和帮助(提前)!



因此,我尝试遵循Marc Gravell的建议,并实现了System.Collections.IList接口,而不是通用接口。它起作用了,所以我可以将它绑定到DataGridView的DataSource属性,并显示所有行,但是当我添加一个过滤器并开始向下滚动时(由于某些原因,直到我开始滚动时,列表才会刷新- Invalidate(),Refresh()和Update()对此无济于事),它开始提供那些怪异的IndexOutOfRangeException-s作为DataError-s。

任何想法如何做这些东西?我不敢相信使用datagridview的linq to sql太难了(对不起,但这变得荒谬)...

最佳答案

要使用DataGridView,您需要实现非通用的IList,而不是通用的IList<T>(或更简单更好的方法:继承自BindingList<T>,后者通过INotifyPropertyChanged提供更改通知)。对于使用LINQ-to-SQL,我有一些info on usenet可能有用(假设它仍然可以容纳水-已经有一段时间了)。

关于“剩下的问题” ...您能更具体一点吗?

重新有效地过滤LINQ-to-SQL,您不想使用Predicate<T>;您想使用Expression<Func<T,bool>>;这使您可以通过Queryable.Where将其传递给数据库,例如(您有IQueryable<T>源的地方),例如:

IQueryable<T> data = tableSource;
// then for each filter "expr"
{
data = data.Where(expr);
}


编写一个真正的过滤列表非常棘手。我已经完成了内存中对象的操作(尽管我无法发布代码),但是它需要进行大量对象跟踪等操作。除非您绝对需要此操作,否则保持事情简单并只显示简单可能会更容易快照,仅跟踪添加/删除。对于简单的快照,只需 ToBindingList()就可以了...

关于c# - Linq to sql,在datagridview中过滤结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1172329/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com