我正在为。net寻找一个数据感知网格,该网格已针对底层数据集的重复更改进行了优化。我将给出一个示例来说明我所说的在这种情况下的优化是什么意思,因为几乎所有网格都允许更改数据源。但是回到OCX时代,改变数据源会给数据感知网格带来问题。
这个数据感知的数据驱动网格不能使用整数行句柄。必须使用GUID行句柄。这是这个网格最重要的要求。
底层数据集的每一行都被分配了一个GUID rowHandle,而不是一个整数,并且无论数据row是如何排序或分组的,数据row的GUID rowHandle都与它保持一致,并且数据row可以通过其rowHandle立即检索。
网格的FocusedRowChanged事件在当前焦点行的GUID与最近具有焦点的行的GUID不相同时被触发。[编辑:在使用整数行句柄的网格中,通常情况下,当数据源更改时,FocusedRowChanged事件不会触发,因为焦点行位置没有改变;例如,焦点在数据源更改前的第一行,焦点在数据源更改后的第一行;整数行句柄是相同的,即使底层行数据完全不同。]
我希望网格在其行为中真正具有数据感知和数据驱动;例如
Grid.GroupByColumnNames = {"customername","city"};
Grid.Groups["customername"].ExpandedValues = {"Acme Widgets", "Foo Industrial"};
Grid.Groups["city"].ExpandedValues = {"New York","Miami"};
现在,如果我清除了上面网格底层的数据集,并用另一个数据集替换它的数据源,该数据源也有客户名和城市列,并在该列中包含值Acme Widgets和Foo Industrial,网格将按客户名和城市列分组新数据集,并展开这些公司(如果PreserveGroupingsWhenDataSetChanges标志设置为True)。
这个问题有一个根本的错误,这就是为什么几个月来没有人给出一个好的答案。即使数据的主键是GUID,也不能证明控件的行句柄是GUID。事实上,这是一个非常糟糕的主意。guid是128位(16字节),而int通常是32位——但比位数(比如在某些环境中是64位)更重要的是int操作是原子的,这意味着你可以在线程之间读写int而不需要锁定,而且性能更高。因此guid具有更高的内存占用和更高的处理成本(每个读/写都是多个操作)。
因此,任何控件都应该使用快速/精简的代码,并在必要时引用数据源来获取主键或其他数据位。
我对网格的经验和思考
我碰巧喜欢DevExpress控件的winforms,也使用他们的数据层组件XPO。然而,有多个组件供应商提供类似的控件和数据层(它们通常都具有将rowhandle与数据主键分离的特性)。在DevExpress中,他们有一个出色的网格,它是数据感知的,并为您提供了大量的事件,以便您绑定各种可能的更改。
XPO数据层可以使用任何类型的主键,包括int或Guid。我和许多其他开发人员一起使用Guids,因为它能够从远程机器或离线数据插入主键(我不能说我曾经负责过一个表中有超过20亿条记录的数据库,但也许你是)。虽然数据的主键可能是GUID,但行句柄仍然是int型。这将在幕后比Guid快得多。但是,它们仍然提供了许多在可视化索引、行句柄和数据源索引之间来回切换的方法,以及一些通过行句柄获取底层数据源行的方法。这在许多提供行句柄(不是数据主键)的控件事件中很有用,在这些事件中,您只需通过一行代码通过行句柄抓取数据源记录。
同样,一般来说,如果像上面的伪代码那样使用基于字符串的索引器访问集合,组件只需在后台执行List.IndexOf()
类型的调用,然后将其作为int索引传递给索引器。因此,您实际上仍然在幕后使用基于int的索引。即使某些组件公司将guid用于rowhandle,他们也会在幕后将这些guid放入哈希集或字典中以查找实际使用的int索引。因此,无论如何,它都只是在int之上的层,所以它们只是抽象的,如果你需要的话,让你在代码中实现这种东西(而不是将其构建到组件库中)。
底线是,我认为你可以用DevExpress Grid完成上面描述的所有事情,但必须放弃GUID rohandles并稍微改变你的策略。如果应用程序需要这种反向查找,您可能需要构建自己的GUID来将索引作为哈希集或字典来处理。如果所有的行句柄都是guid,这样可以避免性能问题,但仍然可以在guid和行句柄之间进行向前和向后转换。