Asked by:
User Control, dynamic Skins and the Page_PreInit.

Question
-
User1764000457 posted
Attempting to dynamically set the SkinID based for an asp:button embedded in a custom UserControl. Calling the SetNavBar method pasted below in the Page_Load event yields the following exception:
The 'SkinId' property can only be set in or before the Page_PreInit event for static controls. For dynamic controls, set the property before adding it to the Controls collection.
Unfortunately the "System.Web.UI.UserControl" doesn't seem to have a Page_PreInit and attempting to define one manually and attach the event handler such as with the following line:
Page.PreInit += new EventHandler(Page_PreInit);
protected void Page_PreInit(object sender, EventArgs e){
SetNavbar();
}
Has no effect. The same code worked perfectly while as an .ASPX page, but moving it to an .ASCX to create a UserControl and its a nightmare.
Any ideas?
protected void SetNavbar()
{
if (Session["CurNavButton"] != null)
{
string sCurrentNav = Session["CurNavButton"].ToString();
Button btnCurrentNav = this.FindControl(sCurrentNav) as Button;
if (btnCurrentNav != null)
{
btnCurrentNav.SkinID = "NavActive";
}
}
}
Wednesday, January 4, 2006 6:24 PM
All replies
-
User1109032460 posted
The answer to the problem is that you must hook the PreInit event in the Page (not the user control) and then call the method on the user control to set the navbar state (obviously you can't at the moment as it's protected, but that would be an easy fix).
I thought about this for a couple of seconds and realised that this would be deathly tedious to do if you had a lot of user controls. So, one way of making it a little easier to work with (and so you won't forget a control) follows.
Create a new interface, IRequirePreInit. This has a single method, OnPreInit
e.g.
public interface IRequirePreInit {
void OnPreInit();
}
Then, on any user control that you want to do things like skin work, you simply implement the interface to do what you need to do (in your case, set the nav bar state).
Finally, write a base page class (that you use as the base for all your pages) and in its OnPreInit override (I never handle Page_xxxx events, I always override the OnXXXX methods to save the unnecessary use of delegates), you simply enumerate the controls on the page, find out if any of them implement IRequirePreInit and if they do, you call the OnPreInit() method.
As a luxury feature, you can do some work on caching the control list (or simply use a boolean) to help optimise the iterating process on subsequent requests.
Wednesday, January 4, 2006 10:14 PM -
User1764000457 posted
Thanks DMV! This is exactly what I was looking for and it worked flawlessly once I implemnted what you described.
One "gothca" to anyone who uses attempts this, if the page you are attempting to walk thru the controls has a MasterPage, you will need to start looking at the control heirarchy from Page.Master, rather than Page.
Friday, January 6, 2006 2:15 PM -
User891972475 posted
DMV,
I know this thread is three years old and you might not even be doing this anymore, but if you are around would you be able to provide c# code examples for the suggestions you made above. Can you particularly explain what you mean by:
"Finally, write a base page class (that you use as the base for all your pages) and in its OnPreInit override (I never handle Page_xxxx events, I always override the OnXXXX methods to save the unnecessary use of delegates), you simply enumerate the controls on the page, find out if any of them implement IRequirePreInit and if they do, you call the OnPreInit() method."
Thanks
Wednesday, April 8, 2009 6:18 AM -
User1535111871 posted
Hello
This is in VB, so you'll want to translate it, but it works:
The interface
Public Interface IRequirePreInit Sub OnPreInit() End Interface
The base page class
Public Class BasePage Inherits System.Web.UI.Page Private Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit Recurse(Me) End Sub Private Sub Recurse(ByVal Parent As Control) Dim loUserControl As IRequirePreInit For Each loChild As Control In Parent.Controls If TypeOf loChild Is IRequirePreInit Then loUserControl = loChild loUserControl.OnPreInit() End If Recurse(loChild) Next End Sub End Class
The derived page classes
Partial Class DerivedPage Inherits BasePage End Class
The UserControl class
Partial Class TocTabControl Inherits System.Web.UI.UserControl Implements IRequirePreInit Public Sub OnPreInit() Implements IRequirePreInit.OnPreInit End Sub End Class
HTH
Wednesday, August 26, 2009 3:45 AM -
User-1315463767 posted
Here's my C# version. Note that I use master pages for all my pages, so I always pass "Master" to HandlePreInitControls() (thanks for the tip mselmer).
The interface:
public interface IRequirePreInit
{
void OnPreInit();
}
The base page class:public class BasePage : System.Web.UI.Page
{
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
HandlePreInitControls(Master);
}
private void HandlePreInitControls(Control parent)
{
foreach (Control control in parent.Controls)
{
if (control is IRequirePreInit)
{
(control as IRequirePreInit).OnPreInit();
}
if (control.HasControls())
{
HandlePreInitControls(control);
}
}
}
}
The derived page classes:public partial class DerivedPage : BasePage
{
}
The UserControl class. I'll show my implementation, which has two DataPagers:public void OnPreInit()
{
if (!DataPagerSkinID.IsNullOrEmpty())
{
DataPager1.SkinID = DataPagerSkinID;
DataPager2.SkinID = DataPagerSkinID;
}
}Note that the test
if (control.HasControls())
was really important. Without it, several of my controls no longer worked on postback, UNLESS I passed "Page" instead of "Master" to the HandlePreInitControls(), which of course totally defeats the purpose of modifying controls during PreInit(), such as programmatically changing SkinIDs.
Tuesday, July 13, 2010 8:37 PM