Difference between revisions of "Diagram viewer control"

From Catglobe Wiki
Jump to: navigation, search
m
(Code)
Line 1: Line 1:
 
[[New Report Design - 2009]] => [[Diagram viewer control]]
 
[[New Report Design - 2009]] => [[Diagram viewer control]]
 
  
 
== Introduction ==
 
== Introduction ==
Line 11: Line 10:
 
* Tabulation result viewer
 
* Tabulation result viewer
  
So, for the sake of consistency, I decided to make a ''DiagramViewer'' control that can be used all over places.
+
So, for the sake of consistency, I decided to make a ''DiagramViewer'' control that can be used all over the places.
  
 
== Design Decisions ==
 
== Design Decisions ==
Line 18: Line 17:
 
* AjaxPro is used as a mean for calling server's code from client-side
 
* AjaxPro is used as a mean for calling server's code from client-side
 
* Crash message must be controlled by the control itself (no dump screen), instead user has the ability to enable/disable viewing of full error message
 
* Crash message must be controlled by the control itself (no dump screen), instead user has the ability to enable/disable viewing of full error message
 +
 +
== Detail implementation ==
 +
 +
=== Code ===
 +
Code can be found under: ''/trunk/CatGlobeCustomControls/Report/DiagramViewer'' folder, there are couple of files under this folder
 +
* ''DiagramViewer.cs'': control's server code
 +
* ''DiagramViewer.js'': control's client code
 +
* ''progress_bar.gif'': the image that is displayed when the diagram is being generated
 +
* ''progress_bar_EN.gif'': locale dependent loading image (English)
 +
* ''progress_bar_DA.gif'': locale dependent loading image (Dannish)
 +
 +
=== Combine MS AJAX.NET and Ajax.Pro ===
 +
MS AJAX.NET provide a great model for building client-server control which provide separation of client code and creating a link between client's object and server's object. However, to invoke server using AJAX it requires either a page method or a web-service method.
 +
* Page method: method must be put onto page while we are developing a control and has no idea of what page will use the control
 +
* Webservice method: require a separate web service implementation which spread the implementation of control to more than one place
 +
 +
Either way are suitable for our need which is putting the server method on the same place as control's server code. ''AjaxPro'' appears to be the perfect implementation in this way. However, normal implementation of ''AjaxPro'' introduce a naming conflict.
 +
 +
==== /ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.Report.ashx ====
 +
Following this [http://www.google.com.vn/url?sa=t&source=web&ct=res&cd=1&url=http%3A%2F%2Fwww.ajaxpro.info%2Fquickguide.aspx&ei=KFpxSomBIZWPkQXEy7mgDA&usg=AFQjCNE2SHMtVnm5jhj06sjHWZ79eefaVw&sig2=hfNUKqGERsp-VXi5GDmT0A link] we will have such below code:
 +
 +
<source lang="javascript">
 +
if (CatGlobe == undefined) CatGlobe = new();
 +
if (CatGlobe.Web == undefined) CatGlobe.Web = new();
 +
if (CatGlobe.Web.UI == undefined) CatGlobe.Web.UI = new();
 +
if (CatGlobe.Web.UI.Report == undefined) CatGlobe.Web.UI.Report = new();
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy = function() { };
 +
Object.extend(CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy.prototype, Object.extend(new AjaxPro.AjaxClass(), {
 +
  BeginGenerate: function(diagramResourceId, diagramInfo) {
 +
      return this.invoke("BeginGenerate", { "diagramResourceId": diagramResourceId, "diagramInfo": diagramInfo }, this.BeginGenerate.getArguments().slice(2));
 +
  },
 +
  EndGenerate: function(guid) {
 +
      return this.invoke("EndGenerate", { "guid": guid }, this.EndGenerate.getArguments().slice(1));
 +
  },
 +
  url: '/ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.ashx'
 +
}));
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer = new CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy()
 +
</source>
 +
 +
* The first 4 lines define the namespace => not important
 +
* The last line define the object for ready to use => not important
 +
* The remain middle lines define the server methods' proxies => important
 +
 +
==== DiagramViewer.js ====
 +
While following [[ResourceSuggestTextBox_control | this link]] we have a template as below
 +
<source lang="javascript">
 +
Type.registerNamespace("CatGlobe.Web.UI.WebControls.Report");
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer = function(element) {
 +
  CatGlobe.Web.UI.WebControls.Report.DiagramViewer.initializeBase(this, [element]);
 +
}
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer.prototype = {
 +
  initialize: function() {
 +
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'initialize');
 +
  },
 +
 +
  dispose: function() {
 +
      //Add custom dispose actions here
 +
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'dispose');
 +
  },
 +
}
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer.registerClass('CatGlobe.Web.UI.WebControls.Report.DiagramViewer', Sys.UI.Control);
 +
 +
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
 +
</source>
 +
 +
* The first line define the namespace
 +
* The next code block define the class
 +
* The next code block define content of the class
 +
* The remaining are required to work with the control template
 +
 +
==== Merging the 2 codes ====
 +
