[Bug 2.3.1]: UpdateContent exception on loaded control

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1

    [Bug 2.3.1]: UpdateContent exception on loaded control

    aspx
    <%@ Page Language="C#" EnableViewState="false" %>
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e) {
    	}
    	protected void CreateTest( object sender, DirectEventArgs e ) {
    		RP.ContentControls.Clear();
    		var uc = Page.LoadControl( "Test39.ascx" );
    		RP.ContentControls.Add( uc );
    		RP.UpdateContent();
    	}
    </script>
    
    
    <!DOCTYPE html>
    <html>
    <head id="Head1" runat="server">
    	<title>Ext.NET Example</title>
    </head>
    <body>
    	<form id="Form1" runat="server">
    
    
    		<ext:ResourceManager ID="ResourceManager1" runat="server" ScriptMode="Development" SourceFormatting="true" />
    		<ext:Viewport ID="vp" runat="server" Layout="HBoxLayout">
    			<Items>
    
    
    				<ext:Container ID="LP" runat="server" Border="true" Padding="5" Flex="1" Layout="FitLayout">
    					<Items>
    						<ext:Button runat="server" Text="Test Right Panel Load">
    						<DirectEvents>
    							<Click OnEvent="CreateTest" />
    						</DirectEvents>
    						</ext:Button>								
    					</Items>
    				</ext:Container>
    
    
    				<ext:Container ID="RP" runat="server" Flex="1" Layout="VBoxLayout">
    					<Items>
    					</Items>
    				</ext:Container>
    
    
    			</Items>
    		</ext:Viewport>
    	</form>
    </body>
    </html>
    ascx
    <%@ Control Language="C#" ClassName="Test39" %>
    
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e) {
    		EventP.Title  = "Test Right Panel";
    		TitleL.InnerHtml = "This is a test title";
    		HeadL.InnerHtml = "This is a test head";
        }
    </script>
    
    
    <ext:Panel ID="EventP" runat="server" Flex="1">
    	<Content>
    		<div class="TitlePnl">
    			<h1 id="TitleL" runat="server" class="Title" />
    			<div class="HeadPnl">
    				<span id="HeadL" runat="server" class="Head" />
    			</div>
    		</div>
    	</Content>
    </ext:Panel>
    There seem to be 2 problems with this code. 1) id names don't match when calling extjs functions, and 2) setTitle is redundant.
  2. #2
    In my production code, I'm seeing both these issues and it's rampant in all ext.net controls. Both the naming reference issues and the redundant calls.
  3. #3
    Hi @michaeld,

    This
    EventP.Title  = "Test Right Panel";
    generates script, because it occurs during an AJAX request, i.e. DirectEvent.

    Yes, it turns out that the EventP is a dynamic control and the scripts are not supposed to be generated. But, I am afraid, we cannot determine it automatically - the EventP is a dynamic control or not.

    As for ids mismatching. First, the user control's Page_Load is executed after:
    RP.ContentControls.Add(uc);
    So, this executes.
    EventP.Title = "Test Right Panel";
    It uses the user control's ID generated by ASP.NET.

    Then, the "final" user control's id is generated during the UpdateContent method. Such a sequence. We will look if we can improve something.

    The options are:

    1. Suspend scripting for the EventP control.
    EventP.SuspendScripting();
    EventP.Title = "Test Right Panel";
    2. Suspend scripting at all inside the Page_Load.
    X.ControlsScripting = false;
    EventP.Title = "Test Right Panel";
    3. Use the IDynamicUserControl interface.
    <%@ Implements Interface="Ext.Net.IDynamicUserControl" %>
    
    <script runat="server">
        public void BeforeRender()
        {
            EventP.Title = "Test Right Panel";
            TitleL.InnerHtml = "This is a test title";
            HeadL.InnerHtml = "This is a test head";
        }
    </script>
    Though, there is a big disadvantage. The BeforeRender won't be executed for a static user control.
  4. #4
    Quote Originally Posted by Daniil View Post
    Yes, it turns out that the EventP is a dynamic control and the scripts are not supposed to be generated. But, I am afraid, we cannot determine it automatically - the EventP is a dynamic control or not.
    Can you elaborate on why?

    Still, this says it all. "You cannot determine it automatically."

    What this tells me is if we can't determine it automatically, then we may need some way to tell Ext what mode we're trying to render in. There seem to be at least 3 possibilities. 1. First Time Page Load mode (renders initialization extjs json), 2. Ajax Direct Event Normal Mode (renders javascript extjs function calls), 3. Ajax Direct Event Control Construction Mode (renders initialization extjs json and add new control names to the App global so they can be referenced)

    #3 seems to be the scenario that's missing. Nothing is presently being added to App global, and the new controls need to be.

    We should be able to do something like this in the DirectEvent that will be adding new controls to notify ExtNet that we are constructing new controls that will be calling Page_Load.

    One option is ...
    protected void CreateTest( object sender, DirectEventArgs e ) {
            // This tells the Page renderer we're going to be adding controls in a direct event
            RP.AddControlsInDirectEvent = true;
    
    
            RP.ContentControls.Clear();
            var uc = Page.LoadControl( "Test39.ascx" );
            RP.ContentControls.Add( uc );
            RP.UpdateContent();
        }
    Alternately, right now ContentControls is using System.Web.UI.ControlCollection. If instead you derived your own Ext.Net.ControlsCollection from System.Web.UI.ControlCollection, you could override Add and AddAt to set this mode automatically based on X.IsAjaxRequest. This makes the best sense to me.


    Quote Originally Posted by Daniil View Post
    The options are:

    1. Suspend scripting for the EventP control.
    EventP.SuspendScripting();
    EventP.Title = "Test Right Panel";
    2. Suspend scripting at all inside the Page_Load.
    X.ControlsScripting = false;
    EventP.Title = "Test Right Panel";
    3. Use the IDynamicUserControl interface.
    <%@ Implements Interface="Ext.Net.IDynamicUserControl" %>
    
    <script runat="server">
        public void BeforeRender()
        {
            EventP.Title = "Test Right Panel";
            TitleL.InnerHtml = "This is a test title";
            HeadL.InnerHtml = "This is a test head";
        }
    </script>
    Though, there is a big disadvantage. The BeforeRender won't be executed for a static user control.
    Okay, these make sense as an alternate for 2.3.X now, but none do I deem acceptable for the future. It means I have to write many different paths if I want to use the same user control for both Direct Events and Initial load. Please see my topic on http://forums.ext.net/showthread.php?27212-Ext-Net-3-0
    Last edited by michaeld; Nov 15, 2013 at 2:42 AM.
  5. #5
    Quote Originally Posted by michaeld View Post
    Can you elaborate on why?

    Still, this says it all. "You cannot determine it automatically."
    Well, ASP.NET is a stateless system. It doesn't save and restore the page's state of previous requests. So, all the controls are recreated on each request. We cannot determine automatically it is created at first time or not.

    Quote Originally Posted by michaeld View Post
    RP.AddControlsInDirectEvent = true;
    Well, good. But it is already possible to produce the same effect by:
    X.ControlsScripting = false;
    RP.ContentControls.Add(uc);
    X.ControlsScripting = true;
    It looks good enough for the scenario. I just didn't realize before that it can be called in the page rather than in the user control.

    Also the Ext.Net.BaseControl has the IsDynamic property. Where possible to determine, we set up it automatically, but it is public and you can set up it to true if needed. A control doesn't generate scripts if its IsDynamic is true.

    Quote Originally Posted by michaeld View Post
    Alternately, right now ContentControls is using System.Web.UI.ControlCollection. If instead you derived your own Ext.Net.ControlsCollection from System.Web.UI.ControlCollection, you could override Add and AddAt to set this mode automatically based on X.IsAjaxRequest. This makes the best sense to me.
    Do you mean if X.IsAjaxRequest is true, we could set up RP.AddControlsInDirectEvent to true automatically? Hmm... But if the page has the following, for example?
    protected void Page_Load(object sender, EventArgs e) 
    {
        this.Panel1.ContentControls.Add(userControl);
    }
    Quote Originally Posted by michaeld View Post
    Okay, these make sense as an alternate for 2.3.X now, but none do I deem acceptable for the future. It means I have to write many different paths if I want to use the same user control for both Direct Events and Initial load. Please see my topic on http://forums.ext.net/showthread.php?27212-Ext-Net-3-0
    We will review the thread. Thank you.
  6. #6
    Quote Originally Posted by Daniil View Post
    Well, good. But it is already possible to produce the same effect by:
    X.ControlsScripting = false;
    RP.ContentControls.Add(uc);
    X.ControlsScripting = true;
    That might prevent the redundant code, but you haven't addressed the fact that right now, the code doesn't do what I posed in scenario 3. You need to add the App globals for the new controls or else you can't refer to them in javascript. This is a new control on the page and it may have it's own DirectEvents/Methods even. They need to be added. I haven't even gotten to testing that scenario, but I'm pretty sure that won't work given that EventP.setTitle() exceptions. You may even think it might be appropriate to remove the ones that were destroyed in the RP.ContentControls.Clear() as well.

    Moreover, your proposal would kill any intentional scripting that was intended to happen in the control. Example, say the control wants to

    Quote Originally Posted by Daniil View Post
    Do you mean if X.IsAjaxRequest is true, we could set up RP.AddControlsInDirectEvent to true automatically? Hmm... But if the page has the following, for example?
    protected void Page_Load(object sender, EventArgs e) 
    {
        this.Panel1.ContentControls.Add(userControl);
    }
    I'm not sure one of us is on the same page. Based on the example you just gave, if you implemented as I said here:
    Quote Originally Posted by michaeld View Post
    Alternately, right now ContentControls is using System.Web.UI.ControlCollection. If instead you derived your own Ext.Net.ControlsCollection from System.Web.UI.ControlCollection, you could override Add and AddAt to set this mode automatically based on X.IsAjaxRequest. This makes the best sense to me.
    ... the Add would be able to wrap the Add in something like this...
    X.ControlsScripting = false;
    base.Add(uc);
    X.ControlsScripting = true;
    ... and work.


    Quote Originally Posted by Daniil View Post
    We will review the thread. Thank you.
    Great.


    Still, do you mind looping vladimir to look at this current topic?

Similar Threads

  1. Replies: 1
    Last Post: Apr 02, 2013, 5:03 AM
  2. Replies: 1
    Last Post: Oct 10, 2012, 11:47 AM
  3. [CLOSED] [1.0] User Control loaded several times
    By FVNoel in forum 1.x Legacy Premium Help
    Replies: 4
    Last Post: Jul 07, 2011, 10:33 AM
  4. Replies: 2
    Last Post: Oct 29, 2010, 8:51 AM
  5. Replies: 2
    Last Post: Feb 10, 2010, 10:45 AM

Posting Permissions