I have a page that programmatically shows a popup in a backing bean method. The popup asks the user a Yes/No question, and the subsequent logical path followed is determined by their response. However, whether the popup is shown or not in the first place is conditional. Also, there is additional logic in the original method, outside of the popup logic, that must be completed.
The issue with this is that ADF seems to spin off the popup into another thread, and keeps executing the logic in the original method simultaneously, while waiting for the user's response. However, the desired effect is that the program halts until the user has answered the question in the popup.
I haven't been able to figure out an elegant way to make this to happen. Ideally, I think the solution is to encapsulate the logic that occurs after the popup is shown (or not shown) in the original method, and call it from the popup's action listener if the popup is shown (otherwise call it from the original method). However, the logic to be encapsulated requires the use of some local variables that were set before the popup was shown. There's no way to get these values to the popup's action listener method in order to pass them to the encapsulated logic (aside from creating global static variables in the bean, which seems like a poor solution).
Another idea I had was to bump up the "show/don't show popup" logic to the task flow. However, it seems that doing this for every single popup would make the task flow really complicated.
Is there a better way to do this? It must be a common issue, and it seems that I'm going about it all wrong.
ETA: I have tried setting the popup's ContentDelivery property to "immediate", and the af:dialog component within the popup so Modal is "true". Neither has produced the desired behavior.
This can't be achieved with a server-side web framework.
For ADF, you will have different events for each lifecycle:
1 - popup opening :: popupFetchListener event
2 - click on OK, Cancel buttons ::DialogListener event
3 - hit Esc button :: popupCancelledEvent
You can share data between these events either on pageFlowScope, or viewScope.
But if you use ADF BC, you may be better off using transient attributes on View Objects.
Related
From a production application, we notice that our WPF buttons fire the ICommand.Execute method twice on fast double click.
Now, on every Command, the application is covered with a full-screen spinner animation, preventing any further interaction with the application.
This github repo contains a minimalistic repro of the issue. Note that:
when the Button's Command fires, the "IsBusy" flag is set to true
as a consequence, the BusyIndicator overlay will be shown
as a consequence, the Button cannot be pressed again until after 300ms
However, especially on slow computers, when fast double-clicking (really fast, like gaming fast that is), it is possible to fire the command twice without the BusyIndicator blocking the second call (this can be seen if the output shows 2 'click' lines right after one another).
This is unexpected behavior to me, as the IsBusy flag is set to true right away on the UI thread.
How come a second click is able to pass through?
I would expect the IsBusy Binding to show the overlay on the UI thread, blocking any further interaction?
The github sample also contains 2 workarounds:
using the ICommand.CanExecute to block the Execute handler
using the PreviewMouseDown to prevent double clicks
I'm trying to understand what the issue is.
What work-around would you prefer?
Diagnosis
This is only my guess and not a solid and confirmed info, but it seems that when you click the mouse button, the hit-testing is done immediately, but all the mouse related events are only scheduled to be raised (using the Dispatcher I presume). The important thing is that the control that is clicked is determined at the time the click occurred, and not after the previous click has been completely handled (including all UI changes that potentially follow).
So in your case, even if the first click results in showing the BusyIndicator covering (and thus blocking) the Button, if you manage to click for the second time before the BusyIndicator is actually shown (and that does not happen immediately), the click event on the Button will be scheduled to be raised (which will happen after the BusyIndicator is shown), causing the command to be executed again even though at that point the BusyIndicator will possibly be blocking the Button.
Solution
If your goal is to prevent command execution while the previous one is still executing the obvious choice is to make the Command.CanExecute result depend on the state of the IsBusy flag. Moreover, I wouldn't even call it a workaround, but a proper design.
What you're facing here is a clear-cut example of why you shouldn't make your business logic rely on UI. Firstly, because rendering strongly depends on the machine's processing power, and secondly because covering a button with another control by far does not guarantee the button cannot be "clicked" (using for example UI Automation framework).
On some of my Forms, I register a sensor listener when I open the form, using the onShow() method. I want to deregister those listeners when I go to a different Form.
I found the onShow() method for anything I need to do when a Form is shown, but I don't see an onHide() method or any method I can use for a Form to clean up after itself. I could put the cleanup code in the navigation commands, but they really belong to the Form. Is there a method I can use that I overlooked?
Normally you don't need to be aware of exiting a Form unless you are in a GUI builder application where navigation might be implicit. Since you always call newForm.show() implementing logic required for exit can be done there.
However, you can always override deinitilize() to do this. Notice it might be invoked when you are showing a Dialog so initComponent() might be a better counterpart than onShow().
Notice that this only applies to the visual aspect of showing a Form. You will also need to implement logic in your stop() method that is invoked when your app is minimized and in the start() method which is invoked when the app is restored (both in the main class of your app).
I'm working on an application on Windows Phone, and I am using silverlight.
I have some bugs where the user can quickly press a button twice, which will effectively do 2 WCF calls since the action is called 2 times.
The obvious solution is simply to disable the button until the call completes but I'm wondering if there's a more global solution where I wouldn't have to implement this for every action. My application uses about 50 WCF methods so it would be tedious to implement this for every single action/every screens.
There's also the situation where users can click the phone back button while a call is running and start clicking on other buttons etc...
Anyone know a clean solution for this?
Simple solution: use a boolean variable that will be set to true after first click and to false when result from server has arrived back. In click handler just check the value of this variable, if it is true do not call the service again.
Are you using a design pattern like MVVM in your application? If not, you probably should.
In this case you could create a bool property called IsIdle or something like it. Then just set <Button IsEnabled="{Binding IsIdle}".
Now whenever you start doing an asynchronous call, set IsIdle to false. This will disable the buttons. When loading is finished set it back to true, so all the buttons are enabled again.
This might not be very elegant, but I think it would prevent any input without creeping all over your views and code.
You could prevent input by temporarily overlaying a transparent rectangle over your screen with IsHitTestable = true. You could write a small utility method to push that rectangle on any of your screens and remove it when you want to restore input.
You could also use that screen to eventually show something like a busy indicator when the network is slow.
I am making an asynchronous call to a web service. Since it might take a few seconds there is a status Label used to let the user know what's going on. But even though the call is async the first call seems to block for a few seconds and the status label takes too long to get updated. In WinForms I could force the label to refresh (using Update() I think) but not in WPF. Any super easy ways to get this working?
Thanks,
Gerry
You could move the entire call logic into a QueueWorkUserItem or BackgroundWorker block. That way the first proxy initialization would not block the UIThread (before the async. Begin/End pattern kicks in). Assuming that you are using databinding the object exposing the property bound to the Label implemented INotifyPropertyChanged everything should happen automagically.
I'd (wildly) guess that the blocking is due to the creation/initialization of the service proxy classes. If so, you could try to create the proxy earlier, or call your asynchronous web service in another thread.
The general answer to your question about refreshing controls... I have always relied on data binding to do this. That won't help though if the main UI thread is stuck doing something. And if the UI thread is stuck, I don't know that there's any way to get it to draw.
There isn't a way to tell the label to refresh that will actually work in your case. If the UI is being blocked, it won't refresh. Basically, when you actually get to the point where you update the label's text, it will show in WPF. The only possible exception that I can think to that would be if you are using a non-WPF control but even then it should work.
My suggestion would be to update the label before you perform the first action (even before variables are initialized, since this might be where the issue actually is). Here is a pseudocode example of what I mean (just in case I wasn't clear):
private void KickOffProcess()
{
label1.Text = "Processing ..."; //This is where you need to move the label update code
AsyncCall();
}
I am new to Windows programming, as in my previous work I've mostly been involved with web technologies, and mostly in the backend. I have inherited a Winforms application, and one of my biggest nightmares is navigating through the endless states a form can be in.
To give you an example, a form has the state 'New' and 'Edit' depending on whether the user decided to Add or Edit a record. On this form, we have logic. If this texbox has a certain value, then these other textboxes are disabled, etc. This leads to endless chaining of these rules. So, a textbox's TextChanged event will influence another field. It in turn will fire X event that changes the state of other controls. It quickly devolves into a tangled mess that is impossible to maintain.
There has to be a better way... something simple and elegant that solves this problem. Any suggestions?
What I do is to have a single method called FormatControls(). In this method, I implement all the logic such as myTextbox.Enabled = mycheckBox.Checked and so on.
I call this method from my event handlers in the form, such as on checked changed, etc... I also call it when appropriate (ie, form newly loaded with no data, record loaded from database, etc). This has suited me well for many years now, it makes everything less complex.
You are correct, if you do not have a pattern in use it can turn into a too-complex thing.
You can try to use tha Application.Idle event to perform the enable disable logic and insulate this part from the business logic part.
Depending on what controls you have on your form, you might be able to do away with the separate textboxes and add/delete buttons and replace the whole works with a DataGrid.