As the code shown, there are name conflicting when using the 2 frameworks together. So, the only way to merge the 2 frameworks together is to omit some code from one of them. And due to the fact that namespace definition of ''AjaxPro'' is not as important as of ''AJAX.NET''. More than that, the code of ''AJAX.NET'' acts as the main frame for the control's client code and ''AjaxPro'' code is just a mean for talking to server. Then the code is merged as below (no server code is required for registering AjaxPro):
 +
<source lang="csharp">
 +
Type.registerNamespace("CatGlobe.Web.UI.WebControls.Report");
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer = function(element) {
 +
  CatGlobe.Web.UI.WebControls.Report.DiagramViewer.initializeBase(this, [element]);
 +
}
 +
 +
///
 +
/// Register proxy using Ajax.Pro
 +
/// This code is taken from /ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.Report.ashx
 +
/// in case we call AjaxPro.Utility.RegisterTypeForAjax on server's code
 +
///
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy = function() { };
 +
Object.extend(CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy.prototype, Object.extend(new AjaxPro.AjaxClass(), {
 +
  BeginGenerate: function(diagramResourceId, diagramInfo) {
 +
      return this.invoke("BeginGenerate", { "diagramResourceId": diagramResourceId, "diagramInfo": diagramInfo }, this.BeginGenerate.getArguments().slice(2));
 +
  },
 +
  EndGenerate: function(guid) {
 +
      return this.invoke("EndGenerate", { "guid": guid }, this.EndGenerate.getArguments().slice(1));
 +
  },
 +
  url: '/ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.ashx'
 +
}));
 +
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer.prototype = {
 +
  initialize: function() {
 +
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'initialize');
 +
  },
 +
 +
  dispose: function() {
 +
      //Add custom dispose actions here
 +
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'dispose');
 +
  },
 +
 +
  ///
 +
  /// Readonly property
 +
  ///
 +
  get_proxy: function() {
 +
      if (this._proxy == undefined) {
 +
        // Setup the server object
 +
        this._proxy = new CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy();
 +
      }
 +
      return this._proxy;
 +
  }
 +
}
 +
 +
CatGlobe.Web.UI.WebControls.Report.DiagramViewer.registerClass('CatGlobe.Web.UI.WebControls.Report.DiagramViewer', Sys.UI.Control);
 +
 +
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
 +
</source>
 +
 +
And now, the 2 frameworks can work together. Note that there is an addition get method for retrieving the proxy, in order to call server method client code just need to get the proxy by call ''get_proxy'' method and then call the desired method. On server side, as normal, we just need to define 2 server method as below:
 +
<source lang="csharp">
 +
      [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
 +
      public static string BeginGenerate(string diagramResourceId, DiagramInfo diagramInfo);
 +
 +
      [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
 +
      public static string EndGenerate(string guid);
 +
</source>
 +
 +
=== Generation steps ===
 +
Link to DiagramInfoFactory
 +
 +
 +
 +
== Document revisions ==
 +
{|
 +
|-
 +
| '''Version No.'''
 +
| '''Date'''
 +
| '''Changed By'''
 +
| '''Description'''
 +
| '''Svn revision'''
 +
|-
 +
| 0.1
 +
| 30.07.2009
 +
| Nguyen Trung Chinh
 +
| Create first version
 +
| 54885
 +
|}

Revision as of 11:49, 30 July 2009

New Report Design - 2009 => Diagram viewer control

Introduction

In current implementation, there is no specific implementation for a DiagramViewer while it should. There are couple of places where diagram can be viewed but with separate implementation, just to name some:

  • Diagram viewer
  • Report viewer
  • Monitor
  • Dashboard
  • Tabulation result viewer

So, for the sake of consistency, I decided to make a DiagramViewer control that can be used all over the places.

Design Decisions

  • Use the model from Microsoft AJAX.NET that has been applied for resource-ex controls. See the instruction for implementation here
  • The design must reuse the nice features of asynchronous processing that have been applied by Chuong and Dennis
  • AjaxPro is used as a mean for calling server's code from client-side
  • Crash message must be controlled by the control itself (no dump screen), instead user has the ability to enable/disable viewing of full error message

Detail implementation

Code

Code can be found under: /trunk/CatGlobeCustomControls/Report/DiagramViewer folder, there are couple of files under this folder

  • DiagramViewer.cs: control's server code
  • DiagramViewer.js: control's client code
  • progress_bar.gif: the image that is displayed when the diagram is being generated
  • progress_bar_EN.gif: locale dependent loading image (English)
  • progress_bar_DA.gif: locale dependent loading image (Dannish)

Combine MS AJAX.NET and Ajax.Pro

MS AJAX.NET provide a great model for building client-server control which provide separation of client code and creating a link between client's object and server's object. However, to invoke server using AJAX it requires either a page method or a web-service method.

  • Page method: method must be put onto page while we are developing a control and has no idea of what page will use the control
  • Webservice method: require a separate web service implementation which spread the implementation of control to more than one place

Either way are suitable for our need which is putting the server method on the same place as control's server code. AjaxPro appears to be the perfect implementation in this way. However, normal implementation of AjaxPro introduce a naming conflict.

/ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.Report.ashx

Following this link we will have such below code:

if (CatGlobe == undefined) CatGlobe = new();
if (CatGlobe.Web == undefined) CatGlobe.Web = new();
if (CatGlobe.Web.UI == undefined) CatGlobe.Web.UI = new();
if (CatGlobe.Web.UI.Report == undefined) CatGlobe.Web.UI.Report = new();

CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy = function() { };
Object.extend(CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy.prototype, Object.extend(new AjaxPro.AjaxClass(), {
   BeginGenerate: function(diagramResourceId, diagramInfo) {
      return this.invoke("BeginGenerate", { "diagramResourceId": diagramResourceId, "diagramInfo": diagramInfo }, this.BeginGenerate.getArguments().slice(2));
   },
   EndGenerate: function(guid) {
      return this.invoke("EndGenerate", { "guid": guid }, this.EndGenerate.getArguments().slice(1));
   },
   url: '/ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.ashx'
}));

CatGlobe.Web.UI.WebControls.Report.DiagramViewer = new CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy()
  • The first 4 lines define the namespace => not important
  • The last line define the object for ready to use => not important
  • The remain middle lines define the server methods' proxies => important

DiagramViewer.js

While following this link we have a template as below

Type.registerNamespace("CatGlobe.Web.UI.WebControls.Report");

CatGlobe.Web.UI.WebControls.Report.DiagramViewer = function(element) {
   CatGlobe.Web.UI.WebControls.Report.DiagramViewer.initializeBase(this, [element]);
}

CatGlobe.Web.UI.WebControls.Report.DiagramViewer.prototype = {
   initialize: function() {
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'initialize');
   },

   dispose: function() {
      //Add custom dispose actions here
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'dispose');
   },
}

