Saturday, January 5, 2013

Crystal Reports Merge Module Problems Resolved!

I've had numerous problems getting Crystal Reports working properly on my deployment server.  I finally figured out why and documented my trials, tribulations, & solution here.

Tuesday, August 14, 2012

Simple Way to Sort a DataTable in .NET

I encountered a situation where I had to populate a DataTable with different types of Equipment.  Depending on different factors, the combination of Equipment types varies.  Here are the primary 3 fields in the table:
  1. Unit Num
  2. Description
  3. Equip Type
After the table was fully populated, it became evident that the Unit Num values were not sorted in an orderly sequence.  So I investigated how to sort it in this manner.  I quickly discovered that there was no method to do this in one step but after a short investigation and a little trial & error I discovered a relatively simple approach:

dataTable.Columns.Add("iUnit_No", typeof(Int32), "Convert(Unit_No, 'System.Int32')");  // Add a numeric column that's equivalent to "Unit_No"
dataTable.DefaultView.Sort = "iUnit_No ASC";  // Sort the DefaultView according to this new numeric column
dataTable = dataTable.DefaultView.ToTable(false, "Description", "Unit_No", "Equip_Type");  // Copy the contents of the DefaultView back to the original table, specifying only the columns we want in it
A few lines of code but it works well!

Tuesday, December 13, 2011

Enhancing Telerik's RadListBox

As a follow-up to the previous post, I wanted to share the work I've done to add server-side functionality via client-side calls.  Though this example focuses heavily on Telerik controls, what I've developed is completely generic ASP.net code that can be used in any situation where one needs to cause a server-side event but one is not natively available from the control.
 
The basic challenge I was facing was to allow both single & double clicking in Telerik's RadListBox.  Natively, single-clicks are handled on the server via: OnSelectedIndexChanged.  But there is no server-side equivalent for double-clicks.

Here's what happens when the RadListBox is single-clicked. Eventually a lot more will occur, including a flowchart appearing, unique to each selected item.



























When the RadListBox is double-clicked, a popup dialog appears.  In this case it's a RadWindow:























Here's the ASP.Net layout code:
    
      
        
          
            
              
                

                
                
              
            
          
          
            
              
            
            
              
              
            
          
        
      
    

Here's the client-side Javascript, which initially makes heavy use of jQuery to obtain the ListBox object. The key points to note are:
  1. The use of the clickTimer variable to help distinguish between single & double clicks.
  2. The differentiation of click type via the initial parameter of either "1" or "2".
  3. Forcing a server-side postback via ASP.Net's __doPostBack Javascript function.
  4. The first parameter used with __doPostBack is the ID of the AJAX UpdatePanel.  Doing so ensures that a partial, rather than full, postback occurs, which is much more aesthetically pleasing. 
    

Finally, here's the server-side code that handles the postback forcibly caused by the client. The key points to note are:
  1. The initial checking of the  __EVENTTARGET system variable is very rudimentary.  If multiple such client postbacks existed from different controls then more sophisticated checking could be accomplished..
  2. What parameters are passed is entirely up to the developer.  In this example, passing just the "1/2" and the ListBox index was sufficient. 
    protected void Page_Load(object sender, EventArgs e)
    {
      if (!Page.IsPostBack)
      {
        // The code in this construct strictly handles the single & double clicking of the RadListBox
        if (this.Request["__EVENTTARGET"].EndsWith("UpdatePanel1"))
        {
          string parameters = this.Request["__EVENTARGUMENT"];

          if (parameters != "")
          {
            // This event may have been fired by either a single-click or a double-click.  We need to 
            // find out which one.  The first parameter will be either "1" or "2", indicating which.
            string[] sParamArray = parameters.Split(new char[] { ',' });

            int idx = Convert.ToInt32(sParamArray[1]);
            if (sParamArray[0] == "1") // Single-click
              SelectListBoxItem(idx);
            else
              AddNode(idx);
          }
        }
      }
    }

