Programming Journal C#, Java, SQL and to a lesser extent HTML, CSS, XML, and regex. I made this so other programmers could benefit from my experience.

Wednesday, February 27, 2008

Lazy Load Panel Courtesy of TabContainer and UpdatePanel

Here is how I implemented a Lazy load Panel. This is a nifty way to have a mini-menu of tabs without some big data transfer happening all at once. The ASP.NET render after complete model makes incremental rendering a necessary task of the developer or else the users will take a hike. This is my adaptation of Matt Burseth's example that should be helpful to avoid the LESSTHAN%= and LESSTHAN%# problems that I had. Remember to put the js in the form tag (probably below the ScriptManager). Two parts below are the ASPX and Code Behind. ASPX:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Lazy Load Panel Page</title>

</head>
<body>
<form id="form1" runat="server">
<ajax:ScriptManager ID="ScriptManager1" runat="server">
</ajax:ScriptManager>
<script type="text/javascript" language="javascript">
//var _updateProgressDiv;

function pageLoad(sender, args) {
// register for our eveents
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginRequest);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);

//_updateProgressDiv = $get('ActionProgress');
}
function beginRequest(sender, args) {
// get the gridview element
var tabContainer = $get('<%= this.tcTest.ClientID %>');
alert(tabContainer);
// make it visible
// _updateProgressDiv.style.display='';
}
function endRequest(sender, args) {
// make it invisible
// _updateProgressDiv.style.display='none';
}

function clientActiveTabChanged(sender, args) {
// see if table elements for the grids exist yet
var isTab1Loaded = $get('<%= this.gv1.ClientID %>');
var isTab2Loaded = $get('<%= this.gv2.ClientID %>');
var isTab3Loaded = $get('<%= this.gv3.ClientID %>');

// if tab does not exist and it is the active tab, trigger the async-postback
alert(isTab1Loaded + ',' + isTab2Loaded + ',' + isTab3Loaded + ':' + sender.get_activeTabIndex());
if (!isTab1Loaded && sender.get_activeTabIndex() == 0) {
// load tab1
// alert('fire1');
__doPostBack('<%= btn1Trigger.UniqueID %>', '');
}
if (!isTab2Loaded && sender.get_activeTabIndex() == 1 ) {
// load tab2
// alert('fire2');
__doPostBack('<%= btn2Trigger.UniqueID %>', '');
}
if (!isTab3Loaded && sender.get_activeTabIndex() == 2 ) {
// load tab3
// alert('fire3');
__doPostBack('<%= btn3Trigger.UniqueID %>', '');
}
}
</script>
<input id="btn1Trigger" runat="server" type="button" style="display:none" onserverclick="btn1Trigger_Click" />
<input id="btn2Trigger" runat="server" type="button" style="display:none" onserverclick="btn2Trigger_Click" />
<input id="btn3Trigger" runat="server" type="button" style="display:none" onserverclick="btn3Trigger_Click" />

<div>
<ajaxc:TabContainer ID="tcTest" runat="server" OnClientActiveTabChanged="clientActiveTabChanged" ActiveTabIndex="0">
<ajaxc:TabPanel ID="tp1" runat="server" HeaderText="TabPanel1">
<ContentTemplate>
<ajax:UpdatePanel ID="upnl1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
1<br />
<asp:GridView ID="gv1" runat="server" Visible="true" DataSourceID="sqlLicStatus">
</asp:GridView>
</ContentTemplate>
<Triggers>
<ajax:AsyncPostBackTrigger ControlID="btn1Trigger" />
</Triggers>
</ajax:UpdatePanel>
</ContentTemplate>
</ajaxc:TabPanel>

<ajaxc:TabPanel ID="tp2" runat="server" HeaderText="TabPanel2">
<ContentTemplate>
<ajax:UpdatePanel ID="upnl2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
2<br />
<asp:GridView ID="gv2" runat="server" Visible="False" DataSourceID="sqlCondition" >
</asp:GridView>
</ContentTemplate>
<Triggers>
<ajax:AsyncPostBackTrigger ControlID="btn2Trigger" />
</Triggers>
</ajax:UpdatePanel>
</ContentTemplate>
</ajaxc:TabPanel>

<ajaxc:TabPanel ID="tp3" runat="server" HeaderText="TabPanel3">
<ContentTemplate>
<ajax:UpdatePanel ID="upnl3" runat="server" UpdateMode="Conditional">
<ContentTemplate>
3<br />
<asp:GridView ID="gv3" runat="server" Visible="False" DataSourceID="sqlCondition" >
</asp:GridView>
</ContentTemplate>
<Triggers>
<ajax:AsyncPostBackTrigger ControlID="btn3Trigger" />
</Triggers>
</ajax:UpdatePanel>
</ContentTemplate>
</ajaxc:TabPanel>

