Webforms asp:Panel children not showing fully in VS 2012 - asp.net

I'm wrestling with design time rendering of my custom WebForms components where I have defined a control derived from Panel and a second control derived from WebControl.
I place the WebControl inside the Panel by dragging and dropping from the Toolbox. The problem I have is that at design time when I drag and drop the component within the Panel, the Paint method of the WebControl's designer is being executed immediately but the image generated by the interpretation of the getDesignTimeHtml and the application of the CSS rules is being executed a varying number of seconds later, typically between 1 and 4 seconds.
So my component is being drawn twice by two different pieces of logic. How can I synchronize these events so they both are executed at the same time? Having to wait for a ghost image to clean itself up is distracting for the developer. Note if I place the WebControl outside the Panel both methods are called at the same time, and they are called immediately.

One solution is to invoke the Invalidate() method of the PanelContainerDesigner that belongs to the parent System.Web.UI.WebControls.Panel. Invoke this from the OnPaint() method of the child component's Designer.
To prevent needless looping, let the child component's Designer remember and verify its position data on each OnPaint() call, and only invoke Invalidate() on the PanelContainerDesigner if there is a real change.

Related

How can I get Visual Studio to auto-stub delegates to control events in ASP.NET?

So in a WinForm app, the Properties tab has an event button. It shows me all the possible events I can wire up to a delegate for the control that has focus. Then, all I have to do is double-click my event of choice and VS will auto-stub the delegate for me with the appropriate EventArgs type and everything. It'll then automagically take me to that delegate in the class.
How can I do the same thing in ASP.NET? For example, where can I click or double-click to have VS auto-stub in lifecycle Page events such as OnInit or OnUnload and then take me to the newly stubbed delegate? Surely this isn't always a manual process?
The Event tab in the property grid requires that Design View be up to date (synchronized) to work. For this to happen, you either need to be in design view, or have just left it without making changes to the document (or be in split view, so you can refresh the designer easily at will).
See also: Events tab randomly appears and disappears in VS 2008
Adding information from the comments:
Currently (VS2010), the only stubbing support for event handler generation using WebForms is for server control events. There isn't any tooling out-of-the-box to create event handlers for the Page itself (e.g. OnInit, OnUnload) if you're using code-behind files. However, if you are using single file webforms (i.e. no code behind) you can generate these via the Navigation Bar (disabled by default in VS2010, but enabled in previous versions).
Just select the element, go to event tab in property grid. Then double click the event you want.
Also make sure you are using "runat=server" and ASP.NET WebControls. In other words, not HTML controls.
As an addendum to the question: Please see Jimmy's comments above. Looks like everything else works fine but there's no method of auto-wiring up Page-type-specific events.

Why do subcontrols initialize before their containers?

