Quantcast
Channel: West Wind Message Board Messages
Viewing all articles
Browse latest Browse all 10393

Re: Compilation Error

$
0
0
Re: Compilation Error
Web Connection 5.0
Re: Compilation Error
04/15/2012
05:52:54 PM
3HA12BUEX Show this entire thread in new window
Gratar Image based on email address
From:
Rick Strahl
To:
Attachments:
None
Bob,

Did you see my bug report on the 'parameter not found' error? This.SelectedValues.Clear(.T.) is failing.

Yes I introduced that in ClearItems() - it's fixed in the code i just posted.

Best practice is to always externalize your CSS even for control properties. Now I'll be the first to admin that I often fall back to tweaking styles too but it's not such a great idea to do in the doc because you can't re-style it easily.

It's also easier to work with CSS externally because you can change CSS setting in the external file and leave it be, and leave the markup window as is as well.

+++ Rick ---



What is the best methodology to lay out a form? My CSS are in separate files. But I am constantly using Visual Studio to change <div> attributes to get everything positions correctly.

Did you see my bug report on the 'parameter not found' error? This.SelectedValues.Clear(.T.) is failing.

Thanks again for a great product and, of course, outstanding support.

~bob


Bob,

Ideally you should keep your CSS in a separate file. Either use a global file or externalize the CSS to a Page.css file and load into the page. Makes life a lot easier.

But this was definitely a big bug. I never see it because I almost always data bind lists and when you do the list items are never set. I have seen this before in demos and never quite figured out where the hangs were coming from :-)

Thanks for helping track this down.

+++ Rick ---



Oh, thank you, Rick. This is one of those things that can be lived with, but is frustrating when doing a lot of CSS formatting.

I am getting an error regarding the new parameter added to this dispose() statement:

This.SelectedValues.Clear(.T.)

Is there also a change in Clear()?

~bob


Ok, after both you and Stein mentioned this I took a closer look and for some reason now ended up with the same behavior you did.

And.... found the problem. There's a bug in wwWebListItem.Dispose() which should read like this:

************************************************************************ * wwWebListControl :: Dispose **************************************** *** Function: *** Assume: *** Pass: *** Return: ************************************************************************ FUNCTION Dispose() *** Don't do if we were already here IF THIS.lDISPOSECALLED RETURN ENDIF *** Must dispose child items IF !ISNULL(THIS.Items) AND THIS.Items.Count > 0 THIS.ClearItems() THIS.Items = null ENDIF This.SelectedValues.Clear(.T.) DODEFAULT() this.lDisposeCalled = .T. ENDFUNC

Note the this.lDisposeCalled = .T. at the end - previously it was BEFORE the DODEFAULT() which caused the control not to clean up properly. In fact the this.lDisposeCalled = .t. is not necessary as the base class takes care of that.

With that in place the page now can be edited.

That takes care of the problem for lists and dropdowns, but not for RadioButtons. List just use key value pairs for the display and value portions while radio buttons actually use controls. In hindsight this was a boneheaded idea - I should just have used web list items. The reason I used the simpler types for lists is so that it's easier to create hte lists with just specifying a value and text description. I may still change this since this is an internal detail.

IAC, in order for the clearing to work for both ClearItems has to look like this:

************************************************************************ * wwWebListControl :: ClearItems **************************************** *** Function: Clears out all manually added items and the DataSource *** Assume: *** Pass: *** Return: ************************************************************************ FUNCTION ClearItems() LOCAL lnX, loItem FOR lnX = 1 TO this.Items.Count *** List items return string values loItem = this.Items.aItems[lnX,2] *** Except RadioButton Lists which return IF VARTYPE(loItem) = "O" loItem.Dispose() ENDIF loItem = null ENDFOR THIS.Items.Clear() this.DataSource = "" ENDFUNC * wwWebListControl :: ClearItems

Damn - Can't believe this has not been noticed in all these years...

With this I can drop any list controls and radiobutton lists without hangs.

Moral of the story: Always make sure that all Controls on a page call .Dispose() and anything placed in the various arrays is explicitly released. Anything manually added to a page needs to be cleaned up or VFP will not release it properly.

+++ Rick ---


The failure occurred with your updated webcontrol.prg exactly the same as Stein's test (and my previous one.)

Without your update, this only occurs when the items are explicitly added to the list control through the script page. If they are added programmatically, the page does not hang.

Could these controls be popped on your stack (or not) differently back when the page is parsed and built? Which is causing the dispose() to see them differently?

I'm at a loss.

~bob


Attached to this message...

+++ Rick ---



Yes. The below steps were all done with the changed ClearItems() code. Why don't you email me webcontrol.prg and I'll repeat the process so we can rule code differences between us.

~bob



Did you try this with the changed code I posted for ClearItems()?

Without that I saw the same behavior you did. With it though it works and I can edit the page as many times as I want without hangups.

The problem with locks is that if the page has pending references to *anything* the class cannot unload which locks the FXP in memory. The PRG actually updates but when the page runs again it can't update the compiled FXP and so it ends up running the old page.

Ultimately this is a problem because that's a slow memory leak in the making... and it's one of those unfortunate VFP features that it doesn't clean up child references consistently especially references that live in arrays - you have to go through each element and explicitly release each.

+++ Rick ---


Hi Rick,

Sorry I didn't follow-up earlier. I did email you a simple test form last week, but then got tied up with a client. I just created a new form with a single control.

<head> <title></title> </head> <body style="margin-top: 0px; margin-left: 0px; text-align: left;"> <form id="form1" runat="server"> <div> <fieldset> <legend>Radio Button</legend> <div> <ww:wwWebRadioButtonList ID="wwWebRadioButtonList1" runat="server"> <asp:ListItem>test</asp:ListItem> </ww:wwWebRadioButtonList> </div> </fieldset> </div> </form> </body> </html>

