Friday, August 14, 2009

Programmatically setting Master Page

The MasterPage class derives from UserControl. The master page will inject itself as the top control in a page’s control hierarchy by clearing the page’s Controls array and adding itself to into the collection. Doing so includes all of the markup and controls defined inside the master page in the page's control tree. The master page can then walk the Content controls that existed in the web form and bring them back them into the control hierarchy in the appropriate locations. The master page injection happens after the PreInit event fires for a Page object, but before the Init event fires.

We can use the @ Page directive and the web.config to specify master page files for our web forms, but sometimes we want to set the master page programatically. A page’s MasterPageFile property sets the master page for the content page to use. This property must be set in the PreInit event (or earlier), like the code below. One the master page has injected itself into the control hierarchy it is too late to try to set a new master page for the web form. If you try to set the MasterPageFile property after the PreInit event fires, the runtime will throw an InvalidOperationException.


Protected Sub Page_PreInit(ByVal sender As Object, _
ByVal e As EventArgs) _
Handles Me.PreInit
' we can select a different master page in the PreInit event
Me.MasterPageFile = "~/otherMasterPage.master"
End Sub


Another way to interact with a master page is through the Master property of a page object. Let’s say we need to get to the Footer property defined in our master page. There are two approaches to touching this property. The first is to use the Master property of the System.Web.UI.Page class, which returns a MasterPage reference. In order to get to the Footer property, though, we would have to cast the reference to our derived master page type, like the following code.
CType(Master, otherMasterPage).FooterText = "New Footer Text"


A second approach, if you know the exact master page file your page will be using at runtime, is to let the ASP.NET page parser generate a strongly typed Master property by adding an @ MasterType directive to your ASPX file, as shown below.
<%@ MasterType VirtualPath="~/myMasterPage.master" %>


The MasterType directive will instruct the runtime to add a new Master property to code-generated file for the page. The new property will return a reference matching the MasterType. With a MasterType directive in place for our web form, we don't need a cast.

Master Pages Events

Another master page twist that catches developers off guard is the order of the page lifecycle events. Let’s say we write the following code in our web form:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Response.Write("Hello from Page_Load in default.aspx ")
End Sub


.. and the following code in our master page:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Response.Write("Hello from Page_Load in Master1.master")
End Sub


Pop quiz: which Response.Write will appear in the output first?
Hint: most ASP.NET events are raised starting at the top of the control tree and working downward.
In this case, “Hello from Page_Load in default.aspx” will appear before “Hello from Page_Load in Master1.master”, because the content page’s Load event fires before the master page’s Load event.

Let’s set up another quiz using the following code in our content page.

Protected Sub Page_Init(ByVal sender As Object,ByVal e As System.EventArgs)
Response.Write("Hello from Page_Init in default.aspx")
End Sub


... and the following code in our master page.

Protected Sub Page_Init(ByVal sender As Object,ByVal e As System.EventArgs)
Response.Write("Hello from Page_Init in Master1.master")
End Sub


Pop quiz: which Init event will fire first?

Earlier we said most ASP.NET events work their way down the tree of controls. The truth is all lifecycle events (Load, PreRender, etc.) work in this fashion except the Init event. The initialization event works from the inside out. Since the master page is inside the content page, the master page’s Init event handler will fire before the content page’s Init event handler.

Obviously, problems will occur if the content page’s Load event handler depends on the master page's Load event to finish some work or initialize a reference. If you find yourself with this problem, or are worried about the order of events when a master page is involved, you might be too tightly coupled to the master page. Consider our earlier approach of using a custom event when when something interesting happens in the master page, and let the content page subscribe to the event and take action. This approach achieves greater flexibility.

Master Pages

Master pages in ASP.NET are the key to building a professional web application with a consistent, easy to maintain layout.

A professional web site will have a standardized look across all pages. For example, one popular layout type places a navigation menu on the left side of the page, a copyright on the bottom, and content in the middle. It can be difficult to maintain a standard look if you must always put the common pieces in place with every web form you build. In ASP.NET 2.0, master pages will make the job easier. You’ll only need to write the common pieces once - in the master page. A master page can serve as a template for one or more web forms. Each ASPX web form only needs to define the content unique to itself, and this content will plug into specified areas of the master page layout.

Example Master Pages:

To add a master page to a web project, right-click your web project in the Solution Explorer window, select Add New Item, and select the Master Page item type from the Add New Item dialog. The listing below shows a sample master page in source view.


<%@ Master Language="VB" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>


A master page looks very similar to an ASPX file, except a master page will have a .master file extension instead of a .aspx extension, and uses an @ Master directive instead of an @ Page directive at the top. Master pages will define the <html>, <head>, <body> , and <form> tags. A new control, the ContentPlaceHolder control also appears in our master page. You can have one or more ContentPlaceHolder controls in a master page. ContentPlaceHolder controls are where we want our ASPX web forms to place their content.
Let’s also write a simple web form to use our master page.


<%@ Page Language="VB" MasterPageFile="~/Master1.master"
AutoEventWireup="true" Title="Untitled Page" %>
<asp:Content ID="Content1" Runat="Server"
ContentPlaceHolderID="ContentPlaceHolder1" >
<asp:Label ID="Label1" runat="server" Text="Hello, World"/>
</asp:Content>



Just like any ASPX form, our master page can contain code in a <script> block, or in a code-behind file, and can respond to page lifecycle events. The MasterPage class (from the System.Web.UI namespace) derives from UserControl and will have all of the usual events: Init, Load, PreRender, etc.