</ajaxc:TabContainer>
</div>





<asp:SqlDataSource ID="sqlLicStatus" runat="server"
ProviderName="System.Data.Bar"
DataSourceMode="DataReader"
ConnectionString="foo"
SelectCommand="SELECT foo FROM Validations WHERE bar=102 ORDER BY Code;">
</asp:SqlDataSource>
<asp:SqlDataSource ID="sqlCondition" runat="server"
ProviderName="System.Data.Foo"
DataSourceMode="DataReader"
ConnectionString="foo"
SelectCommand="SELECT foo FROM Validations WHERE bar=18 ORDER BY Code;">
</asp:SqlDataSource>
</form>
</body>
</html>
Code Behind:

/// <summary>
/// Lazy load TabPanel in a TabContainer
/// The update panel contents are fetched if client trigger is fired.
/// The client trigger is fired if the target tab is active and the
/// target GridView is not active (visible).
/// </summary>
public partial class Samples_LazyPanel : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
protected void btn1Trigger_Click(object sender, EventArgs args)
{
this.gv1.Visible = true;
this.gv1.DataBind();
}
protected void btn2Trigger_Click(object sender, EventArgs args)
{
this.gv2.Visible = true;
this.gv2.DataBind();
}
protected void btn3Trigger_Click(object sender, EventArgs args)
{
this.gv3.Visible = true;
this.gv3.DataBind();
}
}

Simple and Complex Drilldown for ASP.Net Objects

It can be difficult to drill down through an ASPX page to see where your desired object is before you call FindControl. One quick way to figure out the control tree structure is the Document Outline tab of Microsoft Visual Studio. The only caveat is that you will still need to know your Master Page structure.

The complex overkill way is to use Trace="true" under the Page Directive (at the top of the aspx page.) This has other applications as well. For example, instead of debug prints you can see the state of many variables.

Web User Control Library error

When you create a User Control from a class and try to drag and drop the control into the design page, you may get an Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC)) error. Talk about confusing. My solution was to make my (user control) class public.

Thursday, February 21, 2008

Prevent RadioButtonList from forcing a line break

Prevent RadioButtonList from forcing a line break by placing the control in a span and set the RepeatLayout attribute to Flow.

Reference: http://www.webdeveloper.com/forum/showthread.php?t=138562

Tuesday, February 19, 2008

Using Web.config hash for variables using add, key, and value

Use configuration (web.config) hash to set variables. First, there is the web.config file section: ...

<configuration>
<appSettings>
<add key="fooLink" value="http://www.foo.htm"/>
</appSettings>
</configuration>
Now in the code-behind I can set a Hyperlink variable as follows:

HyperLinkFoo.NavigateUrl = ConfigurationManager.AppSettings["fooLink"].ToString().ToLower();

Monday, February 18, 2008

Drilling down a nested master page in ASP.NET to reset a form

Here is an example of drilling down a master page in ASP.NET to reset a form's TextBox controls:

protected void btnqReset_Click(object sender, EventArgs e)
{

try
{
ContentPlaceHolder childMasterContent = (ContentPlaceHolder)Page.Form.FindControl("ParentMasterContent").FindControl("ChildMasterContent");
Control ctrlForm = childMasterContent.FindControl("upnlQueryMoreCriteria").FindControl("pnlQueryMoreCriteria");
Control[] queryControls = { ctrlForm };
for (int i = 0; i < 1; i++)
{
if (queryControls[i].Controls != null)
{
foreach (Control ct in queryControls[i].Controls)
{
if (ct.GetType().ToString().Equals("System.Web.UI.WebControls.TextBox"))
{
((TextBox)ct).Text = "";
}
}
}
}
}
catch (Exception ex)
{
log.Error("Unable to reset query criteria: " + ex.Message + ex.StackTrace);

}
}

Intercepting return in list menu items in ASP.NET

Here is how I was able to intercept the return button in my list menu item when selected, despite a default button on the aspx page:

<li><a href="" onkeydown="if (event.keyCode==13) { window.location.href='http://www.foo.com';}"</a></li>

Saturday, February 16, 2008

FindContol Solution to add Javascript to a control from a user control

Here is a great solution to finding a control using FindControl method from a user control. TargetcontrolID is the public property for TextBoxFooExtender (User Control). _txt is the targeted TextBox assuming it is found.

protected override void CreateChildControls()
{
txt = (TextBox)this.Parent.FindControl(TargetControlID);
if (txt != null) {
_txt.Attributes.Add("ondblclick", "alert('foo')");
}
base.CreateChildControls();
}

Friday, February 15, 2008

