Category Archives: VB.NET

WHDG: Position “Group by” area anywhere on the page

WebHierarchicalDataGrid grouping feature offers handy “Group By” area – a place where columns can be dragged to for grouping. It has one limitation though: by default it can be positioned only on top or the bottom of the grid. But what if you want to place it elsewhere? For example you have a dedicated navigation part of your page where you want to display grouped columns.

DOM to the rescue. As I mentioned in my previous post Group By area is a DIV that can be located by its CSS class name (either assigned by you or, barring that, class of a StyleSet used by the grid control). After the area is located, it can be moved to a location of your choice, for example another DIV by standard appendChild DOM method:

function positionGroupByArea() {
   var aGroupAreas = document.getElementsByClassName('ighg_Office2007BlueGroupArea'); 
   var oDivActionControls = $get('xdivNavigation'); 

   if (aGroupAreas.length > 1) {
      oDivActionControls.removeChild(aGroupAreas[0]);
      oDivActionControls.appendChild(aGroupAreas[1])
   } else {
      oDivActionControls.appendChild(aGroupAreas[0])
   }
}

Lines 2-3 Locate Group By area and target DIV respectfully. Note Line 5: like nature abhors a vacuum – WHDG abhors Group By area missing from its default place, if it is missing – grid will try to recreate it. If this happens you will have 2 Group By areas. If code on Line 5 detects this situation it removes old area and re-adds new one. Otherwise it simple moves original area.

You will have to call this code on initial grid load and after every grid operation (sorting, paging etc.) since grid will try to recreate Group By at the old place. Also, if the grid feels jumpy during this move – hide Group By area initially via it’s CSS class by setting display:none and make it visible again after the move.

Overall effect is quite seamless

WHDG: Give Grouped columns correct captions

If you work with Infragistics WebHierarchicalDataGrid and try to use its grouping features, you may notice that it uses grid column keys instead of column header’s captions to name items in “Group By” area.

To work around this limitation, let’s take a look at how Grouped By area is rendered:

Group By Area in WebHierarchicalDataGrid

Basically a container DIV holds a bunch of SPANs representing grouped columns. Both DIV and SPAN can be located by their CSS class (your own, if it’s assigned or Infragistics StyleSet class name, used by the grid control). Knowing the location of the SPANs we can loop thru them altering their text:

function renameColumnsInGroupByArea() {

   //locating GroupBy area DIV 
   var oGroupArea = document.getElementsByClassName('ighg_IGGroupArea')[0]; 

   //locating GroupedColumn SPANs
   var aGroupedColumns = oGroupArea.getElementsByClassName('ighg_IGGroupedColumn');

   // looping thru SPANS with grouped columns, replacing their text
   for (var I = 0; I < aGroupedColumns.length; I++) {
      aGroupedColumns[I].firstChild.nodeValue = // put your new value here;
   }
}

One way of using this function is generate a JavaScript associative array (ColumnData['ColumnKey'] = 'Column Caption') in ASP.NET server side code. Armed with such array Line 11 in the previous code could be simple

aGroupedColumns[I].firstChild.nodeValue = ColumnData[aGroupedColumns[I].firstChild.nodeValue]

Infragistics: Detect type of AJAX callback

This post continues topic started in “WHDG: Correctly detect Async Callback“. Back then I described a way to correctly detect server-side when an infragistics control (WebHierarchicalDataGrid) issues an async callback.

But what if you need to detect actual type of the call and distinguish paging from sorting from filtering from row expanding? Well, where there is will there is way. Infragistics says there’s no build-in flag indicating AJAX action, but we can determine the action by intercepting and interpreting HTTP Request object.

First let’s define a return type in form of an Enum describing all possible outcomes (it’s always good to work strongly typed values):

Public Enum GRID_AJAX_CALL_TYPE
   NON_AJAX = 0
   PAGING = 1
   SORTING = 2
   FILTERING = 3
   CHILD_POPULATING = 4
End Enum

And now actual function. In the previous post I described that presence of AJAX call can be determined if key starting with "__IGCallback" is present in Request.Form collection. By interpreting actual value of Request item with that key we can determine type of AJAX call. For example, when grid’s row is expanding during load-on-demand, it contains JSON data "eventName":"Populating","type":"loadOnDemand" so our function simple has to catch it:

