Thursday, 20 April 2006
This is just a quickie.  I'm re-doing a rather large input form using a DataGrid to let the user navigate it, filter it, sort it, etc. Looked like an ideal opportunity to try adding AJAX into the mix, to avoid posting the whole thing back. It thought it was working very nicely, then I noticed that the rows were getting incorrect contents when I was filtering the grid -- some of the values were staying in place and being combined with the rows that "slid up" because of the filtering.  One column in the grid has a dynamically loaded user control based on the contents of the row. The user control can display between 1-4 text boxes and contains validation controls as well. This  column was not displaying correctly when filtering.

I figured the AJAX solution I am using was buggy, so I went to the AJAX package's user forum and found a post regarding a similar problem.  One respondent stated that this was not an issue with AJAX, but with the DataGrid and the way it worked with ViewState to create the controls (GridView in 2.0 is supposedly immune). Sounded plausible and would be simple enough to test.

One of the nice things about the AJAX package I'm using is that it is fairily non-intrusive, so I split out all the basic page code into a base class and created two pages that inherited from it -- one AJAX-enabled and one conventional.  This way I'd be able isolate AJAX specific problems from DataGrid problems without having to change the code in two places. 

I ran the conventional page, applied the filter, waited for it to postback, waited, waited, and son-of-gun, the same exact issue as the AJAX-enabled grid. Mangled up user controls. 

Not desiring to become a DataGrid ViewState expert this morning and delve into how the control tree was being screwed up, I took a guess that the control IDs forthe user control might be responsible.  I added some code to explicitly set the ID property to a unique value for each control when they were created. Voila!  No more mangled contents.  Everything was rendering as expected on both the conventional and Ajax-enabled grids.

Since I was not setting the IDs for these explicitly, they were all named ctl0.  Now, the full name inlcuded the gridname and row qualifier as well, dgParameters__ctl3__ctl0 for example, but after applying the filter,  there is no way for the grid to differentiate between the old row three and the new row three, and hence strange results appear.  By explicitly setting the ID on the user control to something unique this no longer happens and I can get back to getting this all working.

More on the AJAX goodies soon.

Thursday, 20 April 2006 09:22:51 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 
Friday, 14 April 2006
Saw a strange method call tonight while answering a post...

System.Threading.Interlocked.Increment(i)

It was in a simple loop, and it turns out it was generated by a code converter (C# to VB.NET) so the poster didn't know what it was for (curiosity is far too lacking in this world, but that's a rant for another day).  Fortunately, like every other of the 7-gazillion methods in the .NET framework, if you know it's name you can look it up very easily. Ah, it is a thread-safe incrementer for use on shared variables. It ensures that the value is updated and read in an atomic transaction, in other words, other threads won't increment it as well before it is read. There is no need to use it on a local variable, but it is a potentially handy tool found in the Interlocked class.

Now, about the only time I can think you would use this would be if you had a method that provided a unique integer ID throughout an application.  I personally let SQL Server handle its own ids.  But if you don't want to use IDENTITY in SQL or aren't using a database engine to store your data, this is a handy thing to have.  It also existed in  version 1.0 of the framework, so its not something new, but its not something you'd use everyday, which raises two related questions:

1) What facacta code converter turns a simple for loop into something so arcane?
or
2) is this call used under the covers of every single loop?

Ah, found the suspected converter on the first try. Thank you Google.

It turns this simple loop

for(int i=0;i<10;i++)
{
    Debug.WriteLine(i);
}


into

Dim i As Integer = 0
While i < 10
 System.Math.Min(System.Threading.Interlocked.Increment(i),i-1)
End While

Why not?

    Dim i as Integer
    For i = 0 to 9
       Debug.WriteLine(i)
    Next

Or even

Dim i As Integer = 0
While i < 10

 Debug.WriteLine(i) 
 i = i + 1 
End While

Of course, this could be what is happening under the covers anyway.  Why this would be so, I don't have the foggiest.  Let's see if we can find out.

As you probably know, when you compile a .NET app, it gets turned into MSIL (Microsoft Intermediate Language) code, not to machine code (the JIT handles that when you run the app). There is a tool that let's you look at this language if you are so inclined, the MSIL Disassembler.  Being so inclined today, let's see what our for loop looks like in MSIL (the // are comments in the MSIL that indicate the original source code)...

//000028:    for(int i = 0; i<10; i++)
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  br.s       IL_0013
//000029:    {
//000030:     Debug.WriteLine(i);
  IL_0004:  ldloc.0
  IL_0005:  box        [mscorlib]System.Int32
  IL_000a:  call       void [System]System.Diagnostics.Debug::WriteLine(object)
//000028:    for(int i = 0; i<10; i++)
  IL_000f:  ldloc.0
  IL_0010:  ldc.i4.1
  IL_0011:  add
  IL_0012:  stloc.0
  IL_0013:  ldloc.0
  IL_0014:  ldc.i4.s   10
  IL_0016:  blt.s      IL_0004
//000029:    {
//000030:     Debug.WriteLine(i);
//000031:    }
//000032:   }
  IL_0018:  ret

You will notice that there is no reference to the Interlock class nor the Math class, which is reassuring.  It's simply looping through and adding 1 to i.  Time to do a little speed test in VB.NET and see what happens when we use the ugly converted code versus the vanilla implementation.

Time (milliseconds)
Iterations Vanilla Converted
10 16 16
100 93 93
1000 1050 1105
10000 15900 26300

Like almost every programming sin, the results are not evident in small samples, but become glaring when you actually start doing something intensive.  In fact running the 10,000 iterations on the converted code caused my little test app to crash occassionally.

The moral? If you use a code converter:
a) Find a good one
b) Don't take it as the gospel truth
c) Clean up after it when it makes boo-boos, especially obvious ones.

Found a couple of goodies while researching this entry.  This is an article about a VS add-in to paste a chunk of C# code as VB code.  Looks pretty cool.

And this is a list of research tools you can download from Microsoft.  Note the reference to F#!

Friday, 14 April 2006 22:53:33 (Eastern Standard Time, UTC-05:00)   #     Comments [0]  | 

Theme design by Dean Fiala

Pick a theme: