By Scott Rosa
Any developer who has had the dubious task of developing a Web site utilizing frames knows it can be an uphill battle. Many argue that frames should be avoided at all costs, while others realize how they can benefit a Web site’s user interface. When my team had to develop a Web site that displayed pdf’s in a management dashboard, we knew frames were the way to go. Unfortunately, we were not sure how to best work with frames in ASP.NET. When I used my list of normal search engines/newsgroups, I could not find much in the way of useful information. Here is one reply I got when asking how to best work with frames in .NET:
Ok, My list of suggestion for Frames.
1. Frames are Evil
2. The Devil created Frames
3. If you are having a problem related to the Target, refer to item 1
4. If you are trying to refresh data in a particular frame, refer to 1
I think you get the idea. The fact of the matter is frames can provide an aesthetically pleasing site, which in many situations is more user-friendly. This of course is only the case if you avoid the pitfalls of frames, such as multiple scroll bars and too many frame windows. I will not address these pitfalls in this article because there is certainly an over-abundance of information/opinions on that subject. In my opinion frames have gotten a bad reputation from users because so many developers misused them. On the other hand they have a well deserved reputation from the developer side because in the past they were very difficult to work with. The purpose of this article is to show you that this is no longer the case. I will also present one alternative to using frames, called Smart Navigation.
In the end we solved the problem of working with frames by utilizing a mix of JavaScript code and the Attributes property of .NET Web Forms. This is essentially the key behind working with frames in .NET.
System Requirements
Netscape 4.0 or later or IE 5.0 or later
Visual Studio.NET
Windows 2000 with IIS5
Web Site Set-Up
A pdf_files directory must be created under the Web site root with write access
Frames and Frame Alternatives
Although this article will be used to address the usage of frames in .NET, it is important to talk about the use of frames and some alternatives. My team has developed the majority of our sites without frames because they did not fit into a model in which they were required. We use frames when we need to present the users with a control or set of controls that maintain a certain state, while another part of the page needs to load a file in or some other type of control(s). The MSDN site illustrates a good use of frames in its library section: http://msdn.microsoft.com/library/default.asp
In the past we have also used frames to control screen refresh. On an ASP 2.0 or 3.0 page, the entire page would refresh any time you needed to perform a server side event. One alternative to solving the screen refresh issue in ASP.NET is Smart Navigation. This tag can be set at page level through page properties, or at site level through web.config. With this turned on, only the controls within the form tag will be refreshed. So if you have other images, headers, etc., the users will not get screen flicker. It is important to note that behind the scenes ASP.NET is using Iframes, so this will only work on IE5.0 and greater browsers. The use of inline frames allows for this targeted refresh because each frame is treated independently. The following link will provide you with more information on Iframes and some issues related to them: http://www.cs.tut.fi/~jkorpela/html/iframe.html
To see how Smart Navigation can be used, let’s take a look at an example.
<%@ Page Language=”vb” AutoEventWireup=”false”
Codebehind=”smart_tag.aspx.vb” Inherits=”asptoday_frames.smart_tag”
smartNavigation=”True”%>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
<HTML>
<HEAD>
<title>smart_tag</title><meta content=”Microsoft Visual Studio.NET 7.0″
name=”GENERATOR”>
<meta content=”Visual Basic 7.0″ name=”CODE_LANGUAGE”>
<meta content=”JavaScript” name=”vs_defaultClientScript”>
<meta content=”http://schemas.microsoft.com/intellisense/ie5″
name=”vs_targetSchema”>
</HEAD>
<body MS_POSITIONING=”GridLayout”><form id=”frmImage” style=”Z-INDEX: 101; LEFT: 6px; POSITION:
absolute; TOP: 18px” runat=”server”>
<asp:button id=”btnRefresh” style=”Z-INDEX: 104; LEFT: 19px; POSITION:
absolute; TOP: 13px” runat=”server” Text=”Refresh”></asp:button><asp:label id=”lblRefresh”
style=”Z-INDEX: 105; LEFT: 96px; POSITION: absolute; TOP: 18px”
runat=”server”></asp:label></form>
<IMG style=”Z-INDEX: 103; LEFT: 27px; WIDTH: 507px; POSITION:
absolute; TOP: 87px; HEIGHT: 259px” height=”259″ alt=”” src=”test.GIF”
width=”507″>
<IMG style=”Z-INDEX: 102; LEFT: 16px; WIDTH: 507px; POSITION:
absolute; TOP: 78px; HEIGHT: 259px” height=”259″ alt=”” src=”test.GIF”
width=”507″>
</body></HTML>
Code Behind
Public Class smart_tag
Inherits System.Web.UI.Page
Protected WithEvents btnRefresh As System.Web.UI.WebControls.Button
Protected WithEvents lblRefresh As System.Web.UI.WebControls.LabelPrivate Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Me.lblRefresh.Text = “”
End SubPrivate Sub btnRefresh_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnRefresh.Click
Me.lblRefresh.Text = “Page Refreshed”
End Sub
End Class
At the top of the page we are setting smartNavigation=”True” so that the only the lblRefresh and btnRefresh make a roundtrip to the server. I have added two images at the bottom of the page to illustrate the difference that smart navigation makes. If you set smartNavigation = False, you will notice some flashing of the images, even when running local to the Web server.
IFrames can be useful in forcing refresh of only part of the screen, but it cannot fully replace the functionality that comes with working with regular frames. The biggest drawback with Iframes is that you cannot implement two separate form tags in the same page, which may be required for some sites.
Questions Regarding Frames
The main problem that most people have when working with frames is cross-frame communication. There are several consistent questions I see on frames including:
This issue is compounded when you start dealing with pop-up windows.
The Solution
Solving the above described problems has become much easier with some basic knowledge of the windows and frames properties in javascript and the ASP.NET Attributes property. In this article I am going to break my code up into several sections, starting with a very easy to follow hello world style example. After that I will address working with pop-ups, adding a very useful HTML control into the mix.
The Code
Goal #1: Pass data between left and right frames
UI Design
Before I get into the code, it is important that you receive the visual of the two frames that we will be working with:
Figure 1
CODE
For the purpose of brevity, I will exclude code automatically generated by Web forms.
To start we have the simple default.htm page that will contain our two aspx pages.
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
<html><head>
<title>How to Work with frames in .Net</title>
<meta name=”vs_defaultClientScript” content=”JavaScript”>
<meta name=”vs_targetSchema”
content=”http://schemas.microsoft.com/intellisense/ie5″>
<meta name=”GENERATOR” content=”Microsoft Visual Studio.NET
7.0″><meta name=”ProgId” content=”VisualStudio.HTML”>
<meta name=”Originator” content=”Microsoft Visual Studio.NET
7.0″>
</head>
<frameset border=”1″ frameborder=”1″ framespacing=”0″
cols=”30%,70%”><frame name=”left frame” src=”leftframe.aspx”/>
<frame name=”right frame” src=”rightframe.aspx”/></frameset>
</html>
Next is the left frame page, which will contain a mix of javascript and VB.NET code. The mix of this code will enable us to pass a text string from a textbox on the left frame to a textbox in the right frame.
Public Class leftframe
Inherits System.Web.UI.Page
Protected WithEvents btnTright As System.Web.UI.WebControls.Button
Protected WithEvents btnPop As System.Web.UI.WebControls.Button
Protected WithEvents txtTright As System.Web.UI.WebControls.TextBoxPrivate Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
‘enclose the add attributes in the not is post back block, so they
‘ are called to be added only once.
If Not IsPostBack Then
btnTright.Attributes.Add(“onclick”,
“javascript:tranRight(txtTransferRight.value)”)
btnPop.Attributes.Add(“onclick”, “javascript:openWindow()”)
‘remove file name from session
Session.Remove(“fileName”)
End IfEnd Sub
End Class
The key to working with frames is the Attributes property along with its Add method, which allows us to dynamically insert calls to javascript functions, passing in our server side control’s data. The Attributes property allows you to declare any event handler that is associated with a specific Web control. Any of the attributes that you add to the controls collection will be rendered at run time. For a text box you could add a call to the textchanged event. Note, if you do make reference to an unsupported event, it will be ignored by the browser. For now you can ignore the session remove, which will be needed for a later part of this article.
Here is the HTML code that exists for the left frame page.
<%@ Page Language=”vb” AutoEventWireup=”false”
Codebehind=”leftframe.aspx.vb” Inherits=”asptoday_frames.leftframe”%>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
<HTML>
<HEAD>
<title>leftframe</title>
<meta content=”Microsoft Visual Studio.NET 7.0″
name=”GENERATOR”><meta content=”Visual Basic 7.0″ name=”CODE_LANGUAGE”>
<meta content=”JavaScript” name=”vs_defaultClientScript”>
<meta content=”http://schemas.microsoft.com/intellisense/ie5″
name=”vs_targetSchema”>
</HEAD>
<body MS_POSITIONING=”GridLayout”>
<form id=”frmTransterRight” method=”post” runat=”server”><asp:button id=”btnTransferRight” style=”Z-INDEX: 101; LEFT: 23px;
POSITION: absolute; TOP: 100px” runat=”server” Text=”Send to right frame”
Width=”131px”></asp:button><asp:textbox
id=”txtTransferRight” style=”Z-INDEX: 102; LEFT: 26px; POSITION: absolute; TOP:
64px” runat=”server” Width=”170px” Height=”24px”>Text to go to right
frame</asp:textbox><asp:button id=”btnPop” style=”Z-INDEX: 103;
LEFT: 24px; POSITION: absolute; TOP: 136px” runat=”server” Text=”Open Pop-Up”
Width=”129px”></asp:button></form>
<script language=”javascript”>//this function takes a value (ltext) and transmits that to the left hand frame
function tranRight(ltext)
{
parent.frames(1).document.forms(“frmReceive”).item(“txtReceive”).value =
ltext;}
</script>
</body>
Notice the tranRight javascript function, which will enable us to transfer the text in the left frame to the right frame. The tranRight function is called from the click event of the btnTransferRight button Parent.Frames(1) indicates we are targeting the right frame, while Parent.Frames(0) is the current page that the code is getting initialized from. When the btnTransferRight button is clicked, only the left frame will be re-rendered because the button’s event is set to run client side.
With that simple code, we have established basic interaction between our frames.
Goal #2: Pass text between pop-up and right frame
In this section we will pass text from a pop-up screen launched from the left frame to a textbox in the right frame.
UI Design
The “Send Via QS” button will trigger the event that will transmit the text. The lower section of this UI will be addressed in Goal#3
Figure 2
UI Code
The first key is the code which allows this pop-up to be launched from the left frame. This is a line in the original left frame codebehind listed as part of example #1:
btnPop.Attributes.Add(“onclick”, “javascript:openWindow()”)
This is the JavaScript which launches this pop-up:
function openWindow()
{ msgWindow=window.open(“popup.aspx”,””,
“fullscreen=no,toolbar=no,status=yes,menubar=yes,scrollbars=no,resizable=no,
directories=no,location=no,width=500,height=400”);
if (msgWindow.opener == null) msgWindow.opener = self; }
Now that we have established the launch of the popup, we can look at the pageload event of the popup Web form.
Public Class popup
Inherits System.Web.UI.Page
Protected WithEvents btnLfile As System.Web.UI.HtmlControls.HtmlInputButton
Protected WithEvents btnWFrame As System.Web.UI.WebControls.Button
Protected WithEvents btnHframe As System.Web.UI.WebControls.Button
Protected WithEvents txtPop As System.Web.UI.WebControls.TextBox
Protected WithEvents myFile As System.Web.UI.HtmlControls.HtmlInputFile
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
‘enclose the add attributes in the not is post back block, so they
‘ are called to be added only once.
If Not IsPostBack Then
btnSendQS.Attributes.Add(“onclick”,
“javascript:openpdf(txtPop.value)”)
btnSendSession.Attributes.Add(“onclick”,
“javascript:openviacache()”)
End If
End Sub
End Class
Once again we are adding attributes to two of the buttons which call javascript functions. The first button is the one we will concentrate on for the time being. As you can see we are passing in the value of the txtPop textbox.
Here is the javascript which transmits the text.
function transferText(strTxtTransfer) {
window.opener.parent.frames[1].location.href
= “rightframe.aspx?strText=”+ strTxtTransfer; window.close(); }
By using window.opener.parent we are able to reference the original frame, so we then in turn can reference the right frame to transmit the data to (by inserting and index of 1). The text itself is encased within a query string. This query string is then read by the right frame on load of the page and presented within that page’s textbox.
Goal #3 Use HTML input control in pop-up to load user file to server and then launch pdf in right fr
In this section we will be using the HTML input control to load a pdf file to the Web server and then subsequently call for the load of that pdf into the right frame. The HTML input control, which is provided with .NET, makes file uploading far more simple by presenting users with the standard Windows file browsing window.
UI Design
Figure 2
UI Code
<form id=”Form1″ method=”post” encType=”multipart/form-data”
runat=”server”>
The first section of code to review is the HTML in the pop-up.aspx page. In the form you must add the
Tag encType=”multipart/form-data”. This will allow the HTML input control to work.
Private Sub btnLoadFile_ServerClick(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnLfile.ServerClick, btnLoadFile.ServerClick‘Grab the file name from its fully qualified path at client
Dim strFileName As String = myFile.PostedFile.FileName
‘ only the attched file name not its path
Dim strShortFile As String = System.IO.Path.GetFileName(strFileName)
‘Save uploaded file to server @ rootweb\pdf_files and add to session
myFile.PostedFile.SaveAs(Server.MapPath(“.”) & “\pdf_files\” & strShortFile)
Session.Add(“fileName”, Server.MapPath(“.”) & “\pdf_files\” & strShortFile)
End Sub
This codebehind for the loadfile button saves the file up to the server and stores the name and location in session. This was the reason for the clearing of session that was seen in the codebehind of the left frame page. The browse button is what presents the user with the standard Windows Explorer file selection box and fills in the lower text box. This functionality is all encapsulated in the HTML input control.
Below is the HTML and JavaScript that exists behind the pop-up aspx page.
<%@ Page Language=”vb” AutoEventWireup=”false” Codebehind=”popup.aspx.vb”
Inherits=”asptoday_frames.popup”%>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>
<HTML>
<HEAD>
<title>popup</title>
<meta content=”Microsoft Visual Studio.NET 7.0″
name=”GENERATOR”><meta content=”Visual Basic 7.0″ name=”CODE_LANGUAGE”>
<meta content=”JavaScript” name=”vs_defaultClientScript”>
<meta content=”http://schemas.microsoft.com/intellisense/ie5″
name=”vs_targetSchema”>
</HEAD>
<body MS_POSITIONING=”GridLayout”>
<form id=”frmPopUp” method=”post” encType=”multipart/form-data”
runat=”server”><asp:label id=”Label1″ style=”Z-INDEX: 106; LEFT: 26px;
POSITION: absolute; TOP: 90px” runat=”server” Height=”20px” ForeColor=”Red”
Font-Bold=”True” Width=”280px”>Session
Example</asp:label><asp:label id=”lblSession” style=”Z-INDEX:
107; LEFT: 26px; POSITION: absolute; TOP: 117px” runat=”server” Height=”20px”
ForeColor=”DimGray” Font-Bold=”True” Width=”459px” Font-
Size=”Smaller”>Click Browse, Find PDF file, click load file and then the
send via session button</asp:label>
<INPUT id=”btnLoadFile” style=”Z-INDEX: 100; LEFT: 334px;
WIDTH: 79px; POSITION: absolute; TOP: 148px; HEIGHT: 23px” type=”button”
value=”LoadFile ” runat=”server”>
<asp:button id=”btnSendSession” style=”Z-INDEX: 101;
LEFT: 18px; POSITION: absolute; TOP: 179px” runat=”server” Width=”112px”
Text=”Send Via Session”></asp:button><asp:button
id=”btnSendQS” style=”Z-INDEX: 102; LEFT: 266px; POSITION: absolute; TOP: 41px”
runat=”server” Width=”113px” Text=”Send Via
QS”></asp:button><INPUT id=”myFile” style=”Z-INDEX: 103;
LEFT: 18px; WIDTH: 311px; POSITION: absolute; TOP: 148px; HEIGHT: 22px”
type=”file” size=”32″ name=”myFile” runat=”server”><asp:textbox id=”txtPop” style=”Z-INDEX: 104; LEFT: 25px;
POSITION: absolute; TOP: 43px” runat=”server” Width=”225px”>Transmit to
right frame</asp:textbox><asp:label id=”lblQS” style=”Z-INDEX:
105; LEFT: 32px; POSITION: absolute; TOP: 13px” runat=”server” ForeColor=”Red”
Font-Bold=”True” Width=”251px”>Query String
Example</asp:label></form>
<script language=”javascript”>function transferText(strTxtTransfer)
{
window.opener.parent.frames[1].location.href = “rightframe.aspx?strText=”+ strTxtTransfer;
window.close();
}function openviacache()
{
window.opener.parent.frames[1].location.href = “rightframe.aspx”;
window.close();
}
</script>
</body></HTML>
A refresh of the right frame is called from the “Send Via Cache” button, which has an onclick event call to the openviacache JavaScript function. This function calls for the re-load of the right frame page. We want the page to reload so the code in the page load event of the right hand frame page will execute.
The code behind of the right frame page looks for the fname session key and loads a pdf in the page based on that filename. In this block of code, I first test to make sure the file passed from session is a pdf. This is because I am using Response.contentType so that the browser can interpret the file as a pdf and display it properly in the browser.
Public Class rightframe
Inherits System.Web.UI.Page
Protected WithEvents txtFleft As System.Web.UI.WebControls.TextBoxPrivate Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
‘Put user code to initialize the page hereDim strTxtTransfer As String = Request.QueryString.Get(“strText”)
‘first find out if this page is getting called from the send via qs
button by looking for a query string
If strTxtTransfer <> “” Then
Me.txtReceive.Text = strTxtTransfer
‘ if session fname is populated and the file is a pdf load the pdf
ElseIf (Session.Item(“filename”)) <> “” And
Right((Session.Item(“filename”)), 3) = “pdf” Then
Response.Expires = 0
Response.Buffer = True
Response.Clear()
Response.ContentType = “application/pdf”
Response.WriteFile(Session.Item(“filename”))
Response.End()
‘if session has a value and it is not a pdf send an error message
ElseIf (Session.Item(“filename”)) <> “” And
Right((Session.Item(“filename”)), 3) <> “pdf” Then
With Me.txtReceive
.ForeColor = Color.Red
.Text = “sorry you must choose a pdf file to display”
End With
End If
End Sub
The final result looks like this:
Figure 3
Conclusion
My goal for this article was to illustrate that working with frames in ASP.NET is a far more efficient endeavor than it once was in the old ASP world. I also wanted to illustrate some benefits of using frames, which are not covered by ASP.NET’s Smart Navigation feature. My goal was not to convince you that frames are appropriate for most Web sites. When they are you can use this article as a guide so that you may avoid some of the struggles my team initially encountered.
Links
More info on Smart Navigation:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWebUIPageClassSmartNavigationTopic.asp
About the Author
Scott has experience working with ASP.NET, VB.NET, VB 6.0, SQL Server, ADO.NET, Essbase, XML, and UML.
Scott Rosa is an applications development manager for Analog Devices and has an MBA in Computer Information Systems.
Download source code below and rename the file to “15Seconds_frames” before unzipping.