Function GetGridAjaxCallType() As GRID_AJAX_CALL_TYPE
   Dim sIgCallBackKey As String = HttpContext.Current.Request.Form.AllKeys.SingleOrDefault(Function(S As String) S IsNot Nothing AndAlso S.StartsWith("__IGCallback"))
   Dim sIgCallBackRequest As String

   If sIgCallBackKey <> "" Then
      sIgCallBackRequest = HttpContext.Current.Request.Form(sIgCallBackKey)

      'Detecting Child Populating.
      If sIgCallBackRequest.Contains("""eventName"":""Populating"",""type"":""loadOnDemand""") Then Return GRID_AJAX_CALL_TYPE.CHILD_POPULATING

      Return GRID_AJAX_CALL_TYPE.NON_AJAX
   Else
      Return GRID_AJAX_CALL_TYPE.NON_AJAX
   End If

End Function

The function tries to locate "__IGCallback" key in HTTP request (Line 2), if the key present – function reads actual Request value (Line 6) and if Load-on-demand populating is detected (Line 9) – returns result saying so, otherwise returned result indicated non-ajax call.

This example implements only one detection – Load-on-demand populating, I will leave it to you to add sorting/filtering/paging detection. Once implemented – usage is pretty straightforward:

If Not IsPostBack Then
   '...
Else
   If GetGridAjaxCallType() = GRID_AJAX_CALL_TYPE.CHILD_POPULATING Then
      RebindTheGrid()
   End If
End if

Solution: WebDataGrid loses styles after postback

Infragistics WebDataGrid control offers very flexible styling option – you can set font, color, size of almost any element from column to individual cell. Here is an example of basic markup that sets CSS classes of overall grid control, grid header, grid odd row and grid even row:

<ig:WebDataGrid ID="xMyGrid" runat="server"
   CssClass = "GridStyle"
   HeaderCaptionCssClass = "GridHeaderCellStyle"
   ItemCssClass = "GridCellStyle"
   AltItemCssClass = "GridAltCellStyle" 
>

And corresponding example of CSS class for even row:

tbody > tr.GridAltCellStyle > td
{
   font-size:11px;
   font-weight:normal;
   font-family:Verdana, Geneva, sans-serif;
   height:20px;
   padding: 2px 2px 2px 2px;
   border-bottom: none;
   border-right: 1px solid rgb(190,198,178);
   background-color:rgb(240,240,240);
}

(For a complete grid styling reference take a look at this styling guide)

And it all works fine, your grid renders so beautifully, Picasso would cry. But only on initial page load. And here comes dreadful postback. Continue reading →

UltraWebGrid strange behavior in IE8 when IE=EmulateIE7

If you’re using Infragistics UltraWebGrid in Internet Explorer 8 you may experience strange visual (and other) issues if you have page compatibility set to emulate IE7, e.g.

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />

Issues can range from column moving not working to weird distortion in grouped mode. According to Infragistics this combination is not supported as “unstable”, but you can still make it work.

Infragistics keeps internal flags of what browser is currently in use: ig_shared.IsIE7, ig_shared.IsIE8, etc. The trick is to detect IE8 and make it fall back to IE7:

if (ig_shared.IsIE8) {
    ig_shared.IsIE8 = false;
    ig_shared.IsIE7Compat = true;
}

Place this code on top of your page JavaScript code and when it sees IE8 it will tell grid to use IE7 rendering. This is most definitely a hack, but it works.

UltraWebGrid: “Input string was not in a correct format” error while setting width of a column

Infragistics UltraWebGrid allows you to set width of a column in client-side JavaScript, you can do it using code similar to this:

igtbl_getGridById('xmyGrid').Bands[0].Columns[3].setWidth(someValue)

But, while executing this code on the client, you may get a nasty surprise by getting following error from the server:

Input string was not in a correct format.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.FormatException: Input string was not in a correct format.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[FormatException: Input string was not in a correct format.]
System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) +10163939
System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) +207
Infragistics.WebUI.UltraWebGrid.StateChangeProcessor.ProcessChanges() +6230
Infragistics.WebUI.UltraWebGrid.UltraWebGrid.ProcessChanges(StateChanges stateChanges, Boolean fireEvents) +701
Infragistics.WebUI.UltraWebGrid.UltraWebGrid.LoadPostData(String postDataKey, NameValueCollection values) +7580
System.Web.UI.Page.ProcessPostData(NameValueCollection postData, Boolean fBeforeLoad) +945
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2071

