We have a WPF app (actually a VSTO WPF app). On certain controls there are multiple elements which, when clicked, load data from a web service and update the UI. Right now, we carry out these web requests synchronously, blocking the UI thread until the response comes back. This prevents the user clicking around the app while the data is loading, potentially putting it into an invalid state to handle the data when it is returned.
Of course the app becomes unresponsive if the request takes a long time. Ideally, we'd like to have the cancel button active during this time, but nothing else. Is there a clever way of doing this, or will we have to switch the requests to execute asynchronously using backgroundworker and write something that disables all the controls apart from the cancel button while a request is in progress?
edit: for actions we already expect to be long running (downloading a file etc.) we pop up a progress dialog window. The case in point is when you expect the action to be pretty fast (a couple of seconds at most) but occasionally take longer. In those circumstances, flashing up a whole window for a moment is a bit too distracting.
Your clickable controls should be bound to commands, and the commands should have CanBeExecuted return false when a background task is in progress. If you do this, the controls bound to those commands will automatically disable and enable themselves.
You can avoid duplicating a lot of code by creating a command class that implements the background-task-in-progress check, and then deriving all of your commands (except the cancel command, of course) from this class.
While you make your Asynchronous request on a seperate thread, show a Modal Dialog box with a Cancel button (and maybe a progress bar or some other activity indicator).
That way the user can't interact with the underlying UI and they still get feedback that something is happening...and the ability to cancel it.
One way would be to put a translucent canvas over the parts of the UI which are not accessible while waiting for the response and in the center put a message with a cancel button.
The Silverlight Toolkit has a BusyIndicator control. The toolkit is open source so you might easily be able to port it to WPF.
It disables and greys out everything in the area that it's assigned to when setting its IsBusy property to true either in code or by binding it to a model. Usage is as follows:
<ctl:BusyIndicator>
<StackPanel x:Name="myDataArea">
<Button Content="Load Data" />
<DataGrid x:Name="myDataGrid" />
</StackPanel>
</ctl:BusyIndicator>
I can't think of easy way other than disabling all controls except for "cancel".
Having said that, it might give a better user experienced if you displayed a "working" or progress dialog with just a cancel button.
You could use this dailog to display useful information about the progress of the web requests and any error messages that might come back.
Related
First things first, this problem only happens while working in Citrix XenApp seamless mode (which, in simplest of words means the actual app is running on some citrix host but it is simulated as residing in your own desktop). I will take this up with Citrix Support as well but just wanted to poll the group in case someone faced a problem like this before.
I have a WPF app which uses Winforms NotifyIcon to reside in system tray until mouse clicked. In Citrix seamless mode, as user clicks the icon in system tray, the popup flashes and immediately closes on its own.
The Popup window is a vanilla one created with StaysOpen as FALSE and same works in every other environment.
Any suggestions ? This is what I've noticed so far:
The window stays open if I use StaysOpen as true. But then I don't have a way to close the window manually when it loses focus. LostFocus Event doesn't get fired on popup when user clicks outside.
In citrix seamless mode, the MouseEnter event is captured but MouseLeave is NOT so the approach of closing the window if user mouse is outside the window for X secs is not achievable.
Tried the workaround of starting the popup with Staysopen as FALSE and then reset staysopen after like 2 secs so that the pop sticks. It works but a soon as I set StaysOpen as FALSE once the timer is hit, the pop up closes on its own.
Without all these workarounds, if a user quickly clicks (leftclick) on the window before it disappears, the pop up sticks so I tried few ways to simulate the mouse click on the popup as it opens up but that doesn't cut it either.
Thanks
I can't help you with specific advice for tweaking your app to work around the issue, however there is always the hit it very hard with a hammer approach, i.e. tell consumers of your app to disable seamless for your application:
http://support.citrix.com/article/CTX116357/
Update: I pinged the original seamless dev - he said it sounds like a bug where seamless is not correctly routing all the necessary mouse messages between client and server. He said the best way to diagnose this was to run the Spy++ tool on the XenApp server and on the client, and then compare the messages each side sees to identify what messages are not getting translated. Since it sounds like a genuine bug, your best bet is to raise a support ticket with Citrix support and provide them with a sample app that can repro the bug.
I'm using the Navigational Framework in Silverlight 4. I'm starting to believe that this was a mistake as the browser buttons are really screwing things up for users. For instance, when a child window is opened the user believes they can close the window by pressing the back button. It doesn't close the window obviously, it just navigates the parent page back a step. The end result is a messed up data set. I'm fed up with the little control I have over the navigation of my application; forward and back buttons are anachronistic. Web applications don't work that way anymore. Please someone tell me how I can disable their functionality; that is, cancel navigation when it is started from one of these buttons.
Remove this code from your html page which holds your silverlight XAP:
<iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe>
This is the history frame.
You will likely have to do this in the actual web/asp.net page, as Silverlight has no real control over the browser.
Some workarounds in this article:
http://lennilobel.wordpress.com/2009/07/26/defeat-the-evil-back-button-in-your-asp-net-applications/
I wouldlike to embed a webbrowser in a WPF application. The browser should look like a normal browser, with address bar, back and forward button and status bar. Is there a way how that could easily written in XAML, with a direct databinding of the address to a textbox, with a direct routing of events from the buttons to the webbrowser object, and the enabling back?
Why not?
Here and here are uploaded some screenshots from our application which has WebModule inside and is able to work like browser.
In our implementation we used Windows Forms WebBrowser control as browser engine and MVVM as communication pattern. Model has navigation commands (forward, back, ...) that raise proper events. View is handling this events and delegate requested actions to inner WebBrowser component. Additionally view is handling WebBrowser's events (NewWindow, DocumentCompleted, Navigating, Navigated) and setting up model's state.
Model and view together contain about 500 lines of code (I don't think it's very much, do you?).
Of course, I should mention, that due to using IE engine this browser could have some problems on complicated web-sites.
P.S. We didn't use System.Windows.Controls.WebBrowser because it does not provide access to NewWindow event.
P.P.S. I've posted this answer from browser in our WPF application. Good luck!
is there a best way to manage a form in WPF application which has asynchronous execution commands?
1) Suppose you have a form where user
enters all his data and clicks on Ok
button to save changes.
2) Your WPF app starts an asynchronous
method to record those data.
3) Now suppose the database server is
down, and the operation is taking
about 15 seconds to get finished. At
this time, user has already closed the
WPF form (he did not wait for the
transaction to be finished).
So that's my question: how could you control when to let user close or not the form?
thank you
Easy answer...don't let the user close the form until the operation is complete.
You can accomplish this with a Modal infinitely scrolling progress bar. It provides feedback to the user that your application is doing something...but doesn't let the user close the window they were working in.
This allows you to run your code outside the UI thread and then when your code completes (either finishes or errors out) you can provide feedback to the user about what happened (either success or something happened and they need to save again).
I would suggest that you disable the controls in the form when the asyncrhonous operation is started. This provides immediate feedback that the state of the form has changed. However, if the operation can be cancelled you should still allow the user to cancel/close the form. Closing the form should then cancel the operation.
If you expect the operation to take longer than a few seconds you should display some sort of feedback like a progress bar. Cancelling the operation should then be on a control visually associated with the progress bar.
Please don't show useless modal message boxes when the operation completes successfully. It is really annoying to not only have to wait for the operation but to have to click on "OK" when the operation is complete.
David Poll has created an Activity control for Silverlight that you might get some inspiration from.
I have an application that will mainly operate in the background. I want certain system events that it handles to cause the app to steal focus from the foreground app, whatever that is. But UIElement.Focus() seems to only set the focus within the WPF app. That is, if the WPF app already has the focus as a whole, then Focus() sets the focus to the right control. But I need to steal focus from another app and put it on my app. How can I do this?
I do not want a system modal dialog. That is, after the window steals focus, it should be possible for the user to immediately switch to another app without dismissing my app's window.
The app may already been in a restored, minimized, or even "minimize to tray" state when it needs to steal system focus. So assuming that it is minimized and stealing focus while restoring the window is not acceptable.
If you don't mind doing som p/invokes, the SetForegroundWindow function should be able to help you:
http://pinvoke.net/default.aspx/user32/SetForegroundWindow.html