SSMS 中的网格控制

Posted

技术标签:

【中文标题】SSMS 中的网格控制【英文标题】:Grid control in SSMS 【发布时间】:2017-11-05 17:56:50 【问题描述】:

我注意到在 SSMS (SQL Server Management Studio 2016) 中,查询结果在一秒钟内返回(超过 10k+ 行)。结果表/网格滚动非常平滑,并且在 SSMS 上具有极低的内存占用 (~80MB)。这种类似于网格/视图的控制方式执行 ListView(~200MB,2-3 秒)和 DataGrid(~600MB,8-10 秒)。即使我关闭所有可视化或调整 cancententscroll 或修复其高度以优化速度,它们在 SSMS 中的表现仍然远远落后于网格,仍然具有缓慢的滚动和 GUI 操作。

SSMS 中使用的网格控件背后是什么让它如此流畅?

【问题讨论】:

良好的编码实践,从 VB6 开始就可用。不加载 更多 数据而不是显示、滚动和数据虚拟化。 ListView 或 DataGrid 没有任何问题 - SSMS 很可能正在使用其中之一 请注意,您的屏幕截图仅显示 16 行,而不是 10K。当您只显示 16 行时,没有理由将所有 10K 行加载到内存中。您可以加载 100 行并使用虚拟化。当用户向下滚动前 10 条记录时,应用程序已经加载了接下来的 100 条记录,而用户没有注意到 我可以更改图像。即使使用虚拟化,它也不会达到那样的速度。请参阅我的其他网格/虚拟化问题.. 否则我不会开始赏金。任何在 wpf 控件上使用过大数据的人都应该体验过这一点 不,他们没有——他们使用数据绑定和虚拟化,所以他们避免这种情况。您提到的内存大小很大 - 这意味着您将所有结果加载到内存中,并且可能也将所有结果作为行添加到网格中。虚拟化意味着数据在需要时才加载。仅加载 100 行的网格并没有什么呆滞 我猜——它很可能是用 C 开发的自定义组件(或者不太可能是 C++/MFC)。我们要求微软开源它! (opensource.microsoft.com) 【参考方案1】:

SSMS 网格不是 C++,它不是 ListView 也不是 DataGrid,它不使用 Windows 原生控件,它“只是”一个名为 GridControl(在 Microsoft.SqlServer.Management.UI.Grid 命名空间中)的自定义 .NET 控件,属于名为 Microsoft.SqlServer.GridControl.dll 的程序集。

您可以在不同的地方找到它:GAC、%ProgramFiles(x86)%\Common Files\Microsoft Shared\SQL Server Developer Tools%ProgramFiles(x86)%\Microsoft SQL Server Management Studio 18\Common7\IDE、Visual Studio 文件等。

它不是一个可再发行的二进制 AFAIK,所以你不应该发布它,它没有文档记录,也不是像其他的全功能网格。但是,正如您所发现的,它是轻量级的,而且速度很快,与您的底层数据访问一样快。

如果您想使用它,这里有一个小的 Winforms C# 示例(一个 10000 x 256 网格,即立即打开的 250 万个单元格)演示如何使用它:

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.SqlServer.Management.UI.Grid;

namespace WindowsFormsApp1

    public partial class Form1 : Form
    
        private GridControl _control = new GridControl();

        public Form1()
        
            InitializeComponent();

            for (int i = 0; i < 256; i++)
            
                _control.AddColumn(new GridColumnInfo  HeaderType = GridColumnHeaderType.Text, IsUserResizable = true );
                _control.SetHeaderInfo(i, "Column " + i, null);
            

            _control.Dock = DockStyle.Fill;
            _control.GridStorage = new GridStorage();
            Controls.Add(_control);
        
    

    // represents a datasource
    public class GridStorage : IGridStorage
    
        public long EnsureRowsInBuf(long FirstRowIndex, long LastRowIndex)
        
            return NumRows(); // pagination, dynamic load, virtualization, could happen here
        

        public void FillControlWithData(long nRowIndex, int nColIndex, IGridEmbeddedControl control)
        
            // for cell edition
            control.SetCurSelectionAsString(GetCellDataAsString(nRowIndex, nColIndex));
        

        public string GetCellDataAsString(long nRowIndex, int nColIndex)
        
            // get cell data
            return nRowIndex + " x " + nColIndex;
        

        public int IsCellEditable(long nRowIndex, int nColIndex)
        
            return 1; // 1 means yes, 0 means false
        

        public long NumRows()
        
            return 10000;
        

        public bool SetCellDataFromControl(long nRowIndex, int nColIndex, IGridEmbeddedControl control)
        
            // when a cell has changed, you're supposed to change your data here
            return true;
        

        public Bitmap GetCellDataAsBitmap(long nRowIndex, int nColIndex) => throw new NotImplementedException();
        public void GetCellDataForButton(long nRowIndex, int nColIndex, out ButtonCellState state, out Bitmap image, out string buttonLabel) => throw new NotImplementedException();
        public GridCheckBoxState GetCellDataForCheckBox(long nRowIndex, int nColIndex) => throw new NotImplementedException();
    

这就是它的样子。您可以在一台不错的计算机上滚动而不会减慢速度。

【讨论】:

在不依赖 SQL Server 的应用程序中分发此网格的最简单方法是什么? 从技术上讲,我认为您只需将其复制到某个地方即可。从法律上讲,我认为您无权这样做,因为它属于 Microsoft,但我根本不是该领域的专家。

以上是关于SSMS 中的网格控制的主要内容,如果未能解决你的问题,请参考以下文章

如何从网格获取值到c#控制器

在 Kendo UI 网格中控制组顺序

如何使用 Kendo 网格在控制器中显示验证错误消息?

三维变形

Autodesk Forge Viewer 中的三个 JS 限制变换控制运动

删除网格 laravel 的所有数据后,网格的标题仍然存在