在ListCollectionView上虚拟化DataGrid

时间:2015-12-17 10:24:38

标签: wpf data-virtualization

我在自定义列表上使用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只获取它正在显示的行,而不是获取整个表。这样的工作怎么可能?

(P.S。我确保为DataGrid本身启用了虚拟化)

1 个答案:

答案 0 :(得分:1)

将ScrollViewer.CanContentScroll =“True”添加到ListView后似乎解决了问题。