need a truly data-aware and data-driven grid for .NET that uses GUIDs as row-handles

219 views Asked by At

I am looking for a data-aware grid for .NET that has been optimized for repeated changes of the underlying dataset. I will give an example to show what I mean by optimized in that context, since almost all grids let you change the datasource. But going way back to the OCX days, changing the datasource has caused problems for data-aware grids.

This data-aware data-driven grid must not use integer row handles. It must use GUID row handles. That is the single most important requirement of this grid.

Each row of the underlying dataset is assigned a GUID rowHandle, not an integer, and no matter how the datarows happen to be sorted or grouped, a datarow's GUID rowHandle stays with it, and a datarow can be instantly retrieved by its rowHandle.

The grid's FocusedRowChanged event is fired when the GUID of the currently focused row is not the same as the GUID of the row that most recently had the focus. [EDIT: In a grid that uses integer row handles, it's often the case that when the datasource is changed the FocusedRowChanged event will not fire because the focused-row-position has not changed; e.g. the focus was on the first row before the datasource change and the focus is on the first row after the datasource change; the integer row handle is the same even though the underlying row data is completely different.]

I want the grid to be truly data-aware and data-driven in its behavior; e.g.

Grid.GroupByColumnNames = {"customername","city"};
Grid.Groups["customername"].ExpandedValues = {"Acme Widgets", "Foo Industrial"};
Grid.Groups["city"].ExpandedValues = {"New York","Miami"};

Now, if I cleared the dataset the underlies the grid above and substituted another dataset for its datasource, which also had customername and city columns, and contained values Acme Widgets and Foo Industrial in that column, the grid would group the new dataset by the customername and city columns, and expand those companies (if a PreserveGroupingsWhenDataSetChanges flag is set to True).

1

There are 1 answers

0
BenSwayne On

There is something fundamentally wrong with this question which is why after several months nobody has provided a good answer. Even if your data's primary key is a GUID it does not justify having the row handles for a control being GUIDs. In fact this is a pretty bad idea. GUIDs are 128 bits (16 bytes) while ints are generally 32-bits - but more important than the number of bits (say it was 64 in certain environments) is that int operations are atomic meaning you can read/write an int without locking between threads and is higher performance. So GUIDs have higher memory footprint and higher cost for processing (reading/writing would be multiple operations each).

So really any control should be using fast/lean code visually and just referencing the datasource when necessary to fetch the primary key or other bits of data.

My Experience With and Thoughts About Grids

I happen to like DevExpress controls for winforms and also use their data layer component XPO. However there are multiple component vendors with similar controls and data layers (which generally all share the feature of separating rowhandles from data primary keys).

In DevExpress they have an excellent grid which is Data Aware and provides a multitude of events for you to tie into for all sorts of possible changes.

There XPO datalayer can use anything for a primary key including either an int or Guid. I use Guids along with a lot of other developers due to the ability to insert primary keys from remote machines or offline data (I can't say I've ever been responsible for a database with more than 2 billion records in a table, but maybe you are).

While the primary key for my data may be a GUID the row handles are still ints. This will be significantly faster behind the scenes than an Guid would be. However, they still provide a bunch of methods for going back and forth between the visual index, row handle, and data source index as well as a few methods for fetching the underlying data source row by the row handle. This is useful inside many of the control's events which provide row handles (not data primary keys) where you'll simply grab the data source record by the rowhandle with one line of code.

Also, generally speaking, if you access a collection using a string based indexer as in your pseudo code above, components simply do an List.IndexOf() kind of call behind the scenes which is then passed on to the indexer as an int index. So you are really still working with int based indexes behind the scenes. Even if some component company used GUIDs for rowhandles, they'd be putting those GUIDs into a hashset or dictionary behind the scenes to lookup the int index to actually use. So it'd all just be layers on top of ints anyway, so they just leave it abstract and let you implement this kind of stuff in your code if you need it (as opposed to building it into a component library).

Recommendation

The bottom line is that I think you can accomplish everything you described above with the DevExpress Grid but will have to let go of the GUID rowhandles and change your strategy a little. You may need to build your own GUID to rowhandle index as a hashset or dictionary if your application requires this kind of reverse lookup. This saves you from the performance issues if all row handles were always GUIDs but still gives you both forwards and backwards translation between GUIDs and rowhandles.