I'm in the process of creating a custom MessageBox dialog. There's some additional functionality we need over the standard version (like a timer to auto-close) plus we want to dress it up a bit.
The standard Windows.Forms.MessageBox can be called anywhere; in a VOID method or one with a return value. My new form, however, because it contains a WAIT-FOR can be called only from a method (or method stack) that contains VOID return values.
Basically what I've done is to create a class with some static methods that a developer will use to call the new message box. This way the dialog doesn't have to be New'd every time it's needed. Within the static method I parse the parameters for the message box style and then NEW the dialog. The dialog has its own WAIT-FOR because it's modal.
If this is called from an event of some kind, no problems. The return type of the event method is VOID. If, however, this is needed to be called from a method that has a return value, it errors out.
My question:
Is there a way to create the message box dialog without using the WAIT-FOR and still be able to have it modal and process its events (button click)? I was given a suggestion to use some sort of repeat loop, but I can't see how I would process the events in the dialog.
Thanks,
JL
Is there a way to create the message box dialog
without using the WAIT-FOR and still be able to have
it modal and process its events (button click)? I was
given a suggestion to use some sort of repeat loop,
but I can't see how I would process the events in the
dialog.
These are the last things, that I still implement using my own assemblies written in the Visual Studio.
A method returning a value (non VOID) can be used in an assign statement or an open query statement. There have been issues affecting the database or index integrity (I don't remember 100% anymore) - that's why progress is preventing this. The issue is related to the ability of event handles causing trouble during the WAIT-FOR ...:ShowDialog() and that's why Progress is preventing this.
These are the last things, that I still implement
using my own assemblies written in the Visual
Studio.
What are ? The dialog boxen ? And how do you call them from the ABL ?
A method returning a value (non VOID) can be used in
an assign statement or an open query statement. There
have been issues affecting the database or index
integrity (I don't remember 100% anymore) - that's
why progress is preventing this. The issue is related
to the ability of event handles causing trouble
during the WAIT-FOR ...:ShowDialog() and that's why
Progress is preventing this.
I wish that they would fix it rather than put this plaster in place. It's been several years now
These are the last things, that I still implement
using my own assemblies written in the Visual
Studio.
What are ? The dialog boxen ? And how do you call
them from the ABL ?
Not any dialog box - just those custom message boxes and exception visualizers. These usually don't need access to the DB or anything else running in the ABL session.
For application specific dialog boxes I use the ABL and the Visual Designer (or the Dynamics Repository). And in those cases I've always found a way of not needing to call them from a non VOID method.
so you create these "extra" dialogs in c# - as a .dll ? Then you call them from the ABL how ?
It's not just dialogs that I need in a method / function : if I am doing a large processing job (exporting millions of records) I have to be able to provide the user with some form of feedback (est completion time etc), so I have to use PROCESS-EVENTS. Something I can't do in a method (non-void) or function. It's a real PITA.
? Then you call them from the ABL how ?
As suggested by Jim: Using static methods.
I definitely agree with Julian. There are many cases where it would be convenient to show a dialog from within a UDF or non-void method.
One of the things I mentioned in the original post was that the Windows.Forms.MessageBox can be called from a non-void method. I realize this is a built in .Net class, but if we're able to use the standard MessageBox, why not our own dialog class.
I agree with all of you. It's a product (ABL) limitation and it would be great to have it fixed soon!
One of the things I mentioned in the original post
was that the Windows.Forms.MessageBox can be
called from a non-void method. I realize this is a
built in .Net class, but if we're able to use the
standard MessageBox, why not our own dialog class.
I know - if you read me replies you'll see, that the dangerous part that might happen during the WAIT-FOR are ABL event handler accessing the database and opening transactions ect.. This is not possible in the MessageBox:Show method. There's no way, that that method fires an ABL event handler.
That's the difference.
Hello everybody,
this limitation is still avail in 10.2B!
I just remind that Mike told this in a course as i tried to change this ugly messageBox (why where modal is o.k.?) to my own user defined modal form.
@PSC: Why this isn't possible until today?
We know that this limitation is tough to work around. We have identified the "problem" and are looking at ways we could allow this in GUI for .NET. We will keep you posted on our progress.
Thanks.
Hi Shelley,
can you share some details on the background with us? So we might discuss "acceptable" and "practicable" solutions.
Are the issues due to things that might happen when a UDF/non-VOID method is user in an ASSIGN Statement to a DB field? Could the AVM detect that an allow uses of WAIT-FOR in an UDF when it's not user in an ASSNG?
Of course the best solution would be to take away this restriction at all!
Mike
Hi Mike,
This restriction was put in place to safeguard UDFs from getting into a state in the middle of expression that was incorrect. This is built into the architecture of the AVM. Methods that return values have the same limitation and as you know has caused frustration. We followed this model with calls to .NET but WAIT-FOR myDialog:ShowDialog( ) is a very specific statement that the AVM could special case.
Additionally we could treat ASSIGNs and statements differently than we treat the same code in the middle of an expression. As I said we are taking a look at the feasibility of a solution as well as long term options for removing the restriction.
If you are asking to discuss our options with the forum before deciding on a direction we can certainly do that but we are not at that stage yet. We first need to explore all our options.
Thanks.
Hi Shelley,
thanks for the clarification. One thing that makes the whole behavior really hard to handle is that there is no reliable way to detect if there is a function somewhere in the call stack - preventing the possible use of WAIT-FOR. Some have suggested to parse the call stack, but as I've demoed earlier around here is that with polymorph methods a method with the same name might exist in a class defined as VOID foo () or LOGICAL foo (pcChar AS CHARATER). The PROGRAM-NAME function won't tell you which of those is in our stack.
The STOP condition raise is almost impossible to CATCH in a usefull way. Especially as it's not the block the executed the (illegal) WAIT-FOR statement is receiving the STOP condition, it's the block (far down in the call stack) that contains the UDF/non-VOID method that is receiving the STOP condition.
A SESSION attribute/method that tells me if I can do a WAIT-FOR might be a short term solution:
SESSION:WAIT-FOR-ALLOWED() returns LOGICAL.
Then I'd know if I can use my beautiful message dialog or the old message box.
This is really an issue when building framework components used by customers. I cannot foresee in which context my customers use our objects making a reliable error handling (including dialogs that contain CANCEL or RETRY options) etc.
Mike
Hello Shelly,
schase schrieb:
We know that this limitation is tough to work around. We have identified the "problem" and are looking at ways we could allow this in GUI for .NET. We will keep you posted on our progress.
Thanks.
i am still waiting for a solution from your side, is there any chance this year?
I assume (hope) that you will deliver with 10.2B a version where i can use SHOW-DIALOG in a way as in any other .NET languages (C#, Delphi, ..)
If not please tell me a date for a fix or a working workaround (i don't mean not only calling with void functions/methods).
Regards,
S.Marquardt
hagebau dd
Not to beat a dead horse...
I just ran into another strange occurrence of this issue.
I've created a base class for the UltraGrid. In the base class, I created an override of OnBeforeExpand. In this method, based on some conditions, I needed to display a dialog. When I tried I got the famed "Input blocking statement is invalid..." error message even though the OnBeforeExpand method returns Void.
If I subscribe to the BeforeExpand method instead, either inside the base class or outside from the containing form, it works fine. My assumption is that somewhere inside of the Ultratree class, the method stack utimately calling OnBeforeExpand must contain a non-void return value.
Food for thought.
JL
Since it is almost 8 years, what is the status on this limitation?
Huh? This has been fixed since version 11 or 10.2B using -IOEverywhere 1 (the default in 11).
Is this documented? It's not yet part of the Help.
Maybe I am interpreting the KB wrong, but the KB reads that in 11 and up, you specify -IOEverywhere 0 to turn it off otherwise the default is on.
Which is exactly what Laura wrote. -IOEverywhere 1 is the default from 11.0 on. From 10.2B02 or 10.2B03 you could use -IOEverywhere to activate the at that time undocumented fix.
Well, we are in 11.6.2.008 and seeing the issue. Is it possible that overridden ProcessCmdKey is not supported?
Can you share details about the code? And the error message?
|
My control raises an event TabApplied inside ProcessCmdKey. The handler will eventually call a .w using WAIT-FOR (dialog-box). I get the 'Encountered an input-blocking statement while executing a user-defined function or non-vloid method: 'ProcessCmdKey' that is invalid within the current runtime context.'
Here is the method override code:
METHOD PROTECTED OVERRIDE LOGICAL ProcessCmdKey( INPUT-OUTPUT msg AS CLASS System.Windows.Forms.Message, INPUT keyData AS CLASS System.Windows.Forms.Keys ):
IF Progress.Util.EnumHelper:AreEqual(keyData, System.Windows.Forms.Keys:Tab) AND
THIS-OBJECT:ByPassTab THEN
DO:
THIS-OBJECT:TabApplied:Publish(THIS-OBJECT, NEW System.EventArgs(), "TAB").
RETURN TRUE. /* processed */
END.
ELSE
RETURN SUPER:ProcessCmdKey(msg, keyData).
END METHOD.
We will need more information. The code above looks fine but now we need to look at the code that does does the wait-for and the frame it is waiting on. If it's really a dialog-box, then it should work (unless there is a bug that we are not aware of).
This is the code inside the main-block. This will display a non-modal window.
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
RUN enable_UI.
IF NOT THIS-PROCEDURE:PERSISTENT THEN
WAIT-FOR CLOSE OF THIS-PROCEDURE.
END.
Well, I completely missed the title regarding DIALOG-BOX. So non-modal window is still off limits?
Sorry, there is still one case that you cannot do. That is using a new WAIT-FOR for a non-modal window when there is already a .NET form on the screen with its own WAIT-FOR and doing this when there is a non-void method or function on the procedure stack. If that is what you're doing then you will get an error. And as Fernando said, if it really is a dialog box then it should be allowed and you should log a bug.
Regarding non-modal windows, we have been telling people for many years that their should only be one WAIT-FOR for all non-modal windows. DIalog boxes will always have a new WAIT-FOR, but otherwise there should only be one. With the introduction of .NET this became even more significant. .NET has the same rule, but they actually enforce it! This puts limitations on what we can allow.
So this means all non-modal windows can only be run as persistent from a call stack with non-void method.