Send a Completed Form Email Without a StringBuilder

Have you ever had to create a large web form for users to fill out and then receive an email copy after its submitted? That can be tedious work. The first few times I did it, I used a StringBuilder to build the email HTML one control at a time. Later, I viewed the HTML output of the page and replaced all input controls with spans, and then put that HTML in a StringBuilder. Either of these methods work, but it gets real annoying when I later have to add a field or two to the form and therefore to the email HTML.

I knew there had to be a way to do this programmatically without copying and pasting into a StringBuilder. Well, there is. Here’s a rather common code snippet that does just this:

public static string GetRenderedHtml(this Control control)
{
    StringBuilder sbHtml = new StringBuilder();
    using (StringWriter stringWriter = new StringWriter(sbHtml))
    using (HtmlTextWriter textWriter = new HtmlTextWriter(stringWriter))
    {
        control.RenderControl(textWriter);
    }

    return sbHtml.ToString();
}

This is great! Let’s try it out on this simple example:

<div id="divForm" runat="server">
    <fieldset class="inputArea">
        <legend>Contact</legend>
        <asp:Label runat="server" AssociatedControlID="txtName">
        Name</asp:Label>
        <asp:TextBox runat="server" ID="txtName" />
        <asp:Label runat="server" AssociatedControlID="txtEmail">
        Email</asp:Label>
        <asp:TextBox runat="server" ID="txtEmail" />
        <asp:Label runat="server" AssociatedControlID="txtWebsite">
        Website</asp:Label>
        <asp:TextBox runat="server" ID="txtWebsite" />
        <asp:Label runat="server" AssociatedControlID="txtComment">
        Comment</asp:Label>
        <asp:TextBox runat="server" ID="txtComment" TextMode="MultiLine" Rows="4" cols="30" />
        <asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" />
    </fieldset>
</div>

protected void btnSubmit_Click(object sender, EventArgs e)
{
    txtRenderedHtml.Text = divForm.GetRenderedHtml();
}

Here is what we get:

Control 'txtName' of type 'TextBox' must be placed inside a form tag with runat=server.

So how do you get around that? Well, lets think about this. I’m trying to capture a form and render it as HTML to be included in an email, so I don’t want any TextBoxes. Lets replace the TextBoxes (and any other editable controls) with Labels and try again.

public static void ReplaceEditableControls(this Control control)
{
    // don't bother with controls that aren't visible
    if (!control.Visible)
    {
        return;
    }

    ListControl listControl = control as ListControl;
    IButtonControl buttonControl = control as IButtonControl;
    IValidator validator = control as IValidator;
    IEditableTextControl textControl = control as IEditableTextControl;
    UpdatePanel updatePanel = control as UpdatePanel;

    if (validator != null || buttonControl != null)
    {
        control.Visible = false;
    }
    else if (listControl != null && listControl.SelectedItem != null)
    {
        Label label = new Label {Text = listControl.SelectedItem.Text, CssClass = "text"};
        Replace(listControl, label);
    }
    else if (textControl != null)
    {
        Label label = new Label {Text = textControl.Text, CssClass = "text"};
        Replace((Control) textControl, label);
    }
    else if (updatePanel != null)
    {
        // replace the update panel with a place holder
        PlaceHolder holder = new PlaceHolder();
        Control[] panelControls = new Control[updatePanel.ContentTemplateContainer.Controls.Count];
        updatePanel.ContentTemplateContainer.Controls.CopyTo(panelControls, 0);

        foreach (Control panelControl in panelControls)
        {
            holder.Controls.Add(panelControl);
        }

        ReplaceEditableControls(holder);

        Replace(updatePanel, holder);
    }
    else if (control.HasControls())
    {
        Control[] controlsCopy = new Control[control.Controls.Count];
        control.Controls.CopyTo(controlsCopy, 0);

        foreach (Control controlCopy in controlsCopy)
        {
            ReplaceEditableControls(controlCopy);
        }
    }
}