The web form contains a single Content control, which in turn is the proud parent of a Label. At this point, the page and master page are two separate objects, each with their own children. When it comes time for the master page to do its job, the master page replaces the page’s children with itself.

The master page’s next step is to look for Content controls in the controls formerly associated with the page. When the master page finds a Content control that matches a ContentPlaceHolder, it moves the controls into the matching ContentPlaceHolder. In our simple setup, the master page will find a match for ContentPlaceHolder1, and copy over the Label.

All of this work occurs after the content page’s PreInit event, but before the content page’s Init event. During this brief slice of time, the master page is deserving of its name. The master page is in control - giving orders and rearranging controls. However, by the time the Init event fires the master page becomes just another child control inside the page. In fact, the MasterPage class derives from the UserControl class.

Of Headers and Meta tags

The master page must define <head>,meaning the master page will include the <title> tag, among others. Since the master page does not know the title of the content page that will plug in, it simply sets the title to “untitled”.
Since a content page cannot contain any markup outside of Content controls, there is no way for a content page to use a title tag, but there is now a Title attribute in the @ Page directive. There is also a Title property on the page itself.
For other elements that end up in the header, the Page class now exposes a Header property of type HtmlHead. You can use the HtmlHead reference to modify style sheet settings and add HtmlMeta objects as needed.

Conclusions

Master pages provide a key component to any web application, namely the ability to organize a consistent layout into reusable templates. These master page templates offer full designer support and programmatic interfaces to meet the demands of most applications.

Saturday, August 8, 2009

The extern modifier C# Reference

The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when using Interop services to call into unmanaged code; in this case, the method must also be declared as static, as shown in the following example:

[DllImport("avifil32.dll")]
private static extern void AVIFileInit();


It is an error to use the abstract (C# Reference) and extern modifiers together to modify the same member. Using the extern modifier means that the method is implemented outside the C# code, while using the abstract modifier means that the method implementation is not provided in the class.

Example

In this example, the program receives a string from the user and displays it inside a message box. The program uses the MessageBox method imported from the User32.dll library.

using System;
using System.Runtime.InteropServices;
class MainClass
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);

static int Main()
{
string myString;
Console.Write("Enter your message: ");
myString = Console.ReadLine();
return MessageBox(0, myString, "My Message Box", 0);
}
}


This example creates a DLL from a C program that is invoked from within the C# program in the next example.

// cmdll.c
// compile with: /LD
int __declspec(dllexport) SampleMethod(int i)
{
return i*10;
}


This example uses two files, CM.cs and Cmdll.c, to demonstrate extern. The C file is the external DLL created in Example 2 that is invoked from within the C# program.

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
[DllImport("Cmdll.dll")]
public static extern int SampleMethod(int x);

static void Main()
{
Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5));
}
}


Output

SampleMethod() returns 50.


Remarks

To build the project:

* Compile Cmdll.c to a DLL using the Visual C++ command line:

cl /LD Cmdll.c

* Compile CM.cs using the command line:

csc CM.cs

This will create the executable file CM.exe. When you run this program, SampleMethod will pass the value 5 to the DLL file, which returns the value multiplied by 10.

Note
The extern keyword also can define an external assembly alias, making it possible to reference different versions of the same component from within a single assembly. For more information, see extern alias (C# Reference).

The extern keyword is more limited in use than in C++. To compare with the C++ keyword, see Using extern to Specify Linkage in the C++ Language Reference.

IIf Function

Returns one of two objects, depending on the evaluation of an expression.

Public Function IIf( _
ByVal Expression As Boolean, _
ByVal TruePart As Object, _
ByVal FalsePart As Object _
) As Object


Parameters

Expression

Required. Boolean. The expression you want to evaluate.

TruePart

Required. Object. Returned if Expression evaluates to True.

FalsePart

Required. Object. Returned if Expression evaluates to False.


Remarks

The IIf function provides a counterpart for the ternary Conditional Operator: ? : in Visual C++.

Example

This example uses the IIf function to evaluate the testMe parameter of the checkIt procedure and returns the word "Large" if the amount is greater than 1000; otherwise, it returns the word "Small".
Visual Basic

Function checkIt(ByVal testMe As Integer) As String
Return CStr(IIf(testMe > 1000, "Large", "Small"))
End Function


Note that if Option Strict is On, you must use the CStr keyword to explicitly convert the return from Object to String.

?: Operator

The conditional operator (?:) returns one of two values depending on the value of a Boolean expression. The conditional operator is of the form.
condition ? first_expression : second_expression;


If condition is true, first expression is evaluated and becomes the result; if false, the second expression is evaluated and becomes the result. Only one of two expressions is ever evaluated.

Calculations that might otherwise require an if-else construction can be expressed more concisely and elegantly with the conditional operator. For example, to avoid a division by zero in the calculation of the sin function you could write either

if(x != 0.0) s = Math.Sin(x)/x; else s = 1.0;


or, using the conditional operator,

s = x != 0.0 ? Math.Sin(x)/x : 1.0;


The conditional operator is right-associative, so an expression of the form

a ? b : c ? d : e


is evaluated as

a ? b : (c ? d : e)


not

(a ? b : c) ? d : e


The conditional operator cannot be overloaded.

Example

// cs_operator_conditional.cs
using System;
class MainClass
{
static double sinc(double x)
{
return x != 0.0 ? Math.Sin(x)/x : 1.0;
}

static void Main()
{
Console.WriteLine(sinc(0.2));
Console.WriteLine(sinc(0.1));
Console.WriteLine(sinc(0.0));
}
}



Output

0.993346653975306
0.998334166468282
1