How to show and hide CalendarExtender and CollapsiblePanel

Here is the javascript for expanding or collapsing a collapsible panel:


// Used for collapsible panels to toggle collapse or open
function CollapsiblePanelExtender_Toggle(behaviorId)
{
var behavior = $find(behaviorId);
if (behavior!=null) {
if (behavior.get_Collapsed()==false) {
try {behavior._doClose();} catch(e) { }
}else if (behavior.get_Collapsed()==true) {
try {behavior._doOpen();} catch(e) { }
}
}
}
// Used for calendar extenders to toggle show or hide
function CalendarExtender_Toggle(behaviorId) {
var behavior = $find(behaviorId);
if (behavior!=null) {
if (behavior._isOpen==true) {
try {behavior.hide();} catch(e) { }
}else if (behavior._isOpen==false) {
try {behavior.show();} catch(e) { }
}
}
}
The Calendar show and hide behavior is above. Note: it may be helpful to use an empty label/image for the calendarExtender popupcontrolId to manage show/hide behavior.

Tuesday, February 12, 2008

Understanding Default Values for User Web Controls

Understanding default values for User Web Controls can be confusing.
First, there is the DefaultValue for the code behind, which does not act as a default value, but as a default property value for the properties window. Here is the Default Property Value for the properties window set in the ascx.cs page:

[Browsable(true)]
[DefaultValue("")]
public string Text
{
get { return Label.Text; }
set { Label.Text = value;
}
}
Now, what you really want is the default value for the control to be set in the ascx page as follows:

<asp:Label ID="Label" runat="server" Text=""></asp:Label>
You can then manipulate the value in the DataBind, CreateChildControls, or Property section. Be aware that the property section doesn't necessarily fire, hence the need to use the ascx properties.

Sunday, February 10, 2008

Creating a ListItemCollection Template User Control

Creating a ListItemCollection Template User Control. Here are the 3 files necessary. A link to the reference link is below.

First: The user control code-behind:

[DefaultEvent("SelectedIndexChanged"),
Designer("System.Web.UI.Design.WebControls.ListControlDesigner, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
ParseChildren(true, "Items"), ControlValueProperty("SelectedValue"),
DataBindingHandler("System.Web.UI.Design.WebControls.ListControlDataBindingHandler, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public partial class ComboBoxControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{

}
private ListItemCollection m_Items;

[DefaultValue((string)null), MergableProperty(false),
PersistenceMode(PersistenceMode.InnerDefaultProperty),
Editor("System.Web.UI.Design.WebControls.ListItemsCollectionEditor,System.Design, Version=2.0.0.0,Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
typeof(UITypeEditor))]
public virtual ListItemCollection Items
{
get
{
if (this.m_Items == null)
{
this.m_Items = new ListItemCollection();
}
return this.m_Items;
}
}
protected override void CreateChildControls()
{
if (this.m_Items == null)
{
this.m_Items = new ListItemCollection();
}

if (m_Items.Count>0) {
foreach (ListItem item in m_Items)
{
_ComboBoxControl.Items.Add(item);
}
}
}
public override void DataBind()
{
CreateChildControls();
ChildControlsCreated = true;
_ComboBoxControl.DataBind();
base.DataBind();
}
}
Next, the User control

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ComboBoxControl.ascx.cs" Inherits="ComboBoxControl" %>
<asp:DropDownList ID="_ComboBoxControl" runat="server">
</asp:DropDownList>
And finally the aspx:

<uc1:ComboBoxControl ID="ComboBoxControl1" runat="server">
<Items>
<asp:ListItem Value="Value1" Text="Text1" />
<asp:ListItem Value="Value2" Text="Text2" />
<asp:ListItem Value="Value3" Text="Text3" />
<asp:ListItem Value="Value4" Text="Text4" />
</Items>
</uc1:ComboBoxControl>


Credit to: http://developers.de/blogs/damir_dobric/archive/2007/03/30/Implementing-Custom-UserControl-with-ListItem-collection.aspx

Friday, February 8, 2008

Installing CA Anti-virus with error on open

I had a Vista problem installing the av_en_32.exe install wizard after I move the file from another computer. It gave some error that Windows cannot access the specified device, path, or file . You may not have the appropriate permissions to access them.

Solution: Right-click the icon and Unblock.

Tuesday, February 5, 2008

Web Control IDs INamingContainer to avoid duplicate IDs

The ID property of the WebUserControl for controls that may be used mulitiple times in an aspx page should not be repeated. Simple implment the INamingContainer to prevent duplicate IDs as follows:

public partial class UCRepeater : System.Web.UI.UserControl, INamingContainer
Marker Interface - An interface that does not require explicit implementation.