There are a few things to note here.

  • The check for ListControl is before IEditableTextControl because of the way it implements IEditableTextControl. ListControl.Text returns ListControl.SelectedValue, but ListControl.SelectedItem.Text makes more sense.

  • UpdatePanels are a special case because of ContentTemplate. They are replaced with a PlaceHolder and then the method is recursively called on each child control.

  • Finally, if the control has a control collection of its own, a recursive call is made on each child control.

  • Notice that the control collection is copied to an array before making the recursive call. This is because the control collection is modified and you can’t modify a collection while iterating it. Well, you can, but you will have problems.

Now we can change the button handler to:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    divForm.ReplaceEditableControls();
}
Which will render the following HTML:
<div id="divForm">
    <fieldset class="inputArea">
        <legend>Contact</legend>
        <label for="txtName">
        Name</label>
        <span id="txtName" class="text">John Rummell</span>
        <label for="txtEmail">
        Email</label>
        <span id="txtEmail" class="text">jrummell@example.com</span>
        <label for="txtWebsite">
        Website</label>
        <span id="txtWebsite" class="text">john.rummell.info</span>
        <label for="txtComment">
        Comment</label>
        <span id="txtComment" class="text">Check out this new post!</span>
    </fieldset>
</div>

To capture this as a string, just add a call to GetRenderedHtml:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    divForm.ReplaceEditableControls();
    string html = divForm.GetRenderedHtml();
    //TODO: send email
}

(The form style is a slight variation of Janko’s tutorial)

29. June 2009 23:09 by jrummell | Comments (1) | Permalink

jQuery/ASP.Net AJAX 1.0/3.5 gotcha

Update: If you are curious as to why MS added the .d attribute, find out why at Encosia.

I was very frustrated the other day trying to figure out why a jQuery ajax call worked on my dev box but not on the server.  It looked something like this:

json(_serviceUrl, "{}", true,
    function(result) { fillSelect($("#ddlDepartment")[0], result.d); },
    function(ajax) { /* handle error */ });
    
// calls a json web service
function json(url, data, async, onSuccess, onFailed)
{
    $.ajax({
        async: async,
        type: "POST",
        url: url,
        data: data,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: onSuccess,
        error: onFailed
    });
}

(The code inside the json function is straight from Dave Ward's post on Using jQuery to Consume ASP.NET JSON Web Services. Dave's blog is an excellent resource full of information on jQuery, AJAX, ASP.Net and how to make them play nice together.)

I figured out the problem was result.d; on the server it was null, but on my machine it was a ListItem[], as expected. It turns out that on my machine, the web service at _serviceUrl was compiled against .Net 3.5. while on the server it was compiled against .Net 2.0 with ASP.NET AJAX Extensions 1.0. In order to get it working on the server, I had to change result.d to result. Apparently they changed a few things in System.Web.Extensions v3.5. Unfortunately, I'm unable to install .Net 3.5 on the server. So I came up with this helper function to get things working in both 1.0 and 3.5:

// gets the ajaxResult. Returns ajaxResult.d is if it is not null, else ajaxResult.
// System.Web.Extensions v3.5 web services will result in ajaxResult.d while v1.0 will be ajaxResult.
function getResult(ajaxResult)
{
    return ajaxResult.d == null ? ajaxResult : ajaxResult.d;
}

So now after replacing result with getResult(result), the json call looks like this:

json(_serviceUrl, "{}", true,
    function(result) { fillSelect($("#ddlDepartment")[0], getResult(result)); },
    function(ajax) { /* handle error */ });

Hopefully this will save someone out there some frustration!

18. December 2008 22:39 by jrummell | Comments (4) | Permalink

WebIconProvider