Despite working with WebForms for years I still find myself getting confused about the event lifecycle from time to time. This isn't so much a problem that needs resolving, as hoping to get a better understanding of why things work the way they do.
Suppose you have a form:
Default.aspx:
<form>
<MyControls:UserControl1 runat="server">
</form>
UserControl1:ascx:
<MyControls:UserControl2 runat="server">
The OnInit events occur in this order:
UserControl2_OnInit
UserControl1_OnInit
Default_OnInit
Isn't this just bass-ackwards? Shouldn't the Init code be run in the order that controls are created? Shouldn't a parent control be able to initialize properties of a child before its OnInit runs? That is, while you can initialize properties of subcontrols in markup, there's no direct way to have a parent control be able to dynamically set properties of the child control that will be available to its OnInit event.
What I've ended up doing is stuff like this:
override void UserControl2_OnInit()
{
NamingContainer.OnInit += new EvenHandler(UserControl1_ActualInit);
}
protected void UserControl2_ActualInit(..) {
// do actual init code here, which will occur before OnLoad but after it's parent
// OnInit
}
So it's not an insurmountable problem. I just don't understand why it's a problem in the first place.
I realize that perhaps you might want to be able to have all your child controls initialized in your OnInit code. So fine, you should be able to call base.OnInit first, instead of after, your own initialization code, which should cause all the child control OnInit events to get run. But the event lifecycle doesn't work that way. The Init events are not chained recursively, they seem to run independently the parent events, and the innermost one always gets run first. But seems life would be a lot easier if they were simply chained recursively so you could either call the base event (or not) before you do your thing in any given situation. Is there something I'm missing that makes this seemingly counterintuitive situation desirable or even necessary?
This document should be the main source of truth for your lifecycle questions.
Basically, OnInit fires after a control's internal initialization in finished. Since the page control is the first control initialized, and during it's internal initialization it initializes all sub-controls (perhaps in the order that the Designer.cs file gives), then it makes sense for the Page's OnInit event to be the last one called, since it's not finished initializing until all it's sub-controls are initialized and their OnInit events fired. Graphically, it looks like this:
Page internal init
Sub-control1 internal init
Sub-sub-control3 internal init
Sub-sub-control3 init finished / OnInit fired
Sub-control1 init finished / OnInit fired
Sub-control2 internal init
Sub-control2 init finished / OnInit fired
Page init finished / OnInit fired
So order of inits in this case is:
Sub-sub-control3 OnInit
Sub-control1 OnInit
Sub-control2 OnInit
Page OnInit
Load also work similarly. In general you should treat most of the events as though the control will go through it's internal process first (which includes calling the same event on all sub-controls), and then fire your custom event handling code afterwards.
Most examples you find use Page_Load specifically because that should be the last event called in that phase (and it's after post back data is loaded). It wouldn't work very well for Page_Load to be called first and risk having controls not in a fully loaded state for your custom event handling code.
The mindset for asp.net parent & child controls is:
Parents know all about their children, but children know nothing about their parent.
This mindset makes sense for re-usable server controls. Re-usability needs the custom child control making no assumptions about the page it gets used on.
The snippet you give makes me guess that your child user controls are not aimed at re-usable as such; but rather are specialized controls which you use to break down the complexities of a large & tricky UI?
In this case I would still try to work with the 'children known nothing about their parent' mindset. Think http://www.google.co.uk/search?q=gof+mediator+pattern where the parent page is the mediator between your children (the wikipedia page is good).
But your children still need to know something about the parent right, because they are doing complex UI interactions? You can address this with interfaces. Each child depends not on the parent, but on an interface that defines exactly what the children need access to. As http://en.wikipedia.org/wiki/SOLID puts it, 'depend on abstractions, not on concretions'. DO one interface per child control: 'many client specific interfaces are better than one general purpose interface'
But it all ends up looking over-engineered, doesn't it? It turns out that a componentised UI where the components must interact, just is complex, and the components may turn out big n clunky. This was, imho, one of the reason for MS web forms ajax controls losing out to jQuery &c. even before MVC came along.
Add to this that web forms ui is very hard to unit test; and your confidence in your software quality dives.
I recommend:
If you can, escape to a rewrite in MVC.
If you can't, consider abandoning server-side controls which do clientside behaviour, and use jQuery instead.
If you can't do that, simplify simplify simplify the UI. Even if that makes it less functional.
If you don't want that, then your choices are: pay the expense of engineering the UI well; or pay the expense of not engineering it well.

ScriptControl inside UpdatePanel

I have a ScriptControl (requires ScriptManager) with JavaScript to handle client-side interactions and ICallbackEventHandler to communicate back and forth. Everything works perfectly with one or multiple instances of the control on a page. I placed the control inside a GridView with sorting and it still works. However, I place the GridView in an UpdatePanel and now whenever I sort I get the following error for each instance:
Sys.InvalidOperationException: Two components with the same id 'GridView_ctl02_MyControl' can't be added to the application.
Can someone point me in the right direction on how to solve this? I am assuming ScriptManager is not disposing of the old Sys.UI.Control objects before trying to $create() the new ones with the same ID. I thought the UpdatePanel/ScriptManager combination would automatically take care of disposing objects that would be replaced?
Edit: This page appears to support what I thought: http://msdn.microsoft.com/en-us/library/system.web.ui.scriptmanager.registerdispose.aspx
Use the RegisterDispose method to
register dispose scripts for controls
that are inside an UpdatePanel
control. During asynchronous
postbacks, UpdatePanel controls can be
updated, deleted, or created. When a
panel is updated or deleted, any
dispose scripts that are registered
for controls that are inside the
UpdatePanel are called. In typical
page development scenarios, you do not
have to call the RegisterDispose
method.
Just to double check I placed an alert("dispose " + this.element.id) inside my JavaScript dispose() function. Every single instance alerts dispose GridView_ctl02_MyControl, but afterwards I get the error that two components can't have the same name GridView_ctl02_MyControl. I'm at a loss...
When the page unloads, my component's dispose() method is called and Sys.Application.removeComponent() is also called. When the UpdatePanel reloads, only dispose() method is called. For now I have solved this by putting Sys.Application.removeComponent(this); inside the dispose(). I didn't find a shortcut such as $remove (similar to $create), implying you aren't expected to need this often.
This seems logical in that you can keep a component loaded even after its related DOM elements (if any) have been replaced by the UpdatePanel. This way you have more control over the component's life. I can't imagine a use case, but I'm sure you could come up with one.
If I am way off and there is a better approach, please let me know!

When "must" I use asp.net CreateChildControls()?

While it seems that the "right" way to make a server control is to construct all child controls inside CreateChildControls call. But since it's difficult to know when it will be called (which is the whole point as a perf optimzation), I see most of our devs construct in OnInit, or OnLoad. And this works 99% of the case.
Are there cases where we have to use CreateChildControls?
You should ALWAYS construct your child controls in CreateChildControls. This is the proper time in the Lifecycle to initialize and add them to the control tree. One of the reasons for this is that many times the method EnsureChildContols is called, which then calls CreateChildControls if necessary. Best Practice, just do it.
Read Control Execution Lifecycle
The CreateChildControls method is called whenever the ASP.NET page framework needs to create the controls tree and this method call is not limited to a specific phase in a control's lifecycle. For example, CreateChildControls can be invoked when loading a page, during data binding, or during rendering.
Performance-wise, waiting to create a child control will save your server some unnecessary CPU time. For example, if an exception is raised or the thread is aborted prior to CreateChildControls() being called, the clock cycles necessary to create those controls are saved.
What's your reasoning for saying that creating controls in OnInit is more performant than during CreateChildControls()?
You will get away with creating your controls in Init or Load until you write a control that needs to recreate the controls.
I find it is always best to create the controls in CreateChildControls and then use EnsureChildControls to control ensure they are created when you need them. This allows you the ability to tear down the controls by setting ChildControlsCreated to false and have them recreated again when needed.

Flex Component Lifecycle with Menus - best practice

I have built a multiplage application in Flex with different user roles. I use a View Stack with a Menu Bar to navigate between the different pages.
However - each time a page gets opened, I need to do some database calls, apply User Role settings, etc. in an init() function. This init function may reference some UI elements of this page.
I tried to load it with the "creationComplete" event, but this one gets only triggered once (since the page is not rebuilt each them the view stack shows it).
Now I have put it on the "show" event, but this seems not to get triggered consistently, or before the page is fully created the first time.
Whats the best practice for this case?
* I have to pass in data
* Call init functions (database calls)
* Manipulate components
Ideally I would need a way to call init each time the page is loaded and after all components are created.
Thanks for your help,
Martin
Just an idea but why not trying to do your remote call on ViewStack change effect. You could use an interface for this that your views implements.
Try updateComplete event.
Dispatched when an object has had its commitProperties(), measure(), and updateDisplayList() methods called (if needed).
This is the last opportunity to alter the component before it is displayed. All properties have been committed and the component has been measured and layed out.
I had the same kind of problem when I wrapped the s:Group with wrapper class to put inside TabNavigator. The result, show event is not being called. Finally I changed all my s:Group with mx:Canvas, directly put them into TabNavigator(The same thing goes for ViewStack too). After that creationComplete event was called once and subsequent page visits call show of mx:Canvas

Resources