I have an application which displays a disclaimer page when it is first run. Once you select Accept or Deny you never see the page again.
However, when you press the back key attempting to close the application after the first run, you go back to the disclaimer page, then if you hit it again, back to the main page and then again to exit.
This only happens the first time the application is run, but I would like to have the application ignore the disclaimer page when the back key is pressed and exit the application.
Other than forcing an unhandled exception error to close the app, are there any other options?
Thanks in advance.
Solution: Add the below NavigationService.RemoveBackEntry(); in my main page.
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
NavigationService.RemoveBackEntry();
NavigationService.RemoveBackEntry();
}
I am sure there is a more elegant way to do it, but I was in a hurry, so I implemented it in a following way.
I have a static global enum that stores the last page I was on. Assuming you have pages called pgDisclaimer and pgMain.
In the OnNavigatedTo event of the pgDisclaimer page, check to see where the control came from. If it came from pgMain, just execute NavigationService.GoBack() and you'll be out of the application and the user will never actually see pgDisclaimer page (not even a flicker).
Edit: Found the more elegant way. In Mango, you can use the horribly named NavigationService.RemoveBackEntry() method.
You should display the Disclaimer as a popup rather than a page, that way you don't have to worry about navigation and backstack issues. I saw this mentioned in a Channel 9 video:
Windows Phone: building apps that customers love, end to end
The specific part in the presentation that covers this is at around 26:20. He's discussing a login page that prevents a user from navigating back out of the app, but the concept is similar.
Also, from this MSDN Blog Post:
I forgot the #1 piece of advice regarding EULA / Login screens - don't make them into pages. If you instead make them Popup controls you can show or hide them at any time (on first navigation; when the user hits a "protected" part of the app; after a time-out; etc.) and they don't consume a slot in the backstack. This should cover the majority of cases.
Related
I have an ASP.NET 4.5 web form running C# code behind on a server. A specific form often takes some time to finish while it updates and changes various database records. However, if the user closes the tab or tries to reopen the web form, it will try to check the users status in the database and fail when those later change due to the first running process.
The need is to track this specific instance of the process and user, and if it is still running, prevent the page from loading fully or redirect. I was hoping to find and store some user and process information on a cookie and then simply check for this each time on page_load. I was not able to find these variables/properties.
Am I going about this the right way, and if so, how can I accomplish this?
Thanks!
I was not able to find the exact solution I was looking for. At the moment, I cannot see any way to find a server side identification id of the process.
Instead, I referenced How to tell if a page unload in ASP is a PostBack and made it so that the page would warn when being unloaded before the confirmation screen is shown. As long as the form opens to the same named tab, the user would be given the warning screen and given a confirmation before they could close or reload a new web form instance.
I am having a very difficult time trying to debug/fix an application.
Briefly:
- I created a "wizard" type app that starts with the user taking a photograph (using the common dialog for photos)
If the user tries to use the text input window (SIP) (the little keyboard input window) after a photo is taken the event loop seems to hang - the event is not processed or is delayed for a while.
If the user does not take a picture the SIP keyboard works great.
This only happens on some of my devices. Specifically it is not a problem on an MC65 but is a problem on an ES400.
It appears that the app's event loop gets screwed up with the way I am displaying forms and taking photos.
If created a simple test app with single form containing a button (Event handler takes a photo) and a text box that accepts input. That works fine. But it is only a single form app that does nothing else.
When I combine the photo taking with my form displaying (making a "wizard" ) things go badly.
I wonder what kind of event loop should I be running?
Essentially the user takes a photo then goes through some forms (I hide one form and show another when they click the "next" button.)
The Form.Show is called from the main form after a picture is taken and then I have something like:
while(UserNotFinished)
{
Application.DoEvents()
}
Where UserNotFinished is a flag set from my wizard/forms after the "submit" button is pressed.
I will be happy to provide more code but not sure what would be useful.
I am new to C# and CF development (lots of years of C++/Win32)
The real confusing part is that this works on one device but not on another. In fact, the device hangs completely. It ends the activesync connection and sometimes I have to hard reset by removing the battery.
I think your problem stems from the while(true) { DoEvents(); } and perhaps how you are trying to go between forms. The only time I've used the DoEvents() method is when I'm already in the scope of a windows event and I need to be sure something in the message queue is processed so screen updates are correct. I'd suggest making a controller class to manage the screen flow for your wizard. You can control the screen flow by either using ShowDialog() and execute the flow control directly in the scope of a single call, or you'll have to use Show() and an asynchronous mechanism such as subscribing to and handling specific form and control events in the controller class. Also saw the comment about introducing another thread, beware that Forms belong to the thread they were created in and you must Invoke(...) all Form members in the context of the creating thread.
Hmm. Very strange
I started a new thread and basically call Application.DoEvents() in in as well and it seems to fix the problem...
I don't know why the
while(true)
{
DoEvents()
}
in the main thread doesn't work.
Msdn doc for IsolatedStorageFile.IncreaseQuotaTo states that:
To increase the quota, you must call
this method from a user-initiated
event, such as in an event handler for
a button-click event. When you call
the IncreaseQuotaTo method, the common
language runtime in Silverlight
presents a dialog box for the user to
approve the request. If the user
declines the request, this method
returns false and the quota remains
the same size.
How does Silverlight know that the method was called from a user-initiated event like a button click and not from some other thread?
More specifically: What is a user initiated event? Is there any way to overcome this limitation?
And another question:
I do some automatic downloads of files when user first accesses my application, but I don't want the user to press "Download" and then when I detect more space is needed call IncreaseQuota and have the "Silverlight dialog" appearing asking for more space.
I want to start the download automatically (not user initiated), and if I detect more space is needed, call IncreaseQuota and hence have the "Silverlight dialog" appear. (No user pressing download).
After much digging, I did find out what a user initiated event is. Seems that msdn doc specifies what a user initiated event in the section related to "events overview", but there's no link between documentation of IsolatedStorageFile.IncreaseQuotaTo and Events Overview
So a user initiated event according to the definition is:
Silverlight enforces that certain
operations are only permitted in the
context of a handler that handles a
user-initiated event. The following is
a list of such operations:
Setting IsFullScreen.
Showing certain dialogs. This includes
SaveFileDialog, OpenFileDialog, and
the print dialog displayed by
PrintDocument.Print.
Navigating from a HyperlinkButton.
Accessing the primary Clipboard API.
Silverlight user-initiated events
include the mouse events (such as
MouseLeftButtonDown), and the keyboard
events (such as KeyDown). Events of
controls that are based on such events
(such as Click) are also considered
user-initiated.
API calls that require user initiation
should be called as soon as possible
in an event handler. This is because
the Silverlight user initiation
concept also requires that the calls
occur within a certain time window
after the event occurrence. In
Silverlight 4, this time window is
approximately one second.
User-initiated event restrictions also
apply to usages of JavaScript API for
Silverlight.
When Silverlight is in full-screen
mode, some input events are
deliberately limited for security
reasons, although this can be
mitigated for out-of-browser
applications using elevated trust. For
more information, see Full-Screen
Support.
Although I don't see "IncreaseQuotaTo" inside the list of "operations", I'm guessing they just forgot it, since the behavior/limitations are the same as the ones described in the doc.
I was curios how exactly does silverlight know what a user initiated event is but after digging through .net framework source code I've got to a dead end:
if ((browserService == null) || !browserService.InPrivateMode())
{
//..
}
return false; //means that IncreaseQuota will fail
where browser.IsInPrivateMode is:
[SecuritySafeCritical]
public bool InPrivateMode()
{
bool privateMode = false;
return (NativeMethods.SUCCEEDED(UnsafeNativeMethods.DOM_InPrivateMode(this._browserServiceHandle, out privateMode)) && privateMode);
}
where DOM_InPrivateMode is in a DllImport["agcore"] which according to microsoft is confidential :(
So it looks like I won't find out soon how they're detecting user initiated events.
Thinking it more about it, I guess microsoft didn't want a user to have many tabs open in a browser and then poof: I call automatically IncreaseQuotaTo.
The IncreaseQuotaTo is a browser modal dialog. This means you can't navigate to other browser tabs while is active.
So if the user has now moved from my page to the tab with google.com, and if I would be able to call IncreaseQuotaTo with a delay, the user might think that google.com is asking for more storage :).
This would be a security breach indeed.
Had they implemented this with a page level dialog, then that would have been probably more easily hacked (or worked around).
So all in all, thinking of it, I'm starting to see why they implemented it like this and why these limitations exist.
The documentation isn't incomplete.
If I do this... button_click(..) { new UserControl() }... Does this still count as a user initiated event?
Yes. But what has that little bit of extra code really achieved?
What i've personally never experimented with is exactly what consitutes a user event; IOW is a mouse-over considered a user event? This will be very simple for you to try, and there are a multitude of other things you can experiment with. If necessary you could have a splash screen popup that welcomes the user and they have to click on it to dismiss it, at which point you make the request. It may seem a bit corny, but you can get away with things like this if you present it well.
Note that the prompt is a one-time thing. If you prompt the user and they accept, that storage is persisted for your application between visits, which means you don't need to prompt them again the next time they use your control, your quota is still increased from last time (unless the user has deliberately deleted it, which they can do by right clicking on the Silverlight control and then going to the Application Storage tab).
I'm writing a web-based application for internal use within the business where I work. It's a fairly complex application, with a lot of forms that will allow the user to view and enter data, which once saved will be stored in a database.
One thing I'm anxious to avoid is allowing a situation to exist where a user might enter large amounts of data in the browser, and then (either deliberately or inadvertently) navigate off the page without saving the changes. To this end, I have already implemented an entry page which opens up a new browser window in which there are no navigation controls at all; only what is provided on the web pages themselves.
However, there are two potential ways in which a user could still lose data:
The browser Close button is still enabled, and a user could potentially lose work by clicking it inadvertently. I can probably live with this, as it falls at the extreme end of helping the user not to shoot himself in the foot.
In Internet Explorer (and, apparently, in Firefox) the Backspace button works like a Back button. I only discovered this accidentally, and have as yet been unable to find a simple way of stopping this behaviour. This is potentially a problem, as an inadvertent use of the Delete key (e.g. having positioned the cursor in a read-only textbox, or when the cursor isn't on any particular field in the page) will navigate off the page.
What I would like to do, as a minimum, is prevent Backspace from navigating off a page if that page has any user-writable fields on it and any of those fields have been changed by the user since the form was loaded. Ideally, I would like to disable this particular use of the Backspace key completely, while the user is logged into this web application. The two possible ways that I can think of, for achieving this, are: (1) clear the browser's history as each page is loaded, or (2) trap the Backspace key and only allow it to work if the cursor is positioned within a field whose text can be changed (e.g. a textbox).
Can anyone suggest how I could achieve either of these things? The solution needs to be programmatic, rather than something that has to be manually configured on every browser in the company.
Instead of blocking* functionality that your users have learned to expect in their daily activities at work and at home, why not work with it? Make the "back" button actually take them to the previous screen as expected, and use AJAX to silently save the form as they fill it out (say, every 5 or 10 seconds), so when they return to the form you can check to see if they already have partial, unsubmitted values saved and reload them.
This approach aligns with the realities of web-based applications and delights users if implemented well. An alert that says "you did something wrong" just frustrates users and makes them trust your application less. Remember - users almost never do the wrong thing. It's our applications that aren't aligned with usage.
* more like trying to block functionality. As you've discovered, people who designed the interwebs and web browsers never really intended for site developers to totally disable moving back and forward in the navigation history.
What about something like this? You can ask them if they are sure before they leave.
var changes = false;
window.onbeforeunload =
function()
{
if (changes)
{
var message = "Are you sure you want to navigate away from this page?\n\nYou still have unsaved changes.\n\nPress OK to continue or Cancel to stay on the current page.";
if (confirm(message)) return true;
else return false;
}
}
You should look at the Javascript's window.unload event.
This is fired when the use tries to leave the page. You can't totally stop them leaving the page, but you can give them a chance to cancel.
try this
window.onbeforeunload() {
return "Are you sure you want to navigate away?";
}
So long story short, the company I work for, that is all about saving money, went from 1 service application, to 2 service web interfaces.
They're not secure, have no cert's, not even over SSL...yet, they have a timeout associated with each interface. Which then breaks the page you're viewing, and you have to refresh IE, and then proceed to login again, and reset your dropdowns etc...
So.
I've tried using a generic webbrowser interface in C# to have a foundation in which I can refresh the connection to the server with the page open, as to avert the timeout.
But, first attempt results in my app, going to the appropriate page, then opening a new IE window when a service ticket is opened, and there must be a lack of cached data, which results in the new IE window that opens, to revert back to the main page which prompts me to login.
The interfaces are Jsp, but I'm more familiar with c#...
Tried catching link clicks to navigate the destination in the current window, but it seems that the data you double click that prompts the new page to open, is merely a data in a table, and not technically a "link"....
I've brought this to the attention of management, but like most huge corporations, I know nothing, and they never have to deal with it, so as they say in every meeting, "silence means compliance"....
Any thoughts?
Probably not the right answer, but...
Session cookies?
Session cookies = fail..
No 'remember me' option...
I can however enter a link in each browser to "goto the home" section of each app, which each page is already at, so it keeps the connection alive, and doesn't navigate away from the current page (keeping the dropdowns etc that are set after login)
But still, the above problem exists where if I use all this in a C# browser, etc...
I told my boss first thing 'they can't tell me the timeout is for security!' heh
And I still didn't get a positive answer from 'well at 10 seconds per re-logon, per x amount of people = thousands of dollars a year spent on re-logging on...'
:D
Use ajax.
poll a server page in a small interval (a minute)
if it returns "timeouted=true" (or whatever convention you like), refresh the page with javascript.
include the ajax snippet on every page (using <jsp:include>, for example)