Wednesday, May 8, 2013

Active Reports HTML viewer skinning

My company recently migrated from Microsoft's reporting services to Active Reports.  I wrote a post here about my complaints and assessment of the product.

One of the big problems with the HTML viewer is the HTML code it generates and its heavy reliance on absolute positioning.  It is some of the worst code I have seen a control generate, I suppose it is supposed to be for flexibility, however none of the flexibility has been made available to us yet.

In order to make this control work for my companies spreadsheet style reporting, I had to come up with a cross between the HtmlView and the RawHTML output.  The raw HTML worked better in page flow usually, but it didn't have paging which is a pretty nice feature.  So I generating the following CSS snippet in an attempt to make the HtmlView just a little closer to the RawHTML output.

.rptDiv and #controlTable and #rptFilter are my own personal divs wrapping the viewer output and my custom parameters, they should not be necessary for the CSS to function correctly.

There are three main features that this CSS changes.  Overflow to remove the extra scrollbars that the viewer adds to the page.  Left and top positioning to get rid of the dumb one inch white space margin that the viewer creates.  And Z-index because moving the main panel one inch up and left causes an invisible portion of the viewer control to be placed on top of any controls in the nearby area; and so it needs to be stuff behind them.

#viewer-layout-main-panel > div > div > div > div > span {
    border:solid 1px;
    border-color:white;
}
.rptDiv,
.viewer-layout-container,
.viewer-layout-container div {
    overflow:visible !important;
    z-index:2;
}
#controlTable,
.viewer-layout-main-panel {
    border:none !important;
}
.viewer-layout-main-panel > div > div {
    left:-1in;
    top:-1in;
    width:0px !important;
           
}
#rptFilter,
#viewer-layout-toolbar-panel {
    z-index:3 !important;
    position:relative;
}

Custom serialization

I recently ran into an issue where using Session variables to maintain state was not a good fit for my web application.  But I had far too many variables to easily be able to save and retrieve them all from a database each time I wanted one.

So I ended up creating a custom object to hold all of my variables, then wrote a serialization piece to dump the object to a string that could be stored as well as used to rebuild the object.

While this does seem to be a pretty common need across the net, I have seen very few complete examples of how to implement it.  So here is the first version of my parameters class:

Notice the ToString method as well as the constructor where all of the cool stuff happens.  A quick note, I am using fields in this example, however if you wanted to hide your fields behind property get and set statements you could easily convert the reflection code from field references to property references.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MyNameSpace {
  public class ContactListParams {
    public string sFilter = "";
    public string sText = "";
    public string trcCL_grdPI = "";
    public string trcCL_grdSE = "";
    public string trcCL_grdSD = "";
    public string trcCL_Disp = "";
    public string trcCL_Comp = "";
    public string trcCL_FName = "";
    public string trcCL_LName = "";
    public string trcCL_Addr3 = "";
    public string trcCL_MSt = "";
    public string trcCL_Zip = "";
    public string trcCL_Phone = "";
    public string trcCL_Industry = "";
    public string trcCL_CID = "";
    public string PCB_Status = "";
    public string progType = "";
    public string userCanReassign = "";
    public string iRecordCount = "";
    public string sPriority = "";
    public string trcCntLstSort_Des = "";

    public ContactListParams() { } // basic constructor

    ///


    /// Creates a new contactlistparams from the data returned through the ToString method.
    ///

    ///
    public ContactListParams(string InitialData) {
      Type type = typeof(ContactListParams);
      string[] fielddata = InitialData.Split(Convert.ToString((Char)3));
      foreach (string field in fielddata) {
        if (field != null && field != "") {
          string[] data = field.Split(Convert.ToString((Char)1));
          FieldInfo fi = this.GetType().GetField(data[0]);
          if(fi != null) fi.SetValue(this, data[1]);
        }
      }
    }

    public override string ToString() {
      string ret = "";
      Type type = typeof(ContactListParams);
      FieldInfo[] fields = type.GetFields();
      foreach (var field in fields) {
        object value = field.GetValue(this);
        ret += field.Name + Convert.ToString((Char)1) + value.ToString() + Convert.ToString((Char)3);
      }
      return ret;
    }
  }
}