LINQ to XtraGrid

If you work with [DevEx] XtraGrid's GridView then you know that it provides a relatively cumbersome way to read values of its grid cells: the values aren't strong typed and the method is somehow not very OO oriented. It goes like this:

// read an int value from a cell int value = (int)gridView.GetRowCellValue(rowHandle, colAnIntColumn);

Note that you can't read the value like this:

int value = (int)gridView.Rows[rowHandle].Value(colAnIntValue); // or int value = gridView.Rows[rowHandle].ColAnIntValue;

which would be more object oriented but probably the performance would suffer. If Value property would be strong typed it would be just great. But the most important feature would be to access the values through Rows collection. Why? Because one could use LINQ to query them. That is unfortunately impossible out of the box.

Here is a simplified sample code to find the rowHandle of the row with SOMEVALUE in one of its colAnIntColumn field:

int rowHandle; for (int f; f<gridView.RowCount; f++) { int value = (int)gridView.GetRowCellValue(rowHandle, intCol); if (value == SOMEVALUE) { rowHandle = f; break; } }

It isn't really pretty, right. Hence the idea of using home made LINQ to XtraGrid.

First, we need a class that will represent a single GridView's row:

public class GridViewRow { internal readonly GridView GridView; internal readonly int RowHandle; public GridViewRow(GridView gridView, int rowHandle) { GridView = gridView; RowHandle = rowHandle; } // method that wraps GetRowCellValue method for getting a cell value // using column name public T Field<T>(string fieldName) { return (T)GridView.GetRowCellValue(RowHandle, fieldName); } // overloaded method that wraps GetRowCellValue method for getting a cell value // using column reference public T Field<T>(GridColumn column) { return (T)GridView.GetRowCellValue(RowHandle, column); } }

The code is pretty trivial. The class has to reference the source GridView and RowHandle that represents a row in GridView's notion. Note the two Field<T> overloaded methods that lets you get cell values in OO manner. Next, we need a collection of GridViewRow objects that implements IEnumerable<T> (IEnumerable<GridViewRow> in this case) interface (which in turn implements IEnumerable hence the two GetEnumerator() methods):

public class EnumerableGridViewRowCollection: IEnumerable<GridViewRow> { internal readonly GridView GridView; public EnumerableGridViewRowCollection(GridView gridView) { this.GridView = gridView; } public IEnumerator<GridViewRow> GetEnumerator() { for (int i = 0; i < GridView.RowCount; i++) yield return new GridViewRow(GridView, i); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }

The core functionality here is public IEnumerator<GridViewRow> GetEnumerator() method. It uses yield return keyword to create GridViewRow instances for each row as query progresses through collection. From the perspective of garbage collection this shouldn't be too huge problem because the objects are small and have a short lifetime usually. Thus they are relatively cheaply garbage collected. Furthermore one doesn't work with million or rows in a grid - if you do, reconsider your approach; but rather in range of thousands. This class also holds reference to source GridView.

Now we have a GridViewRow class that represents a GridView's row and a collection of row objects that are dynamically generated for each query. The only step left is to build a way to get the EnumerableGridViewRowCollection out of GridView. We could use a helper class, pass GridView to EnumerableGridViewRowCollection directly, or derive a class out of GridView and add such a method. However the former aren't really nice and the later is complex and doesn't provide same functionality for other GridView derived views. Fortunately for us .net 3.5 introduced extension methods which are a perfect way to implement this functionality. Here is how I've built it:

public static class GridViewEnumerator { public static IEnumerable<GridViewRow> AsRowEnumerable(this GridView gridView) { return new EnumerableGridViewRowCollection(gridView); } }

This dude adds method AddRowEnumerable to GridView class and to all of derived classes.

LINQ to XtraGrid is now complete and here is rewritten sample query from above:

int rowHandle = gridView.AsRowEnumerable().First( row => row.Field<int>(intCol) == SOMEVALUE);

Doesn't it look nicer and more compact than the query above? The beauty of the LINQ to XtraGrid is that it opens a whole LINQ world to XtraGrid's GridView and descendants. Yes, you can use whatever LINQ construct that works on IEnumerable<T> such as:

var query = from row in this.AsRowEnumerable() where row.Field<int>(intCol) == SOMEVALUE group row by row.Field<string>(nameCol) into g orderby g.Key select g;

So, here it is. A simple LINQ to XtraGrid implementation. It doesn't do everything, but hey, it is a start. Happy?

My first article published in Moj Mikro, Slovene computer monthly magazine

The article is all about HTC's dirty secrets behind its line of PocketPC's based on Qualcomm's MSM7x00 CPU/chipset and is my first article being published in such a large scale magazine or in any magazine I guess. Moj Mikro also brings my memories back; I remember when I was young and I was eagerly waiting for the magazine each month. At the time Moj Mikro was more or less the only Slovene computer magazine and one of the few Yugoslav ones (Slovenia was part of Yugoslavia then and there were a couple of Serb computer magazines, too).

Anyway, the magazine comes out on the first Tuesday in March and I hope you'll enjoy my article titled "Umazane podrobnosti HTC mobilnih naprav – dejstva, ki jih je HTC zamolčal".

Feedback appreciated of course.

Is true belief a good attribute of an architect

Recently I've came across this forum thread regarding the future of [DevEx]' eXpress Persistent Objects for .NET (XPO) ORM product. Customers (actual ones, not potential) are asking whether XPO will someday support n-tier development. They are happily using XPO but they miss a vital part, which is n-tier development. Note that XPO never advertised n-tier support and nobody is arguing that. Perhaps this comment from a customer's post, where the situation is described:

"As Trevor said, I am one whose core is 100% XPO. The future of my application is tied to XPO. Was this a bad decision? Maybe, but probably not. However, XPO lacks in areas (n-tier) where I really need it to start to shine."

Later on Oliver from [DevEx] comments that [DevEx] is planning to add, among various features, a multi-tier support. No other details, no dates, no nothing:

"The architectural changes we are planning will result in the potential to support a variety of layered application architectures, including multi-tier ones. So this is good news for you and everybody else waiting for this kind of functionality."

And crowd goes cheering and applauding. Can this be defined as a true belief? From the point of [DevEx] such a comment in current situation makes sense (I won't question whether XPO is good or bad and if it is going n-tier or not at this point). What I fail to understand is the crowd. How can it be that you use a product that misses a very important feature for you (from the beginning!) and you are prepared to wait for years to get it? We aren't talking about a cosmetic feature. No, we are talking about core functionality. And you are happy that somebody is planning someday to deliver that feature, which might suite you or not, without any obligation to deliver (again, I am not questioning [DevEx]).

Generally speaking, is such a belief and faith that the feature will be what you've asked for, a good attribute of an architect? Would you choose a product that doesn't support a core functionality and it might never support it. Knowing that competition is stiff and you have plenty of choices out there that support this feature and more, you are a bad architect if you don't look around. At least one I wouldn't trust. This is simply bad practice. If you are basing a core part of your application on something, it should work from the start. Gambling on future is not an option.