Saturday, December 10, 2011

Retrieving a Nested ASP.Net Object with Javascript & jQuery

Though I consider myself to be an accomplished C# / ASP.Net web developer, one of my weaknesses lies with client-side Javascript programming. I don't like the free-form, type unsafe nature of it and firmly believe that long term maintainability of Javascript code is a nightmare. The introduction of jQuery has improved things somewhat but there are still times when things can get very tricky. One prime example involves working with nested ASP.Net controls. Here's a quick example of such a situation:

What you're seeing in this image are a number of Telerik controls (which I highly recommend!) that provide a superb user experience for the application I'm building.
My task at hand was to add some custom client-side code for when an item in the listbox was double-clicked.










Here's a snippet of the layout code for the page:

  
    
      
        
          
The challenge was to obtain the ListBox from within the nested objects. Here's a sample Javascript function, that utilizes jQuery, to retrieve the RadListBox object:
 function rlbDoubleClicked() {
   var slidingZone = $find($('table[id$=_radSlidingZone]')[0].id);
   var slidingPane = slidingZone.getPanes()[0];

   // Standard Approach
   var listBox = $find($("#" + slidingPane.get_id() + " #<%= radListBoxStopes.ClientID %>")[0].id);

   // Alternate Approach (necessary if the function is to be placed in an external Javascript file)
   var listBox = $find($("#" + slidingPane.get_id() + " div[id$=_radListBoxStopes]")[0].id);
 }
Hopefully this example will help others with their own projects!

Saturday, January 22, 2011

How to Prevent Visual Studio from Timing Out While Debugging an ASP.net Application

For some time now I've experienced the annoying phenomenon of Visual Studio timing out very quickly during a debugging session. I was never able to precisely nail down exactly how long the timeout duration was but it seemed like a couple of minutes.

I'd searched for a solution to this problem before but could never find one. Today I did. Unfortunately the author wasn't very verbose about how to find specific items referred to in the solution so I thought I'd do so here in the hopes that it will help others.



