我在提供对特定数据库表的读取访问权限的自定义列表上使用 ListCollectionView。下面是自定义列表的定义。
class MaterialCollection : IList
{
#region Fields
private Object syncRoot;
private SQLiteConnection connection;
#endregion
#region IList Interface
public object this[int index]
{
get
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM Materials LIMIT 1 OFFSET @Index";
command.Parameters.AddWithValue("@Index", index);
using (SQLiteDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
return GetMaterial(reader);
}
else
{
throw new Exception();
}
}
}
}
set
{
throw new NotImplementedException();
}
}
public int Count
{
get
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT Count(*) FROM Materials";
return Convert.ToInt32(command.ExecuteScalar());
}
}
}
public bool IsFixedSize
{
get
{
return false;
}
}
public bool IsReadOnly
{
get
{
return true;
}
}
public bool IsSynchronized
{
get
{
return true;
}
}
public object SyncRoot
{
get
{
return this.syncRoot;
}
}
public IEnumerator GetEnumerator()
{
return Enumerate().GetEnumerator();
}
#endregion
#region Constructor
public MaterialCollection(SQLiteConnection connection)
{
this.connection = connection;
this.syncRoot = new Object();
}
#endregion
#region Private Methods
private Material GetMaterial(SQLiteDataReader reader)
{
int id = Convert.ToInt32(reader["Id"]);
string materialNumber = Convert.ToString(reader["MaterialNumber"]);
string type = Convert.ToString(reader["Type"]);
string description = Convert.ToString(reader["Description"]);
string alternateDescription = Convert.ToString(reader["AlternateDescription"]);
string tags = Convert.ToString(reader["Tags"]);
Material material = new Material();
material.Id = id;
material.MaterialNumber = materialNumber;
material.Type = (MaterialType)Enum.Parse(typeof(MaterialType), type);
material.Description = description;
material.AlternateDescription = alternateDescription;
material.Tags = tags;
return material;
}
private IEnumerable<Material> Enumerate()
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM Materials";
using (SQLiteDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return GetMaterial(reader);
}
}
}
}
#endregion
#region Unimplemented Functions
public int Add(object value)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(object value)
{
throw new NotImplementedException();
}
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public int IndexOf(object value)
{
return 0;
}
public void Insert(int index, object value)
{
throw new NotImplementedException();
}
public void Remove(object value)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
#endregion
}
问题是在DataGrid 的初始填充期间,对每一行(即0 到Count - 1)调用this[int index] 方法。
由于该表可能包含数百万行并且读取操作的成本很高(即传统 HDD 上的 SQLite),因此这样的操作是不可接受的。此外,当屏幕只能容纳 50 个左右的项目时,加载所有数百万行是没有意义的。
我想让 DataGrid 只获取它正在显示的行,而不是获取整个表。这样的工作怎么可能?
(PS 我已确保为 DataGrid 本身启用了虚拟化)