I touch the file and start VFP. Refresh the form and all works as expected. A second touch to the file with refresh causes the outstanding references error. Those are the exact steps required to duplicate this every time.

I attempted to step through the Destroy() method (and did so several dozen times) but could not figure out what is happening.

When this fails, ClearItems() is not called as THIS.Items.Count = 0 in dispose.

FUNCTION Dispose() *** Don't do if we were already here IF THIS.lDISPOSECALLED RETURN ENDIF *** Must dispose child items IF !ISNULL(THIS.ITEMS) AND THIS.Items.Count > 0 THIS.ClearItems() THIS.Items = null ENDIF

THIS.Items is still an object at that point. aitems() has two elements, both set to false. I copied the 'THIS.Items = null' after the loop to see if that cleared the references hanging the system, but no joy.

If you are unable to duplicate this, I'll move all this up to my server and give you access to that. Or, I guess you could connect to my desktop development machine if you prefer.

~bob


It's possible you have other unreleased controls in that page then. Pretty sure this fix will take care of the list item issue. You should check this with a simple page that just contains a list of some sort. It works for me and didn't prior to the change.

To find hung references:

* Set a breakpoint in WebControl.Destroy
* Run your app
* Hit page you think has hung refs
* Clear All/Close All

When you hit the Clear All/Close FoxPRo will trigger on any lingering controls that weren't released properly. Check the ID to or Class to figure out which ones.

+++ Rick ---



So I always drop by this site once or twice a week just to see what's up. For some reason, I did not do so last week. So I missed seeing this thread. So when my tech complained about not being able to recompile one of my pages, I was not aware of the radio button issue. So I just spent a good 3 hours trying to figure out what I had introduced into the page to cause the problem before concluding that the radio button was the problem. Then I decide to finally check out the board and find this.

Unfortunately the fix did not work for me either. Here's my WCSX code:

<div id="mainBody" style="display:none"> <form id="form1" runat="server"> <ww:wwWebErrorDisplay runat="server" id="ErrorDisplay" /> <b>Base Path:</b> <WW:WWWEBRADIOBUTTONLIST ID="lstBase" runat='server'> <asp:ListItem Selected="True" Value="WConnect">WConnect Folder</asp:ListItem> <asp:ListItem Value="Manager">Manager Folder</asp:ListItem> <asp:ListItem Value="AW">ACEweb Folder</asp:ListItem> </WW:WWWEBRADIOBUTTONLIST> <br /> <b>Additional Path and File Mask:</b> <br /> <ww:wwWebTextBox ID="txtPath" runat="server" Visible="True" Width="380px" AutoPostBack="True" Change="txtPath_change" /><br /><br /> <b>Main template folder:</b> <ww:wwWebTextBox ID="txtTemplateFolder" runat="server" Visible="True" Width="39px" AutoPostBack="True" Change="txtFolder_change" Text="ace" /> <font size="-2">(Leave as "ace" unless using an Alternate Interface)</font><br /> <ww:wwWebButton ID="btnGo" runat='server' Width='80' Text="Go" Click="btnGo_Click" OnClientClick="return ok2Go('ED');" /><br /><br /><br /> </form>

If I load the page, make a change to the source, and try to reload I get the outstanding references error. I modified wwWebListControl :: ClearItems in webcontrol.prg per your example. Do I also need to change wwWebListControl :: Dispose?

--stein


Can you give me an example? I used your radio button example which worked fine.

Anything that gets added via AddControl() adds to the Items collection and should be removed by the dispose() call. It seems to work for me here. Did you put this in the right place? wwWebListControl :: Dispose and ClearItems().

+++ Rick ---



I think that made it worse. List controls that are populated manually through the code behind now hang also.

~bob



Yeah I noticed this yesterday too as I was looking at Luca's example. I had to stop and start.

Hanging reference there for sure have to see what's happening. Odd that it fires the first time though...

Ok, took a look. I think the issue is that the list items aren't cleaning up. In fact this is a problem for all list controls not just the RadioButtonList (ie. listbox, dropdownlist).

The fix is to explicitly call Dispose() on the child items:

************************************************************************ * wwWebListControl :: ClearItems **************************************** *** Function: Clears out all manually added items and the DataSource *** Assume: *** Pass: *** Return: ************************************************************************ FUNCTION ClearItems() LOCAL lnX FOR lnX = 1 TO this.Items.Count lnItem = this.Items.aItems[lnX] lnItem.Dispose() ENDFOR THIS.Items.Clear() this.DataSource = "" ENDFUNC * wwWebListControl :: ClearItems

This seems to fix the problem and make changes work again.

+++ Rick ---



Hi Rick,

Drop a radio list on an empty page and explicitly add some items as shown below and hit it. Then make a change and hit it again, you will get this error:

Compilation Error: File cannot be closed because outstanding references exist.

<ww:wwWebRadioButtonList ID="wwWebRadioButtonList1" runat="server"> <asp:ListItem>Item 1</asp:ListItem> <asp:ListItem>Item 2</asp:ListItem> <asp:ListItem>Item 3</asp:ListItem> <asp:ListItem>Item 4</asp:ListItem> <asp:ListItem>Item 5</asp:ListItem> </ww:wwWebRadioButtonList>

I stepped through wwControl.Dispose() and can see your code to explicitly release child controls firing on the first hit and working as designed. On the second hit (after a change was made to the page that requires a recompile), Dispose() is not called for the radio control or any others after it on the page.

That's as far as I got debugging this.

~bob

























Rick Strahl
West Wind Technologies

Making waves on the Web

from Maui, Hawaii

Viewing all articles
Browse latest Browse all 10393

Trending Articles