Note: Much to my disappointment, this only works if you get VStudio to attach to IIS.  I have not yet found a way to configure the internal Web Development Server in a similar fashion.  :-(

For starters, on my workstation I am running Windows 7 Ultimate and Visual Studio 2008.  The aforementioned posting refers to changing a timeout value in Internet Information Services (IIS) 7.  I didn't have it enabled on my computer (only on a server) so the first thing I did was install it:
  1. Start → Control Panel → Programs and Features → Turn Windows features on or off (left column)
  2. In the dialog box that appears, simply check "Internet Information Services" and press OK.
  3. After about a minute, it appeared to have installed the necessary components, though no new options showed up in the Control Panel nor in the Administrative Tools section of the same.
  4. With no explicit way to run the IIS Manager, I went to Start and then typed the following into the Search textbox:  inetmgr
  5. To make it more readily available in the future I right-clicked on the "inetmgr" item that appeared from the search and chose "Open file location".
  6. I located "InetMgr.exe" in this folder and dragged & dropped a shortcut into the "Administrative Tools" folder (just hold down Shift + Ctrl to force a shortcut to be created).
  7. For security reasons it wouldn't let me but did ask if I wanted a shortcut placed on the Desktop.  Yes!
  8. I then moved the new shortcut into the Administrative Tools folder.  Other than a confirmation prompt, it let me do it.
  9. Finally, I renamed "InetMgr.exe" to "IIS Manager", confirming a prompt to finalize the name change.
Then I opened up the IIS Manager.  From the aforementioned posting it wasn't immediately obvious what to do.  But after a little trial & error I figured it out:
  1. Double-click on "Configuration Editor" (bottom row, left side).
  2. In the left column click on "Application Pools".
  3. In the center column click on the row beginning with "DefaultAppPool".  On my system it was the only one present.
  4. In the right column click on "Advanced Settings..."
  5. In the dialog box that appears scroll down a little to the "Process Model" section.
  6. You can either changed "Ping Enabled" to False to have an unlimited timeout or you can change the value of "Ping Maximum Response Time (seconds)" from the default of 90 to something else.  I opted for 900 seconds.

Tuesday, January 11, 2011

Input Parameters: One Better than Strings and Enums

The ASP.Net/C# project I'm working on has several methods that resemble this general pattern:
  public void UpdateDataTable(DataRow dataRow, object objFldName, object newValue)
  {
    string fieldName = objFldName.ToString();
    .
    .
    .
In times past the 2nd parameter would always be string fieldname but to increase data typing and reduce errors I started introducing Enums wherever possible.  In this particular example UpdateDataTable processes DataRows from several different DataTables.  As I have a different Enum for each DataTable's fieldnames and not one Enum for all DataTable fieldnames, a solitary Enum parameter type isn't possible.

I eventually realized that I could use the little trick of specifying a generic object data type and then convert each parameter value over to its string equivalent.  A simple trick, yes, but also an effective one!

Tuesday, December 28, 2010

The Social Network

I finally saw The Social Network, the not entirely factual but somewhat documentary-based film about Mark Zuckerberg and the rise of Facebook from its launch in 2004 to 500 Million users today. Here's the trailer:



Many more clips from the film can be seen here.

I must say that I was both enthralled and inspired by the movie.  How closely it resembles what actually happened with Facebook over the past 7 years is irrelevant.  What is important and inspirational for all software developers the world over is how the determination of one person created a multi-billion dollar company out of nothing.  Furthermore, if you take a look at what Facebook actually does on a technical basis, there is no "genius" at work, per say.  In saying this, I'm not taking anything away from Zuckerberg or his colleagues, for what they have achieved is phenomenal.  However, if a Microsoft or Yahoo or Google or Apple wanted to replicate the functionality on Facebook, how long would it take one of their teams to do it - a few months at most perhaps?!  What is clear is that there was marketing genius at work.  In this regard, I think Facebook proves the old adage: "A good product and great marketing will always outsell a great product and poor marketing."

When I look at Facebook, I always think, "Will this still be the place to go for social networking 25 years from now or even just 10 years from now?  My intuition tells me not.  There are several reasons why.  One of the primary ones is that the "walled garden" of Facebook is not where the Internet was supposed to be heading.  Instead it's a throwback to the days of AOL and Compuserve.  I fully understand why it's so much easier to connect millions (or even billions) of people together on a common website but surely one day the technology community must be able to move Beyond Facebook ?!?

From the moment the closing credits of the movie started rolling, I started making a whole lot of notes of what would be required to indeed move beyond Facebook.  I am continuing to add to these notes and frankly, think I have some pretty darn good ideas.  There's nothing I can do to implement them at this very moment since I'm up to my ears with a very important commitment to a longstanding client of mine but once that's over and a bit more money is in the bank, I seriously do plan to build a prototype to turn my ideas into tangible examples [sic] of where I believe things need to go next.

I'm writing this post for several reasons, not the least of which is that I'd very much like to find other entrepreneurs out there - not just software developers but technology company entrepreneurs - to network with and see if there's some common ground to move forward with beginning in 2011 Q3 or Q4.  If so, please do drop me a line via the e-mail address shown on this blog and introduce yourself.  I'm interested to meet other interesting, sincere people who are also willing to put in the hard work to build something truly great!

How to Get a Footer to Behave Like You Expect

When developing web applications I must confess that dealing with CSS issues is amongst my least favourite things.  I understand the basics of CSS, of course, but take no pleasure in learning every last detail.  And don't even get me started about the differences in behaviour between browsers!!!


With the web app I've been working on for the past few years I had a partial solution for a footer on pages of varying heights.  It "kind of" worked the way I wanted it to but not entirely.  After trying a few different approaches to get it working, with no success, I just added it to my "To Do" list and left it be.  But recent testing by others on different sized screens revealed it to be much more of a problem than I had originally thought.

So I did a new search and came across a website devoted entirely to this very problem: CSS Sticky Footer

The solution they present is straight forward, easy to implement, and works great ... at least in the IE8 environment that my client will be using.  Definitely check it out if you're experiencing problems with footer placement and/or behaviour.

Thursday, September 9, 2010

Adding Items to the ASP.Net ListView

Have you ever encountered what you thought would be an easy programming task but then realized you were in the middle of a nightmare? This is exactly what happened to me the past few days when I tried to implement the ListView control into my ASP.Net 3.5 project.  Here's a screenshot of my prototype version:


Essentially what I was trying to build was a fancy looking horizontal listbox.  Having no previous experience with the ListView control in ASP.Net, I just assumed that it pretty much worked like the ListBox control.  How incredibly wrong I was!

Binding the ListView to a DataTable was simple enough.  Then, when I determined that I wanted the ListView to be 1 row tall x 4 columns wide, I fairly quickly implemented a Left and a Right DataPager control.  Everything seemed to be on track.

Where things went totally awry though was when I implemented an external "Add New Item" button.  As any reasonable person would assume, I naturally thought that I could instantiate a new DataRow item, append it onto the DataTable, rebind this to the ListView, and then just select the new last item in the control.  Sounds logical, right?  But lo and behold, setting the ListView's "SelectedIndex" property to the index of this new item had NO effect!  This is where the nightmare began.

I tried everything - and I mean everything - to get it to work.  After a countless number of wasted hours I finally got some help from ASP.net regular, Peter, a super bright developer in the Eastern U.S. and this posting.

Simply put, setting the SelectedIndex property does not work under most circumstances.  I do not understand why but it does not.  So in order to show that a given ListView item is selected you have to add special code to the ItemCreated event handler.  Here's an example:

    protected void listView1_ItemCreated(object sender, ListViewItemEventArgs e)
    {
      if (listView1.SelectedIndex > -1)
        return;

      ListViewDataItem item = (ListViewDataItem)e.Item;
      if (item.DataItemIndex == DataTableRowIndex)
      {
        listView1.SelectedIndex = DataTableRowIndex;
        if (listView1.SelectedItemTemplate != null)
        {
          e.Item.Controls.Clear();
          listView1.SelectedItemTemplate.InstantiateIn(e.Item);
        }

        labelListView.Text = DataTableRowIndex.ToString();
      }
    }

Note: In my case, 'DataTableRowIndex' is an integer property that I set in the 'SelectedIndexChanging' event handler.  Doing so then prepares for what occurs in the 'ItemCreated' event handler.  It's like an indirect, arguably manual way of setting 'SelectedIndex'.

Summary

I've added this posting in the hopes that it will save others the grief I experienced because of Microsoft's very poor implementation of this control. On a positive note, the ListView control is very powerful and highly customizable. Here's an example of my finished implementation:


And here you can download a sample test project.

Monday, August 2, 2010

Is VS2008 Hanging After Debugging an ASP.net Project?

I start & stop Visual Studio 2008 hundreds of times per day as part of the normal debugging cycle.  In my case, it's running my ASP.net project in Internet Explorer 8.  For some time now, there's been a delay of upwards of 10 seconds when stopping the project, before I could gain control of VS2008 again.

This finally got so annoying that I did some research and found this.  I tried every single idea presented in that thread but nothing worked.  Finally I got to the last item - May 7, 2010 - which suggested the culprit to the be the solution's "SUO" file.  Rather than delete it outright, I instead moved it to another folder.  Incidentally, in my case the file was over 11MB in size.  I restarted VS2008 and voilĂ  ... the delay disappeared!

I don't know all that the SUO file contains but I've suffered no adverse effects from deleting it.  In fact, Visual Studio has already started rebuilding it!

Tuesday, July 27, 2010

Expanding the Usefulness of Global.asax

I've long utilized the 'Global.asax' file to run assorted startup methods, both from an Application and Session perspective.  One limitation of this file is that you can't introduce "using" statements like you can in any normal C# file.  This forces you to prefix every method and class with its full definition.  This isn't so bad but I've reached a point where I have more complex code I need to run and have grown tired of all those prefixes.  Frankly, I think they also make the code much less readable.

To resolve this issue I found this excellent blog post by Ross Nelson which explains how to modify things.  Essentially Global.asax is altered to contain just this one line:
<%@ Application Language="C#" Inherits="Global" %>
This then lets you create a new 'Global.cs' file in which all of the previous contents of 'Global.asax' are placed.

Wednesday, July 14, 2010

Multiple Interchangeable User Controls on One Web Page

I'm building an ASP.Net web page in which there's a need to display any one of about twenty different user controls at any one time.  The contents of each user control is varied, with each holding a different assortment of labels, textboxes, dropdown listboxes, etc.  Assorted criteria on the page determines which user control is displayed.  The image shown on the left shows a trio of examples representing the [blue] web page and different [orange] user controls.

I don't have a lot of experience with ASP.Net user controls but when I have used them there'd typically be 2 or 3 on every page in the project, representing such things as a toolbar, a pulldown menu, a navigation menu, etc.  In those cases it was easy enough to just refer to the user control directly, performing a simple cast like this:

         ToolBar toolBar = (ToolBar)...

But the situation with this page is quite different.  With it I have a PlaceHolder control called "placeHolderSubForm" into which one user control at a time will be loaded.  Where the difficulty arises is when it's time to cast from a Control object to a specific User Control type.  For example, if the first user control shown were loaded into the web page then the cast might look like this:

UserControlA ucA = (UserControlA)placeHolderSubForm.Controls[0]

That works okay if there are one or two user controls to deal with but with 20 of them I immediately realized that the code would get rather unwieldy, with a whole lot of switch-case statements necessary to determine which User Control type to cast to.  I wanted something much more generic!

At the end of the day the interaction between the web page and each user control is fairly basic, consisting of:
  1. Passing some basic parameters to each user control.
  2. Retrieving a varied assortment of user entered data from each user control.
After much research I opted to construct a base class that each user control would be derived from.  It's still evolving but here's what it looks like so far:
public class UserControlBase : System.Web.UI.UserControl
  {
    // Input Parameters (more to be added when required)
    public virtual int ContractIdx { get; set; }

    // Output Data - passed via SortedList
    public SortedList NewData = new SortedList();

    // Generic event handler to notify parent web page
    public virtual event EventHandler NewData_Handler;
  }

In this way, within each user control I can add newly entered data to the general purpose SortedList container 'NewData' via a key & value pair.  Thus, one user control might retrieve the following data from a user:
  • Width: 5.0
  • Height: 7.0
  • Length: 144
  • Grade: 2.7%
  • Overtime: Yes
  • Crew: Alpha Prime
Then back in the web page the container can be retrieved like this:
SortedList newData = ((UserControlBase)placeHolderSubForm.Controls[0]).NewData;

Please note that I have posted this blog entry not as "the definitive way" to do this kind of thing but simply to throw out to the ASP.Net developer community what approach I've used.  I very much look forward to feedback from others about alternate approaches they prefer and will definitely modify things accordingly if I learn of a better practice.

Monday, May 3, 2010

Tracking a Telerik RadTreeView via the UniqueID Property of Each Node

The large ASP.Net project I've been working on makes extensive use of Telerik's excellent TreeView control.  Here's an example of its implementation:


It's important to note that the Save button you see on the toolbar is used for saving all changes on the page as a batch.  There is no need for a user to press "OK" (or equivalent) after changes on each node.  To accomplish this was a little tricky because the user has the ability to make one or more changes on a given record (ie. the controls on the right side) and then click on another node or go to another module or close the browser altogether.  In all of these cases the aforementioned changes are correctly recorded, associated with the appropriate node.

I solved this by introducing a modular level property called "CurrentNodeID".  It keeps track of the currently selected node.  There's also an associated property called "CurrentNode".  It uses CurrentNodeID as a lookup value to find the currently selected node.

To ensure that each CurrentNodeID was unique, I initially just generated a new GUID and stored it in each node's "id" attribute.  This worked very well.  It was especially easy to find find the current node with a statement like this:

treeView.FindNodeByAttribute("id", CurrentNodeID)

It's also important to realize that I'm not populating the entire tree at once but only populating on demand.  To accomplish this I originally had each node's "ExpandMode" property set to "ServerSide".  Configured this way, finding a node via its "id" attribute property was very straightforward.

But more recently I've been experimenting with a newer ExpandMode property value: ServerSideCallBack  It's very powerful, using AJAX to perform a much quicker population of child nodes.  But testing quickly revealed that once the ExpandMode property was changed this way, the "id" attribute was no longer visible.  An inquiry with Telerik revealed that perhaps I should use an attribute name other than "id", as it's already the name of a node property.

Rather than go down that road I instead went back to basics and asked myself why I was using the attribute approach in the first place, for I had long known that each node's "UniqueID" property had a unique value as well.  So I set about to drop the use of the "id" attribute and instead use this new approach.  When it came to the "PreviousNodeID", rather than storing the randomly generated GUID in it, instead I'd just store the UniqueID value.  This change worked very well except for two things:
  1. You can search a treeview for a node via its attribute value but there's no direct way to search for a node via its UniqueID value.
  2. When you drag & drop a node, its UniqueID value changes.

To resolve issue #1 I had to create a new method.  Here is that method, along with how I've defined the CurrentNodeID and CurrentNode properties:

  /// References the value of the UniqueID property of the most current treeview node.
    public string CurrentNodeID
    {
      get
      {
        if (ViewState["CurrentNodeID"] == null)
          return null;

        return ViewState["CurrentNodeID"].ToString();
      }

      set
      {
        ViewState["CurrentNodeID"] = value;
      }
    }


    /// References the most current treeview node.
    public RadTreeNode CurrentNode
    {
      get
      {
        if (CurrentNodeID == null)
          return null;
      
        return FindNodeByUniqueID(treeViewMain, CurrentNodeID);
      }
    }


    /// Every node has a Unique ID value.  There's no built-in method to locate
    /// a node in a treeview via its Unique ID.  This method accomplishes that.
    public static RadTreeNode FindNodeByUniqueID(RadTreeView treeView, string uniqueID)
    {
      RadTreeNode foundNode = null;

      int nodeCount = treeView.GetAllNodes().Count;
      RadTreeNode[] allNodes = new RadTreeNode[nodeCount];
      treeView.GetAllNodes().CopyTo(allNodes, 0);

      foreach (RadTreeNode node in allNodes)
      {
        if (node.UniqueID == uniqueID)
        {
          foundNode = node;
          break;
        }
      }

      return foundNode;
    }


To resolve issue #2, one must just reset the value of PreviousNodeID after a node is moved:

PreviousNodeID = node.UniqueID

I now have a UI that works faster and there ends up being a bit less code than before.  That's a true Win-Win!

Thursday, December 31, 2009

How Best to Keep a Treeview in Sync with SQL Server?

I've run into a bit of a challenge with my work and thought I might be able to get some good advice by drawing attention to it here.  I've outlined the problem quite succinctly here.

If you have any Best Practice ideas based on your own work, please do leave a comment if you can.  Thanks!

Thursday, November 19, 2009

Syntax Highlighter

I'd like to send a shout out & much thanks to Nilesh Thakkar, a software engineer at SIHL in India for recommending I introduce Syntax Highlighter into this blog.  It provides a super simple way to display source code to fellow developers.  You'll see it used in all future posts.

Incidentally, for anyone else writing a blog on Blogger, Matthew Ball has provided a step-by-step explanation of how to add Syntax Highlighter.

Thank you, Nilesh!!