ASP.NET Compile behavior changes depending on page content

asp.netvisual-studio-2008

I've been struggling with some issues relating to referencing child controls within a FormView. Another developer wrote an ASPX page that is compiling and working and in that code, he references child controls within a FormView directly as properties of the page object. The page is part of an ASP.NET Web SITE Project (as opposed to a Web Application Project). We decided to convert the project to the Web Application Project model and noticed that these property references now don't compile. The code behind file does not generate the controls within the form view.

While researching that issue (I had a separate post here regarding those problems), I came across something baffling. From all the posts I've read, you should always need to reference child controls within a FormView's template using FindControl — i.e. it is supposedly not possible to do through a simple generated property regardless of whether you're in the Web Site Project model or the Web Application Project model.

I was puzzled as to how my colleague's code compiled and ran. As I indicated, he is referencing the FormView's contained child controls through simple properties in the page and did not have to resort to FindControl calls. So to get to the bottom of this mystery, I cooked up the shortest example that demonstrates this phenomenon.

What I found was very strange. The code I have here has a ASP:FormView with a few label controls within it's ItemTemplate. One of those labels has the ID MyComment. When the FormView databinds (to the Northwind's Products table), I simply set some text.

using System;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.FormView1.ChangeMode(FormViewMode.ReadOnly);
    }
    protected void FormView1_DataBound(object sender, EventArgs e) {
        MyComment.Text = "Data bound at " + DateTime.Now.ToString();
    }
}

This code will not compile because MyComment is not a valid property. Here comes the strange part. If I embed within the FormView's ItemTemplate a TabContainer control from the Ajax Control Toolkit library, the code above does compile and runs correctly.

So the reason my colleague's code is compiling is because of the embedded TabContainer control within the FormView?? Why this should change the behavior of the compiler and the mechanisms by which you can get access to the FormView's child controls is a mystery to me. Incidentally, despite the fact that it compiles cleanly and runs correctly, Intellisense does not see these properties and ReSharper reports them as compile errors (by the red light in the indicator bar).

Here is the markup for the page. Can anyone shed some light on this behavior? Incidentally, I'm not complaining about the fact that ASP.NET creates these properties in this circumstance. (Unfortunately, this happy, but strange, behavior, only seems to apply if the project is a Web Site Project; as a Web Application Project, property accessors don't work within the FormView even with the embedded TabControl).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
        <asp:FormView ID="FormView1" runat="server" DataKeyNames="ProductID" DataSourceID="SqlDataSource1"
            OnDataBound="FormView1_DataBound">
            <ItemTemplate>
                <ajaxToolkit:TabContainer runat="server" ID="TabsItem">
                    <ajaxToolkit:TabPanel runat="Server" ID="PanelBasicsItem" HeaderText="Basics">
                        <ContentTemplate>
                            ProductID:
                            <asp:Label ID="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>' />
                            <br />
                            ProductName:
                            <asp:Label ID="ProductNameLabel" runat="server" Text='<%# Bind("ProductName") %>' />
                            <br />
                            My Comment:
                            <asp:Label ID="MyComment" runat="server"></asp:Label>
                            <br />
                        </ContentTemplate>
                    </ajaxToolkit:TabPanel>
                </ajaxToolkit:TabContainer>
            </ItemTemplate>
        </asp:FormView>
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
            SelectCommand="SELECT [ProductID], [ProductName] FROM [Alphabetical list of products]">
        </asp:SqlDataSource>
    </div>
    </form>
</body>
</html>

Best Answer

When you converted the Web site to a web application, did you check that the partial classes were correctly generated for your aspx files (e.g. there should be a file called "Default.aspx.cs.designer" in your web application, under the Default.aspx and Default.aspx.cs files).

In a web site, these are generated on the fly by the server as your site runs and is compiled (and so don't exist in your project), while in a web application they are created and managed by Visual Studio - if they don't exist, then the code will potentially fail to compile because the objects haven't been instatiated - what is the actual compiler error are you seeing?

By adding a new control to the page after you've converted the project to a web application, you are forcing VS to create the partial class that was missing.