How do you handle sharing icon sets across your web projects?  I started out with an icon folder in each project.  Keeping folders up to date was a bit of a pain - having to remember to update each change across all projects.  Eventually I moved the icons into a class library and compiled them as web resources.  This was great because I could access them from any web project.  But then I wanted to use a different icon set for one project.  I could have just replaced the library icons with the new set, but I didn't want the new set for all of web projects.  All of my projects use the same kinds of icons, e.g. save, edit, delete, new, comment, etc.  So then it hit me, "What if I had an icon set interface that could be used to plug in any number of different icon sets?"

 

Provider Model

The Provider Model seemed like the logical approach.  I had already worked with it when creating custom Membership and Role providers, as well as a SiteMap provider.  The great thing about the provider model is that you can swap providers without recompiling and even do it at runtime.  Here's a class diagram of my provider implementation.

Provider Classes

Following the provider model, I have the following four classes:

WebIconProvider is the abstract icon ProviderBase class that does most of the heavy lifting.  The most important method here is GetImageUrl(WebIcon icon). This an abstract method that returns the url of an image based on the given WebIcon enum value.  WebIcon contains all of the required image types (save, edit, delete, new, comment, etc).

WebIconProviderCollection is a strongly typed collection of WebIconProviders.

WebIconService is a static class that gives access to the providers and a few methods that perform operations using the default provider.

WebIconSection is the ConfigurationSection implementation that contains the configuration settings required for WebIconProviders.

 

WebIconProvider

Now the next step is to implement WebIconProvider.  After implementing it with a few different icon sets, I realized I could refactor out two more abstract classes.

WebIconProvider Classes 

FileWebIconProvider is a virtual path based implementation that provides an ImagePath property that is set in the provider's configuration.  The implementing class must provide the filename of each WebIcon image when it implements WebIconProvider.GetImageUrl(WebIcon icon).

ResourceWebIconProvider is a WebResource implementation that provides a static GetImageUrl(Type type, string resourceName) method that handles retrieving the web resource url.  The implementing class must provide an implementation of IIconResources in it's constructor.  IIconResources is an interface that defines a web resource url for each WebIcon enum value.  ResourceWebIconProvider also provides an implementation of WebIconProvider.GetImageUrl(WebIcon icon) that maps WebIcon values to the appropriate IIconResources property.

 

ResourceWebIconProvider

FileWebIconProvider is pretty much self explanatory.  Creating a new ResourceWebIconProvider icon set is also fairly simple.  First you need to pick out your icons! A few free sets that I like are Silk Icons, Sancons, and ASP.Net Icons. Then you'll need to add them to a class library project and set their build action to Embedded Resource.  The next step is to implement IIconResources.

    /// <summary>
    /// The SilkIcon implementation of <see cref="IIconResources"/>.
    /// </summary>
    internal struct SilkIconResources : IIconResources
    {
        private const string __baseResourcePath = "SilkIcons.Icons.";
        internal const string _Add = __baseResourcePath + "add.png";
        internal const string _Calendar = __baseResourcePath + "calendar.png";
        internal const string _Check = __baseResourcePath + "tick.png";
        
        /* snip */
 
        private static readonly SilkIconResources _default = new SilkIconResources();
 
        /// <summary>
        /// Gets the default instance.
        /// </summary>
        /// <value>The default instance.</value>
        public static IIconResources Default
        {
            get { return _default; }
        }
 
        #region IIconResources Members
 
        public string Add
        {
            get { return _Add; }
        }
        
        public string Calendar
        {
            get { return _Calendar; }
        }
 
        public string Check
        {
            get { return _Check; }
        }
        
        /* snip */
 
        #endregion
    }

The next step is adding the WebResourceAttributes.  ContentType is a struct with string constants that contain the valid web resource content types, such as "image/png".

[assembly: WebResource(SilkIconResources._Edit, ContentType.Png)]
[assembly: WebResource(SilkIconResources._Delete, ContentType.Png)]
[assembly: WebResource(SilkIconResources._Add, ContentType.Png)]
[assembly: WebResource(SilkIconResources._Calendar, ContentType.Png)]
        /* snip */

