<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2677760060687280469</id><updated>2012-01-31T06:48:18.247-08:00</updated><category term='ELMAH'/><category term='OBIEE'/><category term='Telerik'/><category term='Oracle'/><category term='Functional Programming'/><category term='ISD'/><category term='DataStage'/><category term='ASP.NET'/><title type='text'>A Code Thief's Brag</title><subtitle type='html'>Good Programmers Copy.
Great Programmers Steal.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-329017750172104947</id><published>2012-01-29T07:30:00.000-08:00</published><updated>2012-01-31T06:48:18.264-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>ASP.NET MVC Dynamic Model Binding</title><content type='html'>Published at: &lt;a href="http://dotnetslackers.com/articles/aspnet/ASP-NET-MVC-Dynamic-Model-Binding.aspx"&gt;http://dotnetslackers.com/articles/aspnet/ASP-NET-MVC-Dynamic-Model-Binding.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Correction&lt;/h3&gt;CustomModelBinder definition:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public class PetBinderAttribute : CustomModelBinderAttribute {&lt;br /&gt;&lt;br /&gt;  public override IModelBinder GetBinder() {&lt;br /&gt;    return new PetModelBinder();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public class PetModelBinder : DefaultModelBinder {&lt;br /&gt;    public override object BindModel(ControllerContext controllerContext, &lt;br /&gt;      ModelBindingContext bindingContext) {&lt;br /&gt;      var type = controllerContext.HttpContext.Request.Form["PetType"];&lt;br /&gt;      bindingContext.ModelName = type;&lt;br /&gt;      bindingContext.ModelMetadata = ModelMetadataProviders&lt;br /&gt;        .Current.GetMetadataForType(null, petMap[type]);&lt;br /&gt;      return base.BindModel(controllerContext, bindingContext);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    static Dictionary&amp;lt;string, Type&amp;gt; petMap = new Dictionary&amp;lt;string, Type&amp;gt;{&lt;br /&gt;      {"Dog", typeof(Dog)},&lt;br /&gt;      {"Cat", typeof(Cat)},&lt;br /&gt;      {"Fish", typeof(Fish)}&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Use the CustomModelBinder:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;[HttpPost]&lt;br /&gt;public ActionResult Create([PetBinder]IPet pet) {&lt;br /&gt;  // BusinessLogic.Save(pet)&lt;br /&gt;  return View();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-329017750172104947?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/329017750172104947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=329017750172104947' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/329017750172104947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/329017750172104947'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2012/01/aspnet-mvc-dynamic-model-binding.html' title='ASP.NET MVC Dynamic Model Binding'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-4549395551879842348</id><published>2011-12-18T19:15:00.000-08:00</published><updated>2011-12-18T19:15:46.011-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Telerik'/><title type='text'>Re-size and re-center Telerik MVC modal window after ajaxRequest</title><content type='html'>Telerik MVC modal window can auto-size to fit its initial content. After ajaxRequest, however, the window size stays the same, not adjusting to the new content. Here is how to re-size and re-center a modal window after ajaxRequest. The trick is to remove css "width" and "height" properties from the .t-window-content div.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:javascript"&gt;@{Html.Telerik().Window()&lt;br /&gt; .Name("Popup")&lt;br /&gt; .Modal(true)&lt;br /&gt; .Visible(false)&lt;br /&gt; .ClientEvents(events =&gt; events&lt;br /&gt;  .OnRefresh("resizeOnRefresh")&lt;br /&gt;  .OnResize("centerOnResize"))&lt;br /&gt; .Render();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt; function resizeOnRefresh() {&lt;br /&gt;  var winContent = $('#Popup .t-window-content');&lt;br /&gt;  winContent.css("width", "");&lt;br /&gt;  winContent.css("height", "");&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; function centerOnResize() {&lt;br /&gt;  var pop = $('#Popup').data('tWindow');&lt;br /&gt;  pop.center();&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; $(function () {&lt;br /&gt;  var pop = $('#Popup').data('tWindow');&lt;br /&gt;  pop.center().open();&lt;br /&gt;  pop.ajaxRequest("/Home/Ajax");&lt;br /&gt; });&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-4549395551879842348?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/4549395551879842348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=4549395551879842348' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/4549395551879842348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/4549395551879842348'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/12/re-size-and-re-center-telerik-mvc-modal.html' title='Re-size and re-center Telerik MVC modal window after ajaxRequest'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-5188691646441344174</id><published>2011-12-17T19:52:00.000-08:00</published><updated>2011-12-17T19:52:35.247-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Telerik'/><title type='text'>Set Min- and Max-Sizes on Telerik ASP.NET MVC Windows</title><content type='html'>Telerik ASP.NET MVC window (as of 2011.Q3) does not directly support min-length, min-width, max-length or max-width. However, you can set these css properites on its child .t-window-content div. For example,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:javascript"&gt;var winContent = $('#MyWindow .t-window-content');&lt;br /&gt;winContent.css("min-width", "100px");&lt;br /&gt;winContent.css("max-width", "500px");&lt;br /&gt;winContent.css("min-height", "50px");&lt;br /&gt;winContent.css("max-height", "500px");&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-5188691646441344174?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/5188691646441344174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=5188691646441344174' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/5188691646441344174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/5188691646441344174'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/12/set-min-and-max-sizes-on-telerik-aspnet.html' title='Set Min- and Max-Sizes on Telerik ASP.NET MVC Windows'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-6972489504276582858</id><published>2011-11-17T06:44:00.000-08:00</published><updated>2011-11-17T06:44:20.757-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OBIEE'/><title type='text'>OBIEE XMLViewSerive.executeXMLQuery does not accept filters in ReportParams.filterExpressions</title><content type='html'>&lt;h3&gt;OBIEE version:&lt;/h3&gt;&lt;div&gt;11.1.1.5.0&lt;/div&gt;&lt;h3&gt;Symptom:&lt;/h3&gt;&lt;div&gt;I need to evoke XMLViewService.executeXMLQuery() with different saved filters. I tried to set the filter in ReportParams.filterExpressions. The server returned the query result without any complaints. But the results were always the same as the result without any filters.&lt;/div&gt;&lt;h3&gt;Work-around:&lt;/h3&gt;&lt;div&gt;Set filters directly in ReportRef.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-6972489504276582858?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/6972489504276582858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=6972489504276582858' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/6972489504276582858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/6972489504276582858'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/11/obiee-xmlviewseriveexecutexmlquery-does.html' title='OBIEE XMLViewSerive.executeXMLQuery does not accept filters in ReportParams.filterExpressions'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-1709951976250888304</id><published>2011-11-06T17:58:00.000-08:00</published><updated>2011-11-06T17:58:45.198-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Telerik'/><title type='text'>Bind Telerik MVC TreeView to XElement</title><content type='html'>In order to bind Telerik MVC TreeView to an XElement, you need to define a recursive &lt;b&gt;function&lt;/b&gt;, not a helper. For example,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;@using Telerik.Web.Mvc.UI.Fluent;&lt;br /&gt;@using System.Xml.Linq;&lt;br /&gt;@model XElement&lt;br /&gt;&lt;br /&gt;@functions {&lt;br /&gt; void BindXElement(TreeViewItemFactory item, XElement elem){&lt;br /&gt;  var node = item.Add().Text(elem.Name.LocalName);&lt;br /&gt;  foreach (var e in elem.Elements()) {&lt;br /&gt;   node.Items(subItem =&amp;gt; BindXElement(subItem, e));&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@(Html.Telerik().TreeView()&lt;br /&gt;  .Name("TreeView")&lt;br /&gt;  .Items(item =&amp;gt; BindXElement(item, Model))&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-1709951976250888304?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/1709951976250888304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=1709951976250888304' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/1709951976250888304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/1709951976250888304'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/11/bind-telerik-mvc-treeview-to-xelement.html' title='Bind Telerik MVC TreeView to XElement'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-7470598633544401312</id><published>2011-08-24T19:30:00.000-07:00</published><updated>2011-08-24T19:30:25.311-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><title type='text'>A Killer Example for Functional Programming</title><content type='html'>Published at &lt;a href="http://dotnetslackers.com/articles/net/A-Killer-Example-for-Functional-Programming.aspx"&gt;dotnetslakers&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-7470598633544401312?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/7470598633544401312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=7470598633544401312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/7470598633544401312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/7470598633544401312'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/08/killer-example-for-functional.html' title='A Killer Example for Functional Programming'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-412396638339809350</id><published>2011-08-08T19:08:00.000-07:00</published><updated>2011-08-08T19:08:54.681-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Get SQL Expression out of WhereClause</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;&lt;div&gt;Several years ago I posted a method to &lt;a href="http://sjc.ironspeed.com/post?id=2589443"&gt;get SQL expression out of a WhereClause&lt;/a&gt;. I did not dig deep enough, so it was practically unusable because of Null Object Exception. This post is a long overdue correction.&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Implementation&lt;/h3&gt;Put the following code in a .cs file under App_Code (website) or Shared (web application) folder.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;using BaseClasses;&lt;br /&gt;using BaseClasses.Data;&lt;br /&gt;using BaseClasses.Data.SqlProvider;&lt;br /&gt;&lt;br /&gt;namespace DingJing {&lt;br /&gt;	public static class ExtensionWhereClause {&lt;br /&gt;		public static string GetSQL(this WhereClause wc, BaseTable tbl) {&lt;br /&gt;			var f = new CompoundFilterExt(wc.GetFilter() as CompoundFilter);&lt;br /&gt;			return f.GetSQL(tbl.DataAdapter);&lt;br /&gt;		}&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;	class CompoundFilterExt : CompoundFilter {&lt;br /&gt;		public CompoundFilterExt(CompoundFilter cf)&lt;br /&gt;			: base(cf.CompoundingOperator, cf.GetFilters()) { }&lt;br /&gt;&lt;br /&gt;		public string GetSQL(IRelationalDataAdapter adapter) {&lt;br /&gt;			var arg = new SqlGenerationArgs() {&lt;br /&gt;				Adapter = adapter,&lt;br /&gt;				Encoder = new SqlFragmentEncoder()&lt;br /&gt;			};&lt;br /&gt;			&lt;br /&gt;			var tjl = new TableJoinList();&lt;br /&gt;			var s = ToSql(arg, ref tjl);&lt;br /&gt;			return s.Expression;&lt;br /&gt;		}&lt;br /&gt;	} &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The above code adds an extension method GetSQL() to WhereClause. To get the SQL expression, you only need 1 line of code. For example,&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public override WhereClause CreateWhereClause() {&lt;br /&gt;	var wc = base.CreateWhereClause();&lt;br /&gt;	if (wc != null)&lt;br /&gt;		SQLClause.Text = wc.GetSQL(OrdersTable.Instance);&lt;br /&gt;&lt;br /&gt;	return wc;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-412396638339809350?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/412396638339809350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=412396638339809350' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/412396638339809350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/412396638339809350'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/08/get-sql-expression-out-of-whereclause.html' title='Get SQL Expression out of WhereClause'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-8933722114276347016</id><published>2011-07-29T08:57:00.000-07:00</published><updated>2011-08-05T06:15:31.878-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DataStage'/><title type='text'>DataStage Shared Container Parameters</title><content type='html'>Shared containers can have parameters. They are passed literally. &lt;b&gt;Single quotes must be escaped with "\" character.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;(v8.1)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-8933722114276347016?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/8933722114276347016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=8933722114276347016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/8933722114276347016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/8933722114276347016'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/07/datastage-shared-container-parameters.html' title='DataStage Shared Container Parameters'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-8999457001136917655</id><published>2011-07-01T21:39:00.000-07:00</published><updated>2011-07-01T21:44:02.962-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Smart Search Filter</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;&lt;div&gt;In Iron Speed Designer, it is very easy to add a search filter above a table control. It is also very easy to config the filter to work in Equals, StartsWith, EndsWith or Contains mode. At design time, I always set search filters in Contains mode to get the most search power. At&amp;nbsp;run-time, however, Contains mode sometimes returns too many hits. These are the times I wish I could double-quote the search text, and the filter would automatically switch to Equals mode.&lt;br /&gt;&lt;br /&gt;This turns out to be a pretty straightforward customization.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Code customization&lt;/h3&gt;Use the following convention to define a search filter's operator:&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Text&lt;/th&gt;&lt;th&gt;Operator&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;"&lt;/b&gt;search term&lt;b&gt;"&lt;/b&gt;&lt;/td&gt;&lt;td&gt;Equals&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;"&lt;/b&gt;search term&lt;/td&gt;&lt;td&gt;StartsWith&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;search term&lt;b&gt;"&lt;/b&gt;&lt;/td&gt;&lt;td&gt;EndsWith&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;search term&lt;/td&gt;&lt;td&gt;Contains&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div&gt;Override the table control's CreateWhereClause() method. Find the code block that defines the search behavior. Insert the following code right before the WhereClause is declared.&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;var searchOp = BaseFilter.ComparisonOperator.Contains;&lt;br /&gt;if (formatedSearchText.StartsWith("\"") &amp;&amp; formatedSearchText.EndsWith("\"")) {&lt;br /&gt;  searchOp = BaseFilter.ComparisonOperator.EqualsTo;&lt;br /&gt;  formatedSearchText = formatedSearchText.Substring(1, formatedSearchText.Length - 2);&lt;br /&gt;} else if (formatedSearchText.StartsWith("\"")) {&lt;br /&gt;  searchOp = BaseFilter.ComparisonOperator.Starts_With;&lt;br /&gt;  formatedSearchText = formatedSearchText.Substring(1);&lt;br /&gt;} else if (formatedSearchText.EndsWith("\"")) {&lt;br /&gt;  searchOp = BaseFilter.ComparisonOperator.Ends_With;&lt;br /&gt;  formatedSearchText = formatedSearchText.Substring(0, formatedSearchText.Length - 1);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Then replace the search operator in the WhereClause:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;WhereClause search = new WhereClause();&lt;br /&gt;search.iOR(CustomersTable.CustomerID, searchOp, formatedSearchText, true, false);&lt;br /&gt;search.iOR(CustomersTable.CompanyName, searchOp, formatedSearchText, true, false);&lt;br /&gt;search.iOR(CustomersTable.EmailAddress, searchOp, formatedSearchText, true, false);&lt;br /&gt;search.iOR(CustomersTable.City, searchOp, formatedSearchText, true, false);&lt;br /&gt;search.iOR(CustomersTable.Region, searchOp, formatedSearchText, true, false);&lt;br /&gt;search.iOR(CustomersTable.PostalCode, searchOp, formatedSearchText, true, false);&lt;/pre&gt;&lt;h3&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;div&gt;Now you have a smart search filter.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-8999457001136917655?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/8999457001136917655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=8999457001136917655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/8999457001136917655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/8999457001136917655'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/07/smart-search-filter.html' title='Smart Search Filter'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-6938892397756646284</id><published>2011-05-21T17:57:00.000-07:00</published><updated>2011-05-21T18:00:24.043-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DataStage'/><title type='text'>DataStage Custom Routine to Get a File Size</title><content type='html'>Below is a DataStage custom transform routine to get the size of a file. The full path of the file is passed in as a parameter called "Filename".&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;CMD = "ls -la " : Filename : " | awk '{print $5}'"&lt;br /&gt;CALL DSExecute("UNIX",CMD,Output,SystemReturnCode)&lt;br /&gt;size = Group(Output, @FM, 1)&lt;br /&gt;Ans = If Num(size) Then size Else -1&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;If the file doesn't exist, -1 is returned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-6938892397756646284?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/6938892397756646284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=6938892397756646284' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/6938892397756646284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/6938892397756646284'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/05/datastage-custom-routine-to-get-file.html' title='DataStage Custom Routine to Get a File Size'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-8026743394424402773</id><published>2011-05-16T21:26:00.000-07:00</published><updated>2011-05-16T21:28:29.526-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ELMAH'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>Securing ELMAH with Independent HTTP Authentication</title><content type='html'>Published at DotNetSlackers:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dotnetslackers.com/articles/aspnet/Securing-ELMAH-with-Independent-HTTP-Authentication.aspx"&gt;Securing ELMAH with Independent HTTP Authentication&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-8026743394424402773?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/8026743394424402773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=8026743394424402773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/8026743394424402773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/8026743394424402773'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/05/securing-elmah-with-independent-http.html' title='Securing ELMAH with Independent HTTP Authentication'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-686221023675452316</id><published>2011-04-16T10:53:00.000-07:00</published><updated>2011-04-16T10:53:43.250-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Telerik'/><title type='text'>Zoom-n-Scroll on Oversized Chart using jQuery UI's Draggable and Resizable</title><content type='html'>Published at Telerik code library: &lt;a href="http://www.telerik.com/community/code-library/aspnet-ajax/chart/zoom-window-for-oversized-chart-using-jquery-ui-s-draggable-and-resizable.aspx"&gt;Zoom Window for Oversized Chart using jQuery UI's Draggable and Resizable&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-686221023675452316?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/686221023675452316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=686221023675452316' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/686221023675452316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/686221023675452316'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/04/zoom-n-scroll-on-oversized-chart-using.html' title='Zoom-n-Scroll on Oversized Chart using jQuery UI&apos;s Draggable and Resizable'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-4259797680163697838</id><published>2011-04-03T21:24:00.000-07:00</published><updated>2011-04-03T21:27:02.760-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Reorder Table Control Rows with "Drag and Drop"</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;&lt;div&gt;Suppose you need to design a page for users to order a list of items, for example, assigning priorities to a list of tasks, or ordering questions in a questionnaire. ISD's out-of-box solution is an edit table control, in which a textbox is for entering each item's order. An obvious drawback of the solution is that users have to&amp;nbsp;manually&amp;nbsp;maintain the integrity of all orders, and &amp;nbsp;a change in one row may result in changes in other rows.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A slightly better design is to replace the textbox with a pair of up and down arrows. You can use custom code in the arrows' event handlers to switch order between the clicked item and its previous or next one. When the page is regenerated, the items are sorted on their new orders. This design guarantees order integrity, but is inefficient. In order to move an item from bottom to top of the list, it requires quite some clicks.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Wouldn't it be nice that user simply drag and drop an item to its desired position and its new order, as well as other affected items', is reassigned automatically? This post will show you how to implement it in ISD.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;div&gt;There are two candidate implementations for drag-n-drop ordering, AjaxToolkit's &lt;a href="http://www.asp.net/ajax/ajaxcontroltoolkit/Samples/ReorderList/ReorderList.aspx"&gt;ReorderList&lt;/a&gt; and a jQuery plugin &lt;a href="http://www.isocra.com/2008/02/table-drag-and-drop-jquery-plugin/"&gt;Table Drag and Drop (TableDnD)&lt;/a&gt;. ReorderList is a data-bound server control. It asks for a list of items as data source, and takes full control of data-binding and rendering. ISD has little help to offer. On the other hand, TableDnD is a pure client-side solution, leaving ISD with full control at server-side. Therefore, I will use TableDnD in this implementation.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Implementation&lt;/h3&gt;&lt;h5&gt;Step 1: Create a regular EditTable page&lt;/h5&gt;&lt;div&gt;Create a plain vanilla EditTable page as shown below. Nothing fancy.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://sjc.ironspeed.com/file?id=1108614" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="86" src="http://sjc.ironspeed.com/file?id=1108614" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h5&gt;Step 2: Add jQuery and TableDnD libraries&lt;/h5&gt;&lt;div&gt;In the page's prologue, insert 2 script references (lines 2 and 3):&lt;br /&gt;&lt;pre class="brush:javascript"&gt;&lt;script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script src="../jquery.tablednd_0_5.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;    &lt;a id="StartOfPageContent"&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5&gt;Step 3: Configure HTML &amp;nbsp;table for DnD&lt;/h5&gt;&lt;div&gt;Since ISD-generated pages are heavily loaded with HTML tables, it could be a little bit tricky to find the right one to configure. It is the inner most Fields table, as shown below.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://sjc.ironspeed.com/file?id=1108615" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="153" src="http://sjc.ironspeed.com/file?id=1108615" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;First, give the table an unique ID. TableDnD will use the ID to locate the table and attach DnD behavior.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://sjc.ironspeed.com/file?id=1108616" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="197" src="http://sjc.ironspeed.com/file?id=1108616" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Then, add 2 classes (nodrag and nodrop) to the header row. This notifies TableDnD not to attach DnD behavior to the header row.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://sjc.ironspeed.com/file?id=1108617" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="112" src="http://sjc.ironspeed.com/file?id=1108617" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h5&gt;Step 4: Add CssClass to order field&lt;/h5&gt;&lt;div&gt;Add CssClass (orderbox) to the textbox that holds the order field.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://sjc.ironspeed.com/file?id=1108618" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="89" src="http://sjc.ironspeed.com/file?id=1108618" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h5&gt;Step 5: Customize background color for the row in DnD&lt;/h5&gt;&lt;div&gt;Add the following css class in Styles.css:&lt;br /&gt;&lt;pre class="brush:javascript"&gt;tr.tDnD_whileDrag td&lt;br /&gt;{&lt;br /&gt;  background-color: #CCCCCC;&lt;br /&gt;}                                               &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5&gt;Step 6: Attach DnD behavior&lt;/h5&gt;&lt;div&gt;Finally, insert the following script into the page's epilogue:&lt;br /&gt;&lt;pre class="brush:javascript"&gt;&lt;script type="text/javascript"&gt;&lt;br /&gt;function reorder(table, row) {&lt;br /&gt; if(!table)&lt;br /&gt;   table = $("#QuizTable")[0];&lt;br /&gt; &lt;br /&gt;  var rows = table.tBodies[0].rows;&lt;br /&gt;  var step = 1;&lt;br /&gt;  for (var i = 1; i &lt; rows.length; i++) {&lt;br /&gt;    $(".orderbox", rows[i]).val(step++);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Sys.Application.add_load(function () {&lt;br /&gt; // Initialise the table&lt;br /&gt; $("#QuizTable").tableDnD({&lt;br /&gt;  onDrop : reorder&lt;br /&gt; });&lt;br /&gt; reorder();&lt;br /&gt;});&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;div&gt;It seems a lot of steps. But your users' uh-ah reaction makes it all worth the trouble. You can download the demo &lt;a href="http://sjc.ironspeed.com/file?id=1108619"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-4259797680163697838?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/4259797680163697838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=4259797680163697838' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/4259797680163697838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/4259797680163697838'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/04/reorder-table-control-rows-with-drag.html' title='Reorder Table Control Rows with &quot;Drag and Drop&quot;'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-5048061635938641531</id><published>2011-03-27T09:14:00.000-07:00</published><updated>2011-03-27T09:21:08.672-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Open ISD Pages in Popup Windows: A Comprehensive Guide</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;It is sometimes necessary to open a page in a popup window, for example, a printable version of an invoice page. ISD does this itself on large-list-selector (LLS) and quick-add pages. As a developer, when you make a page to be opened in a popup window (instead of redirecting in the main window), you explicitly or implicitly make the following decisions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Where do you open the popup? Client-side or server-side?&lt;/li&gt;&lt;li&gt;How do you pass parameters from the main window to the popup?&lt;/li&gt;&lt;li&gt;How do you send information back to the main window from the popup?&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Different scenarios need different combination of the decisions. This guide will help you make informed decisions.&lt;br /&gt;&lt;br /&gt;Note: A theme button named "PopButton" will be used as the trigger to open the popup throughout the guide.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Primer: window.open()&lt;/h3&gt;Before we examine the above three decisions, let's first review &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;window.&lt;a href="http://www.javascript-coder.com/window-popup/javascript-window-open.phtml" style="font-weight: bold;"&gt;open&lt;/a&gt;&lt;/span&gt;, for those who are not familiar with&amp;nbsp;the&amp;nbsp;JavaScript&amp;nbsp;function.&lt;br /&gt;&lt;br /&gt;No matter where and how you open a popup, you need to use the JavaScript function:&lt;br /&gt;&lt;blockquote&gt;window.open(url, windowName, windowFeatures)&lt;/blockquote&gt;Theoretically, all three parameters are optional. In practice, however, the first parameter &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;url&lt;/span&gt; is usually provided. It is meaningless to open a blank popup without an &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;url&lt;/span&gt;, unless you are trying to annoy your users.&lt;br /&gt;&lt;br /&gt;The second parameter &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;windowName &lt;/span&gt;is optional. It assigns the name to the new popup window. If there is already an open window with that name, the function will not popup a new window. In stead, it just opens the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;url&lt;/span&gt; in the existing window. You can use this parameter to control multiple pages poping up in a single window or multiple windows.&lt;br /&gt;&lt;br /&gt;The third optional parameter, &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;windowFeatures&lt;/span&gt;, controls the popup's features, such as size, position, status bar, address bar, scroll bar, toolbar, etc.&lt;br /&gt;&lt;br /&gt;With the basics out of the way, let us get back to the first decision, whether to open the popup at client-side or server-side.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Client- vs. server-side popup&lt;/h3&gt;To popup at client-side, call window.open() in PopButton's client-side OnClick event handler. This can be done within ISD through PopButton's &lt;i&gt;Custom properties&lt;/i&gt;. For example,&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt; &lt;th&gt;Property&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt; &lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Button-HtmlAttributes-OnClick&lt;/td&gt;&lt;td rowspan="2"&gt;window.open('MyPage.aspx'); return false;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Button-OnClientClick&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;The two properties are synonymous, so they can be used&amp;nbsp;interchangeably. Don't forget "return false" statement after window.open. This is to prevent the button from triggering postback.&lt;br /&gt;&lt;br /&gt;Alternatively, it can be setup in code, especially if you need to formulate the URL at run-time. For example,&lt;br /&gt;&lt;pre class="brush:csharp"&gt;string url = ...; // Formulate url&lt;br /&gt;PopButton.Button.OnClientClick = &lt;br /&gt;  string.Format("window.open('{0}'); return false;", url);&lt;br /&gt;&lt;/pre&gt;Or&lt;br /&gt;&lt;pre class="brush:csharp"&gt;string url = ...; // Formulate url&lt;br /&gt;PopButton.Button.Attributes["OnClick"] = &lt;br /&gt;  string.Format("window.open('{0}'); return false;", url);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To popup at server-side, register window.open() in PopButton's server-side OnClick event handler. For example,&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public override void PopButton_OnClick(object sender, EventArgs e){&lt;br /&gt;  string url = ...; // Formulate url&lt;br /&gt;  string script = string.Format("window.open('{0}');",, url);&lt;br /&gt;  ScriptManager.RegisterStartupScript(Page, GetType(), "OpenWindow", script, true);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;From coding point of view, there is little difference between client- and server-side popup. From efficiency and performance point of view, however, there are huge differences. Client-side popup does not pose any overhead on the server and the network; and you get instant response. On the other hand, server-side popup triggers a round trip between the server and the client; and the server undergoes a full&amp;nbsp;page&amp;nbsp;life cycle. Therefore, client-side popup is almost always favored over server-side popup.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Send information to popup window&lt;/h3&gt;&lt;div&gt;More often than not, you need to pass some information from the main window to the popup. For example, the invoice number to be printed, or the lookup table name in an LLS. There are two ways to pass the information, URL parameters and session variables. URL parameters are suitable for small number of primitive values, such as strings, integers, etc. For complex data (e.g. arrays, lists, records, etc.), session variables work better. Session variable also has the advantage to avoid sensitive information to be seen in address bar.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Send information back to main window&lt;/h3&gt;&lt;div&gt;It is not always necessary to send information back to the main window. For example, after a user prints his invoice in a popup, he simply close the popup and continue shopping in the main window. If you do need to send information back to the main window, there are again two ways to do that, from client-side or server-side.&lt;br /&gt;&lt;br /&gt;ISD's built-in LLS is a typical example for the client-side&amp;nbsp;mechanism. When a value is selected within the LLS, it is sent back to a Textbox or DropdownList in the main window via client-side JavaScript. The key in the communication is the receiving control's ClientID. It is sent to the popup window as a URL parameter. The popup uses the ID to find the control in the main window and manipulate its value. Below is the built-in JavaScript function (in ApplicationWebForm.js) to update a control in the main window.&lt;br /&gt;&lt;pre class="brush:javascript"&gt;function updateTarget(targetName, selectedValue, selectedDisplayValue){&lt;br /&gt;    if (window.opener &amp;amp;&amp;amp; !window.opener.closed) {&lt;br /&gt;        var target = window.opener.document.getElementById(targetName);&lt;br /&gt;        &lt;br /&gt;        var bSuccess = false;&lt;br /&gt;        if (!bSuccess){&lt;br /&gt;            if (Fev_ReplaceLastListControlOption(target, selectedValue, selectedDisplayValue) ){&lt;br /&gt;                //try setting the selection again&lt;br /&gt;                bSuccess = Fev_SetFormControlValue(target, selectedValue);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (bSuccess){&lt;br /&gt;            if(target != null) {&lt;br /&gt;                if (navigator.appName == "Netscape") {&lt;br /&gt;                    var myevent = document.createEvent("HTMLEvents")&lt;br /&gt;                    myevent.initEvent("change", true, true)&lt;br /&gt;                    target.dispatchEvent(myevent);&lt;br /&gt;                }&lt;br /&gt;                else { // IE&lt;br /&gt;                    target.fireEvent('onchange');&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }           &lt;br /&gt;&lt;br /&gt;        window.close();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here is the scenario you may want to try the server-side mechanism. On a typical ShowTable page, there is an New ImageButton, which redirects to an AddRecord page. Instead of redirect, you make the New button to open the AddRecord page in a popup. When a new record is saved in the popup and the popup is closed, you would like the main page refreshed to show the newly added record. This is not an issue in the redirect scenario. After redirecting back from the AddRecord page, the ShowTable page is automatically refreshed. In the popup scenario, however, the main window won't automatically refresh when the popup is closed. You have to trigger a postback in the main window from the popup. Below are the steps to implement this mechanism.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4&gt;Step 1:&amp;nbsp;Set New button's OnClientClick to open popup&lt;/h4&gt;&lt;div&gt;In ShowTable page's TableControl DataBind() method, insert the following 2 lines of code:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;string url = "AddRecord.aspx?TargetID=" + NewButton.Button.UniqueID; // Formulate url&lt;br /&gt;NewButton.Button.OnClientClick = &lt;br /&gt;  string.Format("window.open('{0}'); return false;", url);&lt;br /&gt;&lt;/pre&gt;Applying the above-mentioned decision making process, it is a no-brainer to popup at client-side and pass URL parameters. The AddRecord page itself does not need any parameters. We pass the NewButton's UniqueID so that the popup can use it to trigger postback. Please note it is the UniqueID that triggers server-side postback, not the ClientID for client-side manipulation.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4&gt;Step 2:&amp;nbsp;Change New button's action from redirect to refresh&lt;/h4&gt;&lt;div&gt;Now the New button's server-side function has been changed. We no longer need it to redirect to AddRecord page. We need it to refresh the current page. This can be easily configured in ISD. Please don't forget to change "Redirect and Send Email Actions" to "Stay on the current page."&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h4&gt;Step 3: Set popup's Save button to trigger postback in main window&lt;/h4&gt;&lt;div&gt;Insert the following lines into AddRecord Save button's Click handler:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public void SaveButton_Click(object sender, EventArgs args) {&lt;br /&gt;&lt;br /&gt; // Click handler for SaveButton.&lt;br /&gt; // Customize by adding code before the call or replace the call to the Base function with your own code.&lt;br /&gt; SaveButton_Click_Base(sender, args);&lt;br /&gt; // NOTE: If the Base function redirects to another page, any code here will not be executed.&lt;br /&gt;&lt;br /&gt; if (!ErrorOnPage) {&lt;br /&gt;  string script = string.Format("window.opener.__doPostBack('{0}', '');window.close();", Request.QueryString["TargetID"]);&lt;br /&gt;  ScriptManager.RegisterStartupScript(Page, GetType(), "TriggerPostback", script, true);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Please don't forget to change Save button's "Redirect and Send Email Actions" to "Stay on the current page." Otherwise, the inserted code won't get executed as commented in the method.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;div&gt;Using popups discretionally can improve your web applications' workflow. The tips in this post may help you decide whether to popup or how to popup.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-5048061635938641531?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/5048061635938641531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=5048061635938641531' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/5048061635938641531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/5048061635938641531'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2011/03/open-isd-pages-in-popup-windows.html' title='Open ISD Pages in Popup Windows: A Comprehensive Guide'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-1789289727592548549</id><published>2010-10-08T16:29:00.000-07:00</published><updated>2010-11-18T21:45:16.063-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Oracle'/><title type='text'>Create Oracle Materialized Views on CLOB/BLOB via DB Links</title><content type='html'>If you try to create a materialized view on a LOB column via a database link, for example,&lt;br /&gt;&lt;pre class="brush:sql"&gt;CREATE MATERIALIZED VIEW myview&lt;br /&gt;AS&lt;br /&gt;SELECT LobCol FROM tbl@another_server&lt;/pre&gt;&lt;br /&gt;Oracle will throw you the following error,&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;ORA-22992: cannot use LOB locators selected from remote tables&lt;br /&gt;22992. 00000 –  "cannot use LOB locators selected from remote tables"&lt;br /&gt;*Cause:    A remote LOB column cannot be referenced.&lt;br /&gt;*Action:   Remove references to LOBs in remote tables.&lt;/b&gt;&lt;/blockquote&gt;&lt;br /&gt;Here is a simple workaround.&lt;br /&gt;First, create a view on the remote server:&lt;br /&gt;&lt;pre class="brush:sql"&gt;create or replace view remoteview&lt;br /&gt;as&lt;br /&gt;select LobCol from tbl&lt;/pre&gt;&lt;br /&gt;Then, create your materialized view against the view:&lt;br /&gt;&lt;pre class="brush:sql"&gt;create materialized view myview&lt;br /&gt;as&lt;br /&gt;select * from remoteview@another_server&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-1789289727592548549?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/1789289727592548549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=1789289727592548549' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/1789289727592548549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/1789289727592548549'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2010/11/create-oracle-materialized-views-on.html' title='Create Oracle Materialized Views on CLOB/BLOB via DB Links'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-9007094830509683599</id><published>2010-08-28T16:46:00.000-07:00</published><updated>2010-11-18T21:49:17.461-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Persist Table Control Row Selection</title><content type='html'>A demonstration of extension over customization.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Introduction&lt;/h3&gt;&lt;br /&gt;ISD’s table controls have built-in row selection checkboxes, which do not remember their checked states on filtering, sorting or paging. This behavior is undesirable in some cases. This article will show a solution to persist row selection on filtering, sorting and paging. More importantly, it also demonstrates that extension is better than customization.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Solution by Customization&lt;/h3&gt;&lt;br /&gt;Below is the custom code to implement the functionality for a table control named OrdersTableControl.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;public class OrdersTableControlRow : BaseOrdersTableControlRow {&lt;br /&gt;&lt;br /&gt;  public OrdersTableControlRow() {&lt;br /&gt;    Init += new EventHandler(OrdersTableControlRow_Init);&lt;br /&gt;    PreRender += new EventHandler(OrdersTableControlRow_PreRender);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void OrdersTableControlRow_PreRender(object sender, EventArgs e) {&lt;br /&gt;    OrdersRecordRowSelection.Checked =&lt;br /&gt;      MyAppSession.SelectedRows.Contains(RecordUniqueId);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void OrdersTableControlRow_Init(object sender, EventArgs e) {&lt;br /&gt;    OrdersRecordRowSelection.CheckedChanged +=&lt;br /&gt;      new EventHandler(OrdersRecordRowSelection_CheckedChanged);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void OrdersRecordRowSelection_CheckedChanged(object sender, EventArgs e) {&lt;br /&gt;    if (OrdersRecordRowSelection.Checked)&lt;br /&gt;      MyAppSession.SelectedRows.Add(RecordUniqueId);&lt;br /&gt;    else&lt;br /&gt;      MyAppSession.SelectedRows.Remove(RecordUniqueId);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class OrdersTableControl : BaseOrdersTableControl {&lt;br /&gt;  public OrdersTableControl() {&lt;br /&gt;    Init += new EventHandler(OrdersTableControl_Init);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void OrdersTableControl_Init(object sender, EventArgs e) {&lt;br /&gt;    // Clear selection on initial page load&lt;br /&gt;    if (!Page.IsPostBack)&lt;br /&gt;      MyAppSession.SelectedRows.Clear();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;MyAppSession.SelectedRows is an intellisensified session variable defined in another file, as shown below.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.SessionState;&lt;br /&gt;&lt;br /&gt;namespace SelectionDemo.UI {&lt;br /&gt;  /// &lt;summary&gt;&lt;br /&gt;  /// MyAppSession provides access to session variables as static properties.&lt;br /&gt;  /// &lt;/summary&gt;&lt;br /&gt;  public class MyAppSession {&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// Private shortcut to HttpContext.Current.Session. Check its availability.&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    private static HttpSessionState currentSession {&lt;br /&gt;      get {&lt;br /&gt;        if (HttpContext.Current.Session == null)&lt;br /&gt;          throw new Exception("Session is not available in the current context.");&lt;br /&gt;        else&lt;br /&gt;          return HttpContext.Current.Session;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static string selectedRowsKey = "selectedRowsKey";&lt;br /&gt;    public static HashSet&amp;#60;string&amp;#62; SelectedRows {&lt;br /&gt;      get {&lt;br /&gt;        if (currentSession[selectedRowsKey] == null)&lt;br /&gt;          currentSession[selectedRowsKey] = new HashSet&amp;#60;string&amp;#62;();&lt;br /&gt;        return currentSession[selectedRowsKey] as HashSet&amp;#60;string&amp;#62;;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Please note that this is just for a particular table control. If you need the functionality on other table controls, cut and paste the above code, and change control names accordingly.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Solution by Extension&lt;/h3&gt;&lt;br /&gt;Using the extension framework outlined in a previous article, we can implement the functionality in BaseTableControl and BaseRecordControl.&lt;br /&gt;In BaseTableControl:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;[Category("Behavior")]&lt;br /&gt;[Description("Remember row selection")]&lt;br /&gt;[TypeConverter(typeof(bool))]&lt;br /&gt;[DefaultValue(false)]&lt;br /&gt;public bool PersistRowSelection {&lt;br /&gt;  get { return ViewState["PersistRowSelection"] != null; }&lt;br /&gt;  set {&lt;br /&gt;    if (value)&lt;br /&gt;      ViewState["PersistRowSelection"] = value;&lt;br /&gt;    else&lt;br /&gt;      ViewState.Remove("PersistRowSelection");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;string SelectedRowsKey {&lt;br /&gt;  get { return GetType().Name + "SelectedRows"; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public BaseTableControl() {&lt;br /&gt;  Init += new System.EventHandler(BaseTableControl_Init);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void BaseTableControl_Init(object sender, System.EventArgs e) {&lt;br /&gt;  if (!Page.IsPostBack &amp;amp;&amp;amp; PersistRowSelection) {&lt;br /&gt;    HttpContext.Current.Session[SelectedRowsKey] = new HashSet&amp;#60;string&amp;#62;();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public string[] GetSelectedRecordIDs() {&lt;br /&gt;  if (!PersistRowSelection)&lt;br /&gt;    throw new Exception("Row selection is not persisted.");&lt;br /&gt;&lt;br /&gt;  HashSet&amp;#60;string&amp;#62; set =&lt;br /&gt;    HttpContext.Current.Session[SelectedRowsKey] as HashSet&amp;#60;string&amp;#62;;&lt;br /&gt;  return set.ToArray();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In BaseRecordControl:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;internal string GetRecordUniqueId() {&lt;br /&gt;  return GetType()&lt;br /&gt;        .GetProperty("RecordUniqueId")&lt;br /&gt;        .GetValue(this, null) as string;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;internal CheckBox GetRowSelectionCheckBox() {&lt;br /&gt;  string name = GetType().Name.Replace("TableControlRow", "RecordRowSelection");&lt;br /&gt;  return FindControl(name) as CheckBox;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;HashSet&amp;#60;string&amp;#62; SelectedRows {&lt;br /&gt;  get {&lt;br /&gt;    string key = GetType().Name.Replace("Row", "SelectedRows");&lt;br /&gt;    return HttpContext.Current.Session[key] as HashSet&amp;#60;string&amp;#62;;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public BaseRecordControl() {&lt;br /&gt;  Init += new System.EventHandler(BaseRecordControl_Init);&lt;br /&gt;  PreRender += new EventHandler(BaseRecordControl_PreRender);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void BaseRecordControl_PreRender(object sender, EventArgs e) {&lt;br /&gt;  if(SelectedRows != null){&lt;br /&gt;    GetRowSelectionCheckBox().Checked =&lt;br /&gt;      SelectedRows.Contains(GetRecordUniqueId());&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void BaseRecordControl_Init(object sender, System.EventArgs e) {&lt;br /&gt;  if (SelectedRows != null) {&lt;br /&gt;    CheckBox box = GetRowSelectionCheckBox();&lt;br /&gt;    if (box == null)&lt;br /&gt;      throw new Exception("Cannot find row selection checkbox.");&lt;br /&gt;&lt;br /&gt;    box.CheckedChanged += new EventHandler(RowSelection_CheckedChanged);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void RowSelection_CheckedChanged(object sender, EventArgs e) {&lt;br /&gt;  if (GetRowSelectionCheckBox().Checked)&lt;br /&gt;    SelectedRows.Add(GetRecordUniqueId());&lt;br /&gt;  else&lt;br /&gt;    SelectedRows.Remove(GetRecordUniqueId());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above code will add row selection persistence to ALL table controls. To turn it on, it is as simple as setting a TableControl’s custom property PersistRowSelection to True.&lt;br /&gt;&lt;br /&gt;Of course, you cannot use ISD’s GetSelectedRecords() method to get the selection when persistence is turned on. Instead, you should use the newly defined method GetSelectedRecordIDs().&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;Persisting table row selection is as simple as setting &lt;b&gt;PersistRowSelection = True&lt;/b&gt; after implementing this extesion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-9007094830509683599?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/9007094830509683599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=9007094830509683599' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/9007094830509683599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/9007094830509683599'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2010/11/persist-table-control-row-selection.html' title='Persist Table Control Row Selection'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-301812283051870912</id><published>2010-08-26T15:45:00.000-07:00</published><updated>2010-11-23T17:15:50.220-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Customization vs. Extension</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;&lt;br /&gt;Developing ISD applications is all about customization, customization and customization. Some customizations are project specific, while others are of generic purpose, which can be used across multiple projects. Below are some examples of general purpose customizations.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.ironspeed.com/articles/Displaying%20Pop-up%20Alert%20Messages/Article.aspx"&gt;Roaming Alert: Display Alert Message even if Page Redirects&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.ironspeed.com/articles/Hide%20a%20Column%20in%20Table%20Control/Article.aspx"&gt;Hide Columns in TableControl&lt;/a&gt; (&lt;a href="http://sjc.ironspeed.com/post?id=2884971"&gt;update&lt;/a&gt;)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://sjc.ironspeed.com/post?id=4833967"&gt;Highlight Table Row with One Line of Code&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;This article is about how to better manage general purpose customizations.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Background&lt;/h3&gt;&lt;br /&gt;A trick for general purpose customization is to put the code in ISD's project template folder. When ISD generates a new project, the customization is automatically available. You don't have to manually cut and paste the customization from a previous project. An ideal example of code reuse, isn't it? Nope. It is cut-and-paste in disguise. Although ISD does the cut-and-paste for you, you are left to deal with the consequence of having multiple copies of the same code, a maintenance headache.&lt;br /&gt;&lt;br /&gt;Take the &lt;em&gt;Roaming Alert&lt;/em&gt; as an example. I put it in ISD's project template, so it became a standard feature in all of my projects. After implemented it in more than 10 projects, however, I found a bug in the original implementation. &lt;span class="Apple-style-span" &gt;&lt;b&gt;MiscUtils.RegisterJScriptAlert()&lt;/b&gt;&lt;/span&gt; method did not handle multi-line message correctly. I had to replace it with my own method. For all the previous projects, I had to go over their life cycles (development, staging, production) all over again, because the modification was at the source code level.&lt;br /&gt;&lt;br /&gt;Solution? Do not &lt;strong&gt;customize&lt;/strong&gt; ISD projects. &lt;strong&gt;Extend&lt;/strong&gt; them.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;br /&gt;To customize, insert your code directly into ISD generated projects so that&lt;br /&gt;you get customized ones. To extend, keep your code outside of ISD projects so that they are extended. The following diagram illustrates the difference between customization and extension.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_KJ8z2JHqBo4/TOxnCidwh1I/AAAAAAAABOY/FGOpP_cll64/s1600/ClassDiagram.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 214px;" src="http://1.bp.blogspot.com/_KJ8z2JHqBo4/TOxnCidwh1I/AAAAAAAABOY/FGOpP_cll64/s400/ClassDiagram.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5542918534695257938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Implementation&lt;/h3&gt;&lt;br /&gt;Here is a sample implementation of the extension BasePage.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;&lt;br /&gt;namespace DingJing {&lt;br /&gt;  public class BasePage : BaseClasses.Web.UI.BasePage {&lt;br /&gt;&lt;br /&gt;    public BasePage() {&lt;br /&gt;      PreRender +=  new EventHandler(My_PreRender);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void My_PreRender(object sender, EventArgs e) {&lt;br /&gt;      Dictionary&amp;lt;string, string&amp;gt; AlertQueue =&lt;br /&gt;        Session["AlertQueue"] as Dictionary&amp;lt;string, string&amp;gt;;&lt;br /&gt;      if (AlertQueue != null) {&lt;br /&gt;        foreach (string key in AlertQueue.Keys)&lt;br /&gt;          DisplayAlert(key, AlertQueue[key]);&lt;br /&gt;        AlertQueue.Clear();&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void DisplayAlert(string key, string msg) {&lt;br /&gt;      msg = msg.Replace(@"\", @"\\").Replace("'", @"\'").Replace("\n", @"\n");&lt;br /&gt;      string script = string.Format("alert('{0}');", msg);&lt;br /&gt;      ScriptManager.RegisterStartupScript(this, GetType(), key, script, true);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public virtual void RegisterAlert(string key, string msg, bool roaming) {&lt;br /&gt;      if (!roaming) {&lt;br /&gt;        DisplayAlert(key, msg);&lt;br /&gt;      } else {&lt;br /&gt;        Dictionary&amp;lt;string, string&amp;gt; AlertQueue =&lt;br /&gt;          Session["AlertQueue"] as Dictionary&amp;lt;string, string&amp;gt;;&lt;br /&gt;        if (AlertQueue == null)&lt;br /&gt;          Session["AlertQueue"] = AlertQueue = new Dictionary&amp;lt;string, string&amp;gt;();&lt;br /&gt;        AlertQueue.Add(key, msg);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Then, make your project's BaseApplicationPage a subclass of the extension BasePage.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;namespace ProjectNamespace.UI {&lt;br /&gt;  public class BaseApplicationPage : DingJing.BasePage {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can make the class hierarchy change in generated projects, or in ISD project template. You can extend BaseApplicationTableControl and BaseApplicationRecordControl similarily.&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;&lt;br /&gt;namespace DingJing {&lt;br /&gt;  public class BaseTableControl : System.Web.UI.Control {&lt;br /&gt;&lt;br /&gt;    public void SetColumnVisibility(string colName, bool visible) {&lt;br /&gt;      Control header = FindControl(colName + "Header");&lt;br /&gt;      if (header != null)&lt;br /&gt;        header.Visible = visible;&lt;br /&gt;&lt;br /&gt;      Control[] rows = GetType().GetMethod("GetRecordControls").Invoke(this, null) as Control[];&lt;br /&gt;      foreach (Control row in rows) {&lt;br /&gt;        Control cell = row.FindControl(colName + "Cell");&lt;br /&gt;        if (cell != null)&lt;br /&gt;          cell.Visible = visible;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;namespace ProjectNamespace.UI {&lt;br /&gt;  public class BaseApplicationTableControl : DingJing.BaseTableControl {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;&lt;br /&gt;namespace DingJing {&lt;br /&gt;  public class BaseRecordControl : System.Web.UI.Control {&lt;br /&gt;&lt;br /&gt;    public void SetRowAppearance(string cssName) {&lt;br /&gt;      WebControl ctrl = Controls&lt;br /&gt;        .OfType&lt;WebControl&gt;()&lt;br /&gt;        .Where(c =&gt; !(c is Literal) &amp;&amp; c.Visible)&lt;br /&gt;        .First();&lt;br /&gt;      string script = string.Format(&lt;br /&gt;        "$('td', $('#{0}').closest('tr')).addClass('{1}');",&lt;br /&gt;        ctrl.ClientID,&lt;br /&gt;        cssName);&lt;br /&gt;      ScriptManager.RegisterStartupScript(this, GetType(), ClientID, script, true);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;namespace ProjectNamespace.UI {&lt;br /&gt;  public class BaseApplicationRecordControl : DingJing.BaseRecordControl {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Benefit&lt;/h3&gt;&lt;br /&gt;First, maintenance overhead is greatly reduced. You have only one copy of the source code to maintain. Other projects only need to update their reference if there is any changes. If they are already deployed to production, you only need to copy over one dll file.&lt;br /&gt;&lt;br /&gt;Second, I no longer have to post my code samples in 2 languages. Even if your main ISD project is in VB, you can still reference libraries written in C#. If you are a consultant developing projects for different clients using different languages, this is also for you.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;br /&gt;For general purpose customizations, refactoring them into a separate project will greatly reduce maintenance overhead.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-301812283051870912?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/301812283051870912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=301812283051870912' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/301812283051870912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/301812283051870912'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2010/11/customization-vs-extension.html' title='Customization vs. Extension'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_KJ8z2JHqBo4/TOxnCidwh1I/AAAAAAAABOY/FGOpP_cll64/s72-c/ClassDiagram.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-2490078405750330357</id><published>2010-08-15T09:50:00.000-07:00</published><updated>2010-12-22T05:19:52.055-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Replace a detail table control with a list control: CheckBoxList or DualList</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;ISD's master-detail page supports adding/editing a master record and its detail records. However, the out-of-the-box detail table control is not the ideal presentation in some scenarios. Sometimes, a CheckBoxList is much clearer to present the information and easier for users to make selections, as described in &lt;a href="http://www.ironspeed.com/mvp/MVPHermanChan.aspx"&gt;Herman Chan&lt;/a&gt;'s&amp;nbsp;article, &lt;a href="http://www.ironspeed.com/articles/Implement%20Detail%20Table%20as%20CheckBoxList/Article.aspx"&gt;Implementing a Detail Table as CheckBox List&lt;/a&gt;. In some cases, a DualList&amp;nbsp;might be the best choice as described in this &lt;a href="http://sjc.ironspeed.com/post?id=4644115"&gt;article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In both articles, the plumbing work of data loading and saving is encapsulated in custom user controls. User controls are easier to develop, but more difficult to deploy or use, than server controls. For example,&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Maintain multiple source files within a project.&lt;/li&gt;&lt;li&gt;Maintain different versions (C# and VB) of source files for different projects. This may be not necessary for in-house development, but is likely for consulting projects.&lt;/li&gt;&lt;li&gt;Limited access to properties and methods for dynamically loaded user controls at run-time.&lt;/li&gt;&lt;li&gt;Limited access to inner properties at design-time.&lt;/li&gt;&lt;/ul&gt;It would be nice to see both implemented as server controls.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Solution&lt;/h3&gt;The most difficult part of implementing a server control is typically its&amp;nbsp;rendering. You are not able to drag and drop components into a designer window, but&amp;nbsp;have to code it line by line. However, using a technique described in &lt;a href="http://dotnetslackers.com/articles/aspnet/Deveploy-a-Userver-Control.aspx"&gt;Deveploy a Userver Control&lt;/a&gt;, you can design a server control with drag&amp;nbsp;and drop just like a user control. In this article, I re-implemented&amp;nbsp;CheckBoxList and DualList as server controls. The class diagram is shown below.&lt;br /&gt;&lt;a href="http://dingjing.files.wordpress.com/2010/08/classdiagram.png"&gt;&lt;img alt="" class="alignnone size-full wp-image-13" height="221" src="http://dingjing.files.wordpress.com/2010/08/classdiagram.png" title="ClassDiagram" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;I am not going to reiterate the details about how they are implemented (you can get them from the above links). Instead, I will simply describe how to use them in your ISD projects.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Use the controls&lt;/h3&gt;Using the two controls is like using any other 3rd-party components.&lt;br /&gt;&lt;br /&gt;&lt;h4 style="font-style: italic;"&gt;Step 1: Add dll library&lt;/h4&gt;Download and unzip the demo at the end of this article. Find the following 3 dll files in the bin folder, and copy them to your project's bin folder.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;DetailListControl.dll&lt;/li&gt;&lt;li&gt;DualListBox.dll&lt;/li&gt;&lt;li&gt;UserverCtrl.dll&lt;/li&gt;&lt;/ol&gt;If your project is a "Web Application" project, you also need to explicitly add reference to the first dll (DetailListControl.dll). You don't have to explicitly reference the other two dlls. They are just dependencies.&lt;br /&gt;&lt;br /&gt;&lt;h4 style="font-style: italic;"&gt;Step 2: Add control to a page&lt;/h4&gt;First, register the assembly in page prologue:&lt;br /&gt;&lt;pre class="brush:html"&gt;&amp;lt;%@ Register Assembly="DetailListControl" Namespace="DingJing" TagPrefix="dj" %&amp;gt;&lt;br /&gt;&lt;/pre&gt;Next, insert the control in a cell editor. For example,&lt;br /&gt;&lt;a href="http://dingjing.files.wordpress.com/2010/08/celleditor.png"&gt;&lt;img alt="" class="alignnone size-full wp-image-15" height="370" src="http://dingjing.files.wordpress.com/2010/08/celleditor.png" title="CellEditor" width="612" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4 style="font-style: italic;"&gt;Step 3: Configure the control&lt;/h4&gt;Both CheckListDetailControl and DualListDetailControl inherit the following properties from the DetailListControl.&lt;br /&gt;&lt;table border="1px"&gt;&lt;tbody&gt;&lt;tr&gt; &lt;td&gt;&lt;strong&gt;Property&lt;/strong&gt;&lt;/td&gt; &lt;td&gt;&lt;strong&gt;Required&lt;/strong&gt;&lt;/td&gt; &lt;td style="font-weight: bold;"&gt;Description&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;DetailTableName&lt;/td&gt; &lt;td class="style1"&gt;Yes&lt;/td&gt; &lt;td&gt;Name of detail table or view. For example, Developer_Language, Developer_DBMS.&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;DetailColumnName&lt;/td&gt; &lt;td class="style1"&gt;Yes&lt;/td&gt; &lt;td&gt;Name of detail comlumn. For example, Language_ID, DBMS_ID.&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;WhereString&lt;/td&gt; &lt;td class="style1"&gt;No&lt;/td&gt; &lt;td&gt;Filter on detail column's parent table or view. For example, Programming, DBMS.&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;a href="http://dingjing.files.wordpress.com/2010/08/schema.jpg"&gt;&lt;img alt="" class="alignnone size-full wp-image-16" height="336" src="http://dingjing.files.wordpress.com/2010/08/schema.jpg" title="Schema" width="586" /&gt;&lt;/a&gt;&lt;br /&gt;WhereString can be set dynamically. The ideal place to set it at runtime is in the PrePopulate event handler. In addition to the WhereString property (of string type), you can also set the ItemFilter property (of WhereClause type) directly at runtime, as shown in the following code snippet.&lt;br /&gt;&lt;br /&gt;C#&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public DevelopersRecordControl() {&lt;br /&gt;  Init += new EventHandler(DevelopersRecordControl_Init);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void DevelopersRecordControl_Init(object sender, EventArgs e) {&lt;br /&gt;  ProgrammingDualList.PrePopulate += new EventHandler(ProgrammingDualList_PrePopulate);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void ProgrammingDualList_PrePopulate(object sender, EventArgs e) {&lt;br /&gt;  WhereClause wc = new WhereClause(ProgrammingTable.Language_Name,&lt;br /&gt;    BaseFilter.ComparisonOperator.Starts_With, "C");&lt;br /&gt;  ProgrammingDualList.ItemFilter = wc;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;VB&lt;br /&gt;&lt;pre class="brush:vb"&gt;Public Sub New()&lt;br /&gt;  Init += New EventHandler(AddressOf DevelopersRecordControl_Init)&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Private Sub DevelopersRecordControl_Init(sender As Object, e As EventArgs)&lt;br /&gt;  ProgrammingDualList.PrePopulate += New EventHandler(AddressOf ProgrammingDualList_PrePopulate)&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Private Sub ProgrammingDualList_PrePopulate(sender As Object, e As EventArgs)&lt;br /&gt;  Dim wc As New WhereClause(ProgrammingTable.Language_Name, BaseFilter.ComparisonOperator.Starts_With, "C")&lt;br /&gt;  ProgrammingDualList.ItemFilter = wc&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The presentation components of the two controls are exposed as public properties, CheckList and DualList, respectively. So they can be configured declaratively or dynamically. For example,&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:html"&gt;&lt;dj:checklistdetailcontrol detailcolumnname="DBMS_ID" detailtablename="Developer_DBMS" id="DatabaseCheckList" runat="server"&gt;&lt;br /&gt;  &lt;checklist repeatcolumns="3" repeatdirection="Horizontal"&gt;&lt;br /&gt;&lt;/checklist&gt;&lt;/dj:checklistdetailcontrol&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4 style="font-style: italic;"&gt;Step 4: DataBind and SaveData&lt;/h4&gt;Each DetailListControl needs a line of code to be wired up with its master record at DataBind() or SaveData(). For example,&lt;br /&gt;&lt;br /&gt;C#&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public override void DataBind() {&lt;br /&gt;  base.DataBind();&lt;br /&gt;&lt;br /&gt;  if (DataSource != null) {&lt;br /&gt;    ProgrammingDualList.DataBind(DataSource);&lt;br /&gt;    DatabaseCheckList.DataBind(DataSource);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public override void SaveData() {&lt;br /&gt;  base.SaveData();&lt;br /&gt;&lt;br /&gt;  ProgrammingDualList.SaveData(DataSource);&lt;br /&gt;  DatabaseCheckList.SaveData(DataSource);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;VB&lt;br /&gt;&lt;pre class="brush:vb"&gt;Public Overrides Sub DataBind()&lt;br /&gt;  MyBase.DataBind()&lt;br /&gt;&lt;br /&gt;  If DataSource IsNot Nothing Then&lt;br /&gt;    ProgrammingDualList.DataBind(DataSource)&lt;br /&gt;    DatabaseCheckList.DataBind(DataSource)&lt;br /&gt;  End If&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;Public Overrides Sub SaveData()&lt;br /&gt;  MyBase.SaveData()&lt;br /&gt;&lt;br /&gt;  ProgrammingDualList.SaveData(DataSource)&lt;br /&gt;  DatabaseCheckList.SaveData(DataSource)&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;Reimplementated as server controls, the CheckListDetailControl and the DualListDetailControl are easier to (re)use than their user control versions.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Download&lt;/h3&gt;&lt;a href="http://sjc.ironspeed.com/file?id=1017801"&gt;Demo application&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-2490078405750330357?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/2490078405750330357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=2490078405750330357' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/2490078405750330357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/2490078405750330357'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2010/08/replace-detail-table-control-with-list.html' title='Replace a detail table control with a list control: CheckBoxList or DualList'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2677760060687280469.post-2813800278112119423</id><published>2010-08-07T08:21:00.000-07:00</published><updated>2010-11-28T09:49:14.859-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ISD'/><title type='text'>Highlight a table row with 1 line of code</title><content type='html'>&lt;h3&gt;Introduction&lt;/h3&gt;It is a usual requirement to highlight a table row based on specific conditions. ISD has a &lt;a href="http://www.ironspeed.com/Designer/7.0.2/Code%20Customizations/ShowCodeCustomization.aspx?codeCustomizationName=/Designer/7.0.2/Code%20Customizations/cs/Highlight%20Controls/Highlight%20a%20Record%20Row%20Based%20on%20a%20Condition&amp;amp;displayType=description&amp;amp;scriptLanguage=cs"&gt;CCW&lt;/a&gt; (Highlight a table row based on a condition) designed exactly for that purpose. However, using the CCW is a little tedious. First, you need to make the row "runat = server" in the designer. Then, run through the wizard, which inserts more than 20 lines of code into code-behind. (Even after comments removed, there are still about 10 lines of code.)&lt;br /&gt;&lt;br /&gt;This article will show you a much simpler way to highlight a table row. After initial setup, only 1 line of code is needed. I don't think you can get it any simpler.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Initial Setup&lt;/h3&gt;&lt;h4&gt;Step 1: Add jQuery support&lt;/h4&gt;In the master page's prologue, add the following line (line 3):&lt;br /&gt;&lt;pre class="brush:jscript"&gt;&lt;scripts&gt;&lt;br /&gt;    &amp;lt;asp:ScriptReference  Path="~/SetFocus.js"  /&amp;gt;&lt;br /&gt;    &amp;lt;asp:ScriptReference  Path="http://code.jquery.com/jquery-1.4.2.min.js"  /&amp;gt;&lt;br /&gt;&lt;/Scripts&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Step 2: Add SetRowAppearance() method&lt;/h4&gt;In BaseApplicationRecordContorl class, insert the following method.&lt;br /&gt;C#&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public void SetRowAppearance(string cssName) {&lt;br /&gt;  WebControl ctrl = Controls&lt;br /&gt;    .OfType&amp;lt;WebControl&amp;gt;()&lt;br /&gt;    .Where(c =&amp;gt; !(c is Literal) &amp;&amp; c.Visible)&lt;br /&gt;    .First();&lt;br /&gt;  string script = string.Format(&lt;br /&gt;    "$('td', $('#{0}').closest('tr')).addClass('{1}');",&lt;br /&gt;    ctrl.ClientID,&lt;br /&gt;    cssName);&lt;br /&gt;  ScriptManager.RegisterStartupScript(this, GetType(), ClientID, script, true);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;VB&lt;br /&gt;&lt;pre class="brush:vb"&gt;Public Sub SetRowAppearance(cssName As String)&lt;br /&gt;    Dim ctrl As WebControl = Controls.OfType(Of WebControl)().Where(Function(c) Not (TypeOf c Is Literal) AndAlso c.Visible).First()&lt;br /&gt;    Dim script As String = String.Format("$('td', $('#{0}').closest('tr')).addClass('{1}');", ctrl.ClientID, cssName)&lt;br /&gt;    ScriptManager.RegisterStartupScript(Me, [GetType](), ClientID, script, True)&lt;br /&gt;End Sub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Step 3: Add highlighted css class(es)&lt;/h4&gt;In your project App_Theme's Style.css, add as many css classes as you like. For example,&lt;br /&gt;&lt;pre class="brush:css"&gt;td .highlighted { &lt;br /&gt;  background-color: #FF99FF;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;br /&gt;These steps are required only once for a project. They can also be setup in ISD's project template. Then the functionality will be available automatically in new projects.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Highlight a row&lt;/h3&gt;Here is the one-liner to highlight a row. Please note that the example is called from within a TableControlRow class.&lt;br /&gt;C#&lt;br /&gt;&lt;pre class="brush:csharp"&gt;if (SomeCondition)&lt;br /&gt;  this.SetRowAppearance("highlighted");&lt;br /&gt;&lt;/pre&gt;VB&lt;br /&gt;&lt;pre class="brush:vb"&gt;If SomeCondition Then&lt;br /&gt;  Me.SetRowAppearance("highlighted")&lt;br /&gt;End If&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;br /&gt;Having a closer look at SetRowAppearance() method, you will notice that it needs a non-Literal WebControl as a "seed" to locate the row at client side. If your table row contains any ImageButtons, CheckBoxes, DropDownLists, etc, the method will work just fine. In case your row contains only Literals, switch one of them to Label.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2677760060687280469-2813800278112119423?l=jingding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jingding.blogspot.com/feeds/2813800278112119423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2677760060687280469&amp;postID=2813800278112119423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/2813800278112119423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2677760060687280469/posts/default/2813800278112119423'/><link rel='alternate' type='text/html' href='http://jingding.blogspot.com/2010/08/introduction-it-is-usual-requirement-to.html' title='Highlight a table row with 1 line of code'/><author><name>Jing</name><uri>http://www.blogger.com/profile/00701892215626207223</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='26' src='http://4.bp.blogspot.com/_KJ8z2JHqBo4/TONGSu8caoI/AAAAAAAABNw/YlAZTsh7Yag/S220/CustomerProfileJingDing.gif'/></author><thr:total>0</thr:total></entry></feed>