CatGlobe.Web.UI.WebControls.Report.DiagramViewer.registerClass('CatGlobe.Web.UI.WebControls.Report.DiagramViewer', Sys.UI.Control);

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
  • The first line define the namespace
  • The next code block define the class
  • The next code block define content of the class
  • The remaining are required to work with the control template

Merging the 2 codes

As the code shown, there are name conflicting when using the 2 frameworks together. So, the only way to merge the 2 frameworks together is to omit some code from one of them. And due to the fact that namespace definition of AjaxPro is not as important as of AJAX.NET. More than that, the code of AJAX.NET acts as the main frame for the control's client code and AjaxPro code is just a mean for talking to server. Then the code is merged as below (no server code is required for registering AjaxPro):

Type.registerNamespace("CatGlobe.Web.UI.WebControls.Report");

CatGlobe.Web.UI.WebControls.Report.DiagramViewer = function(element) {
   CatGlobe.Web.UI.WebControls.Report.DiagramViewer.initializeBase(this, [element]);
}

///
/// Register proxy using Ajax.Pro
/// This code is taken from /ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.Report.ashx
/// in case we call AjaxPro.Utility.RegisterTypeForAjax on server's code
///
CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy = function() { };
Object.extend(CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy.prototype, Object.extend(new AjaxPro.AjaxClass(), {
   BeginGenerate: function(diagramResourceId, diagramInfo) {
      return this.invoke("BeginGenerate", { "diagramResourceId": diagramResourceId, "diagramInfo": diagramInfo }, this.BeginGenerate.getArguments().slice(2));
   },
   EndGenerate: function(guid) {
      return this.invoke("EndGenerate", { "guid": guid }, this.EndGenerate.getArguments().slice(1));
   },
   url: '/ajaxpro/CatGlobe.Web.UI.WebControls.Report.DiagramViewer,CatGlobe.Web.UI.WebControls.ashx'
}));


CatGlobe.Web.UI.WebControls.Report.DiagramViewer.prototype = {
   initialize: function() {
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'initialize');
   },

   dispose: function() {
      //Add custom dispose actions here
      CatGlobe.Web.UI.WebControls.Report.DiagramViewer.callBaseMethod(this, 'dispose');
   },

   ///
   /// Readonly property
   ///
   get_proxy: function() {
      if (this._proxy == undefined) {
         // Setup the server object
         this._proxy = new CatGlobe.Web.UI.WebControls.Report.DiagramViewer_proxy();
      }
      return this._proxy;
   }
}

CatGlobe.Web.UI.WebControls.Report.DiagramViewer.registerClass('CatGlobe.Web.UI.WebControls.Report.DiagramViewer', Sys.UI.Control);

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

And now, the 2 frameworks can work together. Note that there is an addition get method for retrieving the proxy, in order to call server method client code just need to get the proxy by call get_proxy method and then call the desired method. On server side, as normal, we just need to define 2 server method as below:

      [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
      public static string BeginGenerate(string diagramResourceId, DiagramInfo diagramInfo);

      [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
      public static string EndGenerate(string guid);

Generation steps

Link to DiagramInfoFactory


Document revisions

Version No. Date Changed By Description Svn revision
0.1 30.07.2009 Nguyen Trung Chinh Create first version 54885