The final step is implementing ResourceWebIconProvider, which is only a few lines of code.

    /// <summary>
    /// A <see cref="WebIconProvider"/> for Silk Icons (http://www.famfamfam.com/lab/icons/silk/).
    /// </summary>
    public class SilkIconProvider : ResourceWebIconProvider
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SilkIconProvider"/> class.
        /// </summary>
        public SilkIconProvider()
            : base(SilkIconResources.Default, "Mark James", "http://www.famfamfam.com/lab/icons/silk/")
        {
        }
    }

WebControls

I also created a few WebControls to make displaying the icons easier.

Control Classes

WebIconImage is a control that inherits Image and adds a couple WebIconProvider related properties. You can use it just like an <asp:Image> except that you can specify the icon you want to display and it uses a WebIconProvider to determine the url.  The following markup would display the default WebIconProvider's help image.

<webicons:WebIconImage id="WebIconImage1" icon="Help" runat="server" />

 

WebIconCredit is control that displays the name of the icon set creator and a link to the creator's web site.  The name and link come from the configuration settings.  This control's markup is very simple.

<webIcons:WebIconCredit ID="WebIconCredit1" runat="server" />

 

Configuration

The configuration looks a lot like any provider configuration.

    <webIcons defaultProvider="Silk">
        <providers>
            <add name="Sanscons"
                 type="Sanscons.SansconsIconProvider, Sanscons"
                 cssClass="icon"/>
            <add name="Silk"
                 type="SilkIcons.SilkIconProvider, SilkIcons"/>
        </providers>
    </webIcons>

 

Source Code

The following zip file contains four WebIconProvider implementations and a test web site.

WebIcons.zip (2.18 mb)

21. August 2008 22:11 by jrummell | Comments (2) | Permalink

My version of the MessageBox control

Update: I fixed a couple issues and updated the zip file below.

  • The close button's client side onclick event wasn't getting the correct client id when used inside a Master page.  I moved the onclick addition to the Load event to correct it.
  • The message would not display when used inside an UpdatePanel.  The Page.ClientScript.RegisterStartupScript method only works for synchronous (non-AJAX) post backs.  The control now uses the ScriptManager.RegisterStartupScript method for async post backs.

Last month Janko posted an excellent article about creating standard website message boxes.  He concluded it with this:

I am aware that this code isn't perfect, although it did a great job for me on several projects. Did you ever need or do something similar? Do you have any other ideas how this could be implemented? Share it!

I took that as a challenge Cool.  I loved his idea but the implementation didn't fit my needs 100%.  Since I maintain multiple web projects I try to use custom web controls over user controls. I find it easier to reference a web control library than keeping track of .ascx files.  In addition, I found that if a message was displayed and the user clicks the close button and then does something else on the page that initiates a postback, the message would be visible again.

Creating the Custom WebControl

I used CompositeControl as my base class and started by duplicating the functionality of Janko's user control.  The first difference in the code is the CreateChildControls method.

   87         protected override void CreateChildControls()

   88         {

   89             base.CreateChildControls();

   90 

   91             // the wrapper div

   92             Style[HtmlTextWriterStyle.Display] = "none";

   93             CssClass = "container";

   94 

   95             // the message div

   96             _pnlMessageBox = new Panel();

   97             _pnlMessageBox.ID = "pnlMessageBox";

   98             Controls.Add(_pnlMessageBox);

   99 

  100             // the close button

  101             _hlClose = new HyperLink();

  102             _hlClose.ID = "hlClose";

  103             _hlClose.ToolTip = "Close";

  104             _hlClose.CssClass = "close";

  105             // add the onclick event

  106             string onclick = String.Format("document.getElementById('{0}').style.display = 'none';", ClientID);

  107             _hlClose.Attributes.Add("onclick", onclick);

  108             _pnlMessageBox.Controls.Add(_hlClose);

  109 

  110             // the message

  111             _pMessage = new HtmlGenericControl("p");

  112             _pnlMessageBox.Controls.Add(_pMessage);

  113 

  114             _litMessage = new Literal();

  115             _litMessage.ID = "litMessage";

  116             _pMessage.Controls.Add(_litMessage);

  117         }

