Tim Weaver

A .NET Blog

<November 2008>
SuMoTuWeThFrSa
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456


Navigation

Work

Subscriptions

Post Categories



Friday, September 10, 2004 - Posts

VS 2005 Master Pages -- Part II
Scenario one:  Have a shared ASPX page that must display the same controls laid out horizontally vs vertically
  The intent here is to determine how realistic it is to use a shared partial class with different UI layouts.
Currently you can easily handle this by dynamically loading a different control to the page and ensuring that the control is completely self-aware. The control gets the data/manipulates it, etc.
  For this example I wanted to have the shared code beside handle all the page logic. I didn't want to have to have duplicate code in the controls.
 
I setup my web page [AddUserThree.aspx] using a simple MasterPage [MasterPage_Custom.master]:

<asp:ContentPlaceHolder ID="pageBodyContentPlaceHolder" Runat="Server">
</asp:ContentPlaceHolder>

I then moved the click event from the user control to AddUserThree.aspx.cs. This doesn't work. Since the code in the code beside isn't compiled there is no way to reference from one to another (that I could figure out anyway).

Okay, I thought, no problem. I added an event declaration to the user control [AddNewUser.ascx]. Again I had the same problem. The public delegate for the event wasn't visible outside of the page. I moved the delegate declaration to a class in the /code folder. This folder contains classes that are generally available to the web site. My delegate was suddenly visible.

Next step was to attached the AddUserThree.aspx page to the event in the user control. Once again code beside foiled me. The declaration of the event inside the user control wasn't visible.
I came up with a couple of options:
  • Create a base user control and have all my shared controls inherit from it
  • Create an interface and have all my shared controls implement it
A quick attempt at the base page produced a number of nasty errors. The issue being that the partial classes inheritance didn't match. This makes sense because all I changed was the partial class that was visible to me in the IDE. I'm going to assume that there is a way to change the inheritance of the partial class, but I punted on that approach and went with the interface.
I created a simple interface that contains the one method whose event I wanted to bubble up:
public interface IAddNewUser
{
   event NewUserEventHandler OnNewUserClick;
   void AddUser_Click(object sender, EventArgs e);
}
Next step was to implement that interface in my user control(s) partial class
public partial class AddNewUser_ascx : IAddNewUser
{
   public event NewUserEventHandler OnNewUserClick;
   public void AddUser_Click(object sender, EventArgs e)
   {
      if(OnNewUserClick!=null)
         OnNewUserClick();
   }
}
The final step was to hook the aspx into the event
public partial class AddUserThree_aspx
{
    #region OnPreInit
    /// Load up the correct user control based upon querystring parameter
    protected override void OnPreInit(EventArgs e)
   {
       base.OnPreInit(e);
       object pageType = Request.QueryString["PageType"];
      int controlID = 1;
      if(pageType !=null)
       {
          controlID = Convert.ToInt32(pageType);
       }
       LoadCustomControl(controlID);
    }
    #endregion
    #region LoadCustomControl
    /// Load the control specified by the controlType
    private void LoadCustomControl(int controlType)
    {
       //get a reference to our placeholder
      Control ctr = this.Master.FindControl("pageBodyContentPlaceHolder");
       string controlPath;
       //the LoadControl is defined for us in TemplateControl abstract class
       switch (controlType)
       {
          case 1:
             controlPath = @"~/AddNewUser.ascx";
             break;
         case 2:
             controlPath = @"~/AddNewUser2.ascx";
             break;
          default:
            throw new InvalidOperationException("Unable to load a control based upon type " + controlType.ToString());
          }
          Control loadedControl = LoadControl(controlPath);
          ((IAddNewUser)loadedControl).OnNewUserClick += new NewUserEventHandler(AddNewUserClick);
          ctr.Controls.Add(loadedControl);
   }
    #endregion
    #region AddNewUserClick
    void AddNewUserClick()
    {
      if (!Page.IsValid)
       {
          Page.Title = "Warning Page isn't valid";
       }
    }
    #endregion
}
 
At this point I can define any events in my interface and as long as the controls implement that interface I can capture them and respond as needed. My initial take on these effort is that partial classes, while offering a lot, change the way you have to approach your problems. It seems likely that this is going to break a fair amount of code that exists today under the 1.1 framework.
My goal in this scenario was to try and test a shared code beside between the user controls. It turned out that I couldn't get that to work, so I moved that shared logic into the page that was hosting the shared controls and added custom events to get the scenario working. Next step is to try the same thing but using a Dynamically loaded master page.

posted Friday, September 10, 2004 1:03 PM by icodemarine

VS 2005 and Homegrown Master Pages
We have a custom master pages implementation. It relies on a custom base page to handle the templating. We also use base page(s) to handle other shared type logic. I ran the site through VS 2005 migration wizard and quickly realized something was seriously wrong.

I started doing a bunch of different tests to see what the results would be:

  • ASPX Pages that inhert from Page
  • Custom User Control without custom base class
  • ASPX Pages inherit from custom base page
  • Custom User Control that inherits from a base class definated in another assembly
  • Custom User Control inherits from custom base class, which exists in project
 
  Results
The first two tests turned out pretty much as I expected.
The ASPX page was properly converted and the codebehind was turned into a partial class.
The User control was properly converted and the codebehind was turned into a complete class
    I would have thought this would be a partial class, but it was the complete definition.

The ASPX that inherited from a custom base page didn't fare so well. The page was converted and a partial class was created. However, the original base page reference was lost and although the page had the Inherits attribute which pointed to the original base page class name the class wouldn't compile (and obviously none of the custom base page functionality was available).

The Custom User Control that inherits from a base class defined in another assembly had the same issue as the page with a custom base. The original base was lost.

The Custom User Control that inherits from a base class defined in the project worked

  • The base class was moved to the code directory
  • The codebehind was converted to a partial class
  • The page had the Inherits attribute pointed to the base in the code directory
  • Major downside was that you can't tell what a partial class is inherited from without some serious digging or looking at that ascx file

posted Friday, September 10, 2004 8:51 AM by icodemarine




Powered by Dot Net Junkies, by Telligent Systems