Now, you do know that your someValue is definitely a number, why this error then? Let alone – why client-size resize causes a server call? But I will leave this to Infragistics. Actual cause of the error – number not being Integer. If you change the code from above to

igtbl_getGridById('xmyGrid').Bands[0].Columns[3].setWidth(Math.ceil(someValue))

it will execute without any errors. Go figure.

Correctly compare file date against TSQL stored date

If you need to track whether a particular file has changed or not (and I am not talking about FileSystemWatcher, often it’s an overkill), one way is to compare file’s LastWriteTime against stored value. But if you store the date value in SQL Server you may be in for a surprise – even if file date hasn’t changed – dates will not compare as equal. Consider following example:

'Reading current system file date/time
Dim dCurrentFileDate As DateTime = File.GetLastWriteTime(sFilePath)

'Storing file date/time in SQL Server table
CMyDatabaseClass.SaveDate(sFilePath, dCurrentFileDate)

'Immediately reading date/time value back
Dim dStoredFileDate As DateTime = CMyDatabaseClass.LoadDate(sFilePath)

'Comparing stored value against current
If dCurrentFileDate = dStoredFileDate
'
End If

The If statement on Line 11 will produce False results even if the dates seem identical. The reason – millisecond part of the datetime. SQL Server and .NET disagree on how to treat it so the best thing to do is to strip milliseconds from system file date/time before storing it or comparing against stored value.

Joe from StackOverflow.com offers a very elegant solution. That solution is in C# and here it is converted to VB.NET. To apply it to the example above simple add after the second line:

dCurrentFileDate = dCurrentFileDate.Value.AddTicks(-(dCurrentFileDate.Value.Ticks Mod TimeSpan.TicksPerSecond))

This will remove milliseconds from the date/time value and next time if you compare to the same value – values will be really equal.

Solution for “Operation is not valid due to the current state of the object” error

Typically this happens when AJAX controls are involved (Microsoft’s UpdatePanel or others that utilize AJAX POST requests.) The error may be displayed outright or, if nothing is shown on the UI – logged in the Event Viewer. In any case you will get a message similar to:

0x800a139e – Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: Operation is not valid due to the current state of the object

Issue happens because Microsoft Security Update MS11-100 limits number of keys in Forms collection during HTTP POST request. To alleviate this problem you need to increase that number.

This can be done in your application Web.Config in the <appSettings> section (create the section directly under <configuration> if it doesn’t exist). Add 2 lines similar to the lines below to the section:

<add key="aspnet:MaxHttpCollectionKeys" value="2000" /">
<add key="aspnet:MaxJsonDeserializerMembers" value="2000" /">

The above example set the limit to 2000 keys. This will lift the limitation and the error should go away.

Regenerate JavaScript function code in ASP.NET partial postback after initial load

ASP.NET has a handy way of generating client side JavaScript code, but using it can be sometimes unpredictable. For example your client-side script needs to call function MyAlert, but the function itself is generated server-side on page load:

ClientScript.RegisterStartupScript(Me.GetType, "JSCode", _
                  "function MyAlert() {alert('This is the FIRST call')}", True)

Function is generated, and in due time, when needed is called by the client and the message “This is the FIRST call” is displayed. All is well.

Now, your page also has an UpdatePanel, and during a partial postback you need to modify that client-side function:

ScriptManager.RegisterStartupScript(Me, Me.GetType, "JSCode", _
                  "function MyAlert() {alert('This is the SECOND call')}", True)

In due time, when again needed by client code, function MyAlert is called and the message (wait for it, you’re in for a surprise) “This is the FIRST call” is displayed again. Originally generated function is called and second generation is ignored. Continue reading →

UltraWebGridExcelExporter: Export more than 65536 rows

When exporting data from Infragistics UltraWebGrid into Excel using UltraWebGridExcelExporter ordinary a very basic code similar to this is used:

'
' define Exporter "xMyExporter"
' define UltraWebGrid "xMyGrid" and load grid with data, then:
'
xMyExporter.ExportMode = UltraWebGrid.ExcelExport.ExportMode.Download
xMyExporter.Export(xMyGrid)

That’s it. But, if your data exceed 65536 rows you will get an error:

System.InvalidOperationException: The maximum number of rows in an excel worksheet with the current format is: 65536

This is not Excel Exporter limitation. Continue reading →