This is where I'm (you guessed it) creating and adding the child controls.  One difference here is Style[HtmlTextWriterStyle.Display] = "none";.  I'll get to that next.  Another difference is I'm not using an image control inside the close hyper link. I modified the css to include a background image for the hyperlink instead.  I did this because I didn't want to worry about setting the close image url in each project in addtion to including the css file and associated images.

Keeping the MessageBox Hidden on PostBack

Instead of using the server side Visible property to show/hide the message I'm using javascript and css.  This can be better or worse.  Better because it allows me to keep the message hidden on post back, and worse because the html bits are sent to the client on every request even if the message is hidden.  In the CreateChildControls method above I'm setting the style display value to 'none'.  This is what hides message.  In the Show method, I'm using a startup script to change the display value to its default - 'block', which shows the message.  This startup script is lost on post back so the message goes back to hiding.

  204             // add a script to display the message on page load

  205             string script = String.Format("document.getElementById('{0}').style.display = 'block';", ClientID);

  206 

  207             Page.ClientScript.RegisterStartupScript(GetType(), ClientID, script, true);

 

I've been using this is production for a few weeks now and its done very well for me, but I also don't claim to write perfect code. If you have found a better way, please let me know!

MessageBoxSite.zip (23.91 kb)

Update: The source now includes a Visual Studio 2005 WebSite with an example page.
9. July 2008 14:46 by jrummell | Comments (15) | Permalink

A SiteMapProvider for Static Web Sites

The new navigation features of ASP.Net 2.0 are pretty cool. If you haven't seen them yet, check out ScottGu's blog for more information.

I've seen a few blog posts on SiteMapProvider implementations for dynamic web sites, but not a whole lot on providers for static web sites. Sure, you could use the default implementation and manually update the web.sitemap xml file, but what about large sites? In my opinion, its not worth the effort.

Here are my requirements for a static SiteMapProvider:

  • Must automagically update whenever pages are added/removed.
  • Must be able to only include specified file types.
  • Must be able to exclude specified directories under the application's virtual directory.

So I went searching and didn't find anything. The closest I found was a macro by K. Scott Allen that generates a web.sitemap file from a web project. A noble effort, but I needed a bit more. So I set off to implement my own provider. Using the SqlSiteMapProvider example as a reference, I had created my own StaticFileSiteMapProvider by lunch time.

The implementation is rather straighforword. It starts at the application path (~/) and recurses each of its sub directories. There is a FileExtensions property that defines the types of files to include (e.g. aspx, html) and there is also a DirExclusions property that defines the directory name patterns to exclude (e.g. bin, App_*). The DefaultDocuments property defines the default document names for a directory (e.g index, default).

Why do I need a DefaultDocuments property? I can answer that with another question. What happens when you've got a directory in your app that doesn't have an index page? Well, the provider will generate a link to that folder, but clicking on it will result in a Directory Listing Denied error (at least I hope you would have your site set up that way). In
BuildSiteMap(SiteMapNode parentNode, string directory), if the current node's directory doesn't have a default document page, then the node's url isn't set, ensuring that its not hyperlinked.

On to the code. I've included the main parts of the class below. For a full listing, use the link at the end of this post.


public override SiteMapNode BuildSiteMap()
{
lock (this)
{
if (isBuilt)
{
return root;
}
string physicalAppPath = HttpContext.Current.Server.MapPath("~/");
BuildSiteMap(null, physicalAppPath);
isBuilt = true;
return root;
}
}
/// <summary>
/// Recursive method to build the site map.
/// </summary>
/// <param name="parentNode">The parent node.</param>
/// <param name="directory">The directory.</param>
private void BuildSiteMap(SiteMapNode parentNode, string directory)
{
// create the current node
string url = GetUrlFromPhysicalPath(directory);
string title = parentNode == null ? "Home" : Path.GetFileName(directory);
SiteMapNode node = new SiteMapNode(this, url, url, title);
// set the root
if (parentNode == null)
{
root = node;
}
// add a node foreach file
string[] files = GetFiles(directory);
foreach (string file in files)
{
url = GetUrlFromPhysicalPath(file);
SiteMapNode fileNode = new SiteMapNode(this, url, url, Path.GetFileNameWithoutExtension(file));
AddNode(fileNode, node);
}
// unset the url if there isn't an index file in the directory
if (!Array.Exists(files, delegate(string match)
{
foreach (string index in DefaultDocuments.Split(','))
{
if (String.Compare(Path.GetFileNameWithoutExtension(match), index.Trim(),
StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
}
return false;
}))
{
// Note: setting node.Url to null doesn't change the value, so I'm setting it to String.Empty, 
// which is its default value
node.Url = String.Empty;
}
// recurse sub directories
string[] directories = GetDirectories(directory);
foreach (string dir in directories)
{
BuildSiteMap(node, dir);
}
// only add the current node if it has children
// Note: node.HasChildren throws an InvalidOperationException, so I'm checking the 
// file and directory arrays instead
if (files.Length > 0  directories.Length > 0)
{
AddNode(node, parentNode);
}
}

web.config settings:

<siteMap defaultProvider="StaticFileSiteMapProvider">
<providers>
<add name="StaticFileSiteMapProvider" type="Providers.StaticFileSiteMapProvider"
fileExtensions="asp, htm"
defaultDocuments="index"
dirExclusions="bin, obj, Properties, App_*, DMS, old" />
</providers>
</siteMap>

StaticSiteMapProvider.cs (11.85 kb)

3. August 2007 20:34 by jrummell | Comments (1) | Permalink

Converting DateTime to String and back

I spent about 20 frustrating minutes the other day wondering why a sql query wasn't selecting the record I wanted. Everything looked right until I stepped through my code the 3rd time. Then I discovered my problem.

In a web form, I allow a user to select a row in a GridView that fires an event to populate a DetailsView using an ObjectDataSource. The select method of the ObjectDataSource takes two parameters, a DateTime and a string. Since the date is coming from the GridView, I was just using Convert.ToDateTime([date cell].ToString()).

I discovered that the DateTime displayed in the GridView was '5/21/2007 8:51:42 AM' while the DateTime in the database was '2007-05-21 08:51:42.153'. They're close, but not exactly the same. It's that missing fraction of a second that made my where clause incorrect.

So then I thought, "How can I successfully convert a DateTime to a string and back?" After a short pause it hit me, "Ticks". No, not the kind of ticks I'm afraid of getting when backpacking in woods, but DateTime.Ticks. I used a HiddenField to store the string representation of the selected DateTime in ticks, and then added an overloaded select method that takes a ticks (long) parameter. In the new method I simply construct a DateTime from the ticks and call the original select method.

So in summary, to convert from DateTime to string and back, use ticks.
21. May 2007 11:32 by jrummell | Comments (0) | Permalink

Using ASP.Net to open a new browser window - Part II, the web control

This a follow up to my previous post, Using ASP.Net to open a new browser window - Part I. There I used a static helper class to register a javascript function to open a new browser window. I've scratched the static class and replaced it with a BrowserWindow class and a PopUpWindow WebControl. BrowserWindow simply encapsulates all of the parameters passed to RegisterOpenWindowScript(), and PopUpWindow registers the javascript function and the call to the function.

Here's an example:



<cc1:PopUpWindow ID="PopUpWindow1" runat="server" OpenOnLoad="false" />
<asp:Button ID="Button1" runat="server" Text="Open Window" OnClick="Button1_Click" />



protected void Page_Load(object sender, EventArgs e)
{
BrowserWindow window = new BrowserWindow(
"http://john.rummell.info/blog", 800, 600);
window.Resizable = true;
window.Scrollbars = true;
PopUpWindow1.BrowserWindow = window;
}
protected void Button1_Click(object sender, EventArgs e)
{
PopUpWindow1.OpenWindow();
}



PopUpWindow exposes a few of BrowserWindow's properties: Width, Height, and Url. For more options, create a BrowserWindow object and set PopUpWindow's BroswerWindow property with it, as shown in Page_Load. You can use the OpenWindow() method of PopUpWindow to open the window as shown in Button1_Click, or you can set OpenOnLoad to true to have it open when the page loads.

BrowserWindow.cs (7.56 kb), PopUpWindow.cs (6.91 kb)

 

20. February 2007 13:24 by jrummell | Comments (1) | Permalink

Using ASP.Net to open a new browser window - Part I

I recently needed to add a 'pop-up' window to a website. Now I'm not a fan of javascript, never have been. I like my code to be type safe and compile. So I came up with a C# helper class to do the dirty work for me. I must give credit to where I found the idea. I saw something like this in Chapter 4 of Developing Web Applications with Microsoft VB .Net and VC# .Net by Jeff Webb and MS Corp. In this book they create BrowserWindow class and use it inside some javascript. I've take a different approach, so that I can avoid having to write the javascript in the future.

I created a static helper class that contains the following method. I also provided some methods that overload this, but you get the idea.


public static void RegisterOpenWindowScript(
Page page, string key, string url,
WindowName name, int width, int height,
int left, int top,
bool location, bool menubar, bool resizable,
bool scrollbars, bool status, bool titlebar)
{
if (!page.ClientScript.IsClientScriptBlockRegistered(
typeof(OpenWindowHelper), key))
{
string script = String.Format(@"
function {12}()
{{
var win = window.open('{0}', '{1}',
'width={2},height={3},left={4},top={5},location={6},
menubar={7},resizable={8},scrollbars={9},
status={10},titlebar={11}');
win.focus();
}}
", url, name, width, height, left, top,
GetInt(location), GetInt(menubar),
GetInt(resizable), GetInt(scrollbars), GetInt(status),                    
GetInt(titlebar), openFunctionName);
page.ClientScript.RegisterClientScriptBlock(
typeof(OpenWindowHelper), key, script, true);
}
}


WindowName is an enum that defines the possible window names: _blank, _parent, _self, _top. GetInt() simply returns 1 if true and 0 if false.

As I'm writing this I'm realizing that it would be a cool idea to merge this static class with the BrowserWindow class. You could define a BrowserWindow object and perform the Open() operation to open the window. Hmm ... I'm seeing a follow up post in the near future.


OpenWindowHelper.cs (5.24 kb)

19. February 2007 23:15 by jrummell | Comments (0) | Permalink

NUnint C# Templates for Visual Studio 2005

I recently upgraded to Visual Studio 2005. I wrote a few classes and began the testing process. I added a new class library project and then added a reference to nunit.framework, added a new testing class and typed out all of the NUnint attributes .... and then I stopped. There has to be a faster way to set up a test class. A quick Google search returned a few results for VB templates, but no C# templates =/.

So I got out my thin VS 2005 manual and decided to make my own template. It was much easier than expected, since I had made previous templates in VS 2003. And now I share them with you, my fellow readers.

NUnit Class Library
NUnit Class

Just drop the NUnit Class Library in your "My Documents\Visual Studio 2005\Templates\ProjectTemplates" folder and the NUnit Class in your "My Documents\Visual Studio 2005\Templates\ItemTemplates" folder.
30. December 2006 15:08 by jrummell | Comments (0) | Permalink

About the author

John is a .Net Web Developer for a manufacturing company in Ohio. In his free time he enjoys web development, the outdoors, and spending time with his wife.

Page List

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2008