Thursday, January 29, 2009

This shouldn’t be that hard!

For any of my vast number of readers (hah, hah) who have been following this blog, this post is more what I intended when I decided to start blogging, but so far, haven't gotten around to – a recounting of dealing with a technical issue.

So if you're not into software development, this will doubtless leave you cold, and you're forgiven if you want to go read something more interesting.

For the past 3 days I have been struggling to do something in Microsoft ASP.NET that should be duck soup. But it ain't.

I have a 24x7 array of data that I want to present and edit in a GridView.

Now, a GridView being a presentation control composed of a number of rows and a number of columns, one would think at first glance that he could simply set the DataSource to the array, and, voilá, it would appear. Not so.

In the end, the solution is not too, too terrible, but arriving at it is. This is owing in large part to the state of documentation of today's software products.

They come with megabytes and megabytes of hyper-linked references and how-to walkthroughs, which is great if the task you want to accomplish is exactly one of the walkthrough topics. But if not, you're left to try different combinations of words in various online and offline search engines and hope you hit a combination that lands on an article that somebody has fortuitously written that describes your plight, or something relevant to it.

Now, the Visual Studio Help file entry for "GridView" tells you:

The GridView control can be bound to a data source control (such as SqlDataSource, ObjectDataSource, and so on), as well as any data source that implements the System.Collections..::.IEnumerable interface (such as System.Data..::.DataView, System.Collections..::.ArrayList, or System.Collections..::.Hashtable).

(An IEnumerable is basically anything whose members you can sequence through one at a time – including an array.)

But then it goes on and tells you that there are two different ways to bind to the datasource, depending on which type you're using – a data source control, or an IEnumerable. And there's the first hint of difficulty.

The GridView is really designed to work with data from a database, and when you use it that way, everything just goes, point, point, click, click, and it just works. But when you start trying to figure out how to use it with arrays, you're just kinda left in the dark. Searching help files for "GridView binding to array" yields a bunch of articles and hyperlinked references on binding GridViews … to DataSource controls. I never could find a walk through on how to use it with an array.

When you bind to a Database data source (from now on referred to, as Microsoft does, as a "Data Source Control"), the binding goes in the aspx declarative markup, so it's there automatically each time the page is loaded. When you bind to an array, you have to set it programmatically, which basically means that you end up starting all over each time the page is loaded, including when anyone clicks on a button or link on the page.

I'm gonna cut to the chase here and skip dragging you through all the stumbling around that I did … partly in the interest of time, partly so I don't make myself look excessively stupid.

Yes, GridViews can be bound to arrays, although, at least not that I could find, to 2-dimensional arrays, at least not in the way that I wanted to. The thing is that you have to do everything just right, and if you don't, you're rewarded with … nothing. It just simply doesn't work, and you have no clue why.

The first thing is that, while a GridView looks like it would display a 2-dimensional array nicely, it really displays a one-dimensional sequence of objects (in its rows). The columns that it displays have to be Properties of the objects. Not just elements, but properties. Thus, one of my early attempts, for a programming exercise, involved an array of product elements:


public
class
shortProduct

{


public
int id;


public
string sku;


public
string name;


public
decimal cost;


public
bool fractional;


public
decimal weight;

}


I tried to bind an array of those to a GridView (actually, that was a Windows Form project, so it was a DataGridView, but it's the same principal), and got nothing, because those elements (id, sku, etc.) are just elements and not properties. When I converted them all to properties, and bound it to the control, they came up pretty as you please.

But that's a problem when you have a 2-dimensional array of simple elements. What I ended up doing was re-mapping it to an array of 7 objects, each of which was an array of 24 booleans. And then I defined 24 separate properties corresponding to each one of the Booleans. Now I could display it in a datagrid. Clumsy, but it worked:

public class ValidTimeDay

{

private bool[] _validTimeArray;

public bool ValidHour0 { get {return _validTimeArray[0];} set { _validTimeArray[0] = value}}

public bool ValidHour1 { get {return _validTimeArray[1];} set { _validTimeArray[1] = value}}

etc. down to

public bool ValidHour23 { get {return _validTimeArray[23];} set { _validTimeArray[23] = value}}


}


Now I had an object I could display in the GridView. I then mapped each of the 7 rows into one such object, and made the 7 objects into an array, and I could bind to it.

The other area where the GridView makes it difficult to work with arrays is in the editing features. Again, when you're working with Data Source controls, enabling editing of the data is pretty much point, point, click, click. Because the array doesn't have any kind of programmatic insert/update/delete interface, the GridView basically throws up its hands and leaves it up to you. You can get an Edit button on your GridView with just a few clicks, but everything else is up to you. You have to write the program code for handling each event in the process. And one thing that cost me about half a day of stumbling around until some kind soul on a forum gave me an example, the first thing you have to do is tell it what it's editing – even though it just told you . In your "RowEditing" event handler, the first line should be something akin to "GridView1.EditIndex = e.NewEditIndex". If you don't do that, nothing else happens! You also have to write the code to go back into the child controls of the GridView and figure out exactly what changes were made and store them in the array- that doesn't happen automatically either.

Once you know how to do something, it's not all that hard. It just shouldn't be that dang hard to figure out.




No comments: