In my first WP7 App, I have all resolved (with MVVM pattern) except for recovering the App from inactivity. I have a main screen with a list of database ítems and a field for each one that, depending on a value and the actual day, shows one value or another (not a calendar, but the same problem).
If the user goes home and, the next day, resumes the App, the calcs must be done again, to refresh the contents. Also, in a second screen happens the same: what it shows depends on the day it is.
How can I detect the activation (I know it is on the Application_Activated function, but don't know how to use it) and refresh all that I need (a refreshInterface function in my second screen, if the user leave the App there, and the main list in the main screen).
I don't need to save nothing in deactivation, just refresh data on activation only.
In your page's OnNavigatedTo method you can subscribe to Application.Activated event (don't forget to unsubscribe in OnNavigatedFrom). In the event handler you can then update the viewmodel.
Related
I have a problem with a Windows Store app.
I have a view; on this view I display data that can be modified in this view.
Once the user finishes modifying the information, they have to click on a "Finish" button to store in a database the information.
But when there is too much information to store the treatment takes a long time and the UI is open to user actions. If the user makes an action, my application throws an exception because data were not present any more for the control.
So I searched for a way to block the UI (like a messagedialog: Wait while your data is being stored). I tried with a message dialog, but once I tap on yes my storage method is launched and the message dialog is directly closed, so the user can create an exception with his action.
My question is: how to block the UI while doing a treatment in Windows Store apps?
You can do the trick by adding the Grid on whole page content with, for example, ProgressBar. Then show it when you perform long operations and you want to avoid user interactions with the app. When operation finished, just change state of your page (hide Grid from the top).
The other way to do it, if you don't have a lot of elements of UI to block, is to set IsHitTestVisible property of your Buttons and other clickable elements to false when you perform operations.
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.
I have a settings save method I call, but I tried unload, and lost focus the application will close out and not save before ever getting to either of those methods. When should I save application settings to keep this from happening?
Should I use a timer and save every 30 seconds, or what?
How often you save depends on your app. However, the key timings are:
Launching
Activated
Deactivated
Closing
Launching is called when the app is first launched from the main screen and Closing is called when the user presses the back key to exit your app. Naturally, you'll most likely want to save permanent data in the Closing event.
Activated is called when the user has closed your app via the Windows button and has gone back into it by pressing the back button. This doesn't get called if the user launches the app for the first time.
Likewise, the Deactivated event is called when the user presses the Windows button. Depending on your app, you'll want to save transient data at this point so that when it's restored, you can give the illusion that your app wasn't closed at all. (Otherwise, for example, all textboxes will become empty even if the user entered data before pressing the Windows button).
Those are the main events, so you can design your app around that. One thing to remember is that if your save files are going to be big, and they take longer than 10 seconds to save after the closing event is called, your app will be terminated immediately, possible corrupting the save file. Therefore, for large saves files, you should plan ahead by saving incrementally (for example, after the user has made a change that should remain permanent).
There's no one size fits all solution to this as saving timings are highly dependant on the type of app being developed. Have a read of the Execution Model MSDN Page as it goes into more detail and provides code examples.
Here is a sample from MSDN on how to implement settings page for Windows Phone.
http://msdn.microsoft.com/en-us/library/ff769510(v=vs.92).aspx
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 know about tombstoning stuff any how to save the states of your application but my question is this regarding states.
Let's say I have a page that have 5 buttons. Whenever I click a button the button can be either visible or hidden. How do I save the current state or the saved state of my page? Let's say if I exit my application and loaded the 5 buttons again one button should be hidden.
I tried saving a variable state value in an IsolatedStorageFile and retrieve it when the Page is loaded in loaded event but I figured out that it's too tedious for the processor to do a lot of things just for saving a state.
Another solution I thought of is when the Loaded event is fired, I will statically declare an if else statements and manually declare the Visibility of the button.
Is there any other way?
Are you trying to do the same thing when the page/app is exited normally and when it's tombstoned? The default expected behaviour is that when launching the app after exiting (via the back button) the app will be in it's default state. When returning from a tombstoned state the app should (as far as is appropriate) be displayed to the user in exactly the same way as when the page/app was tombstoned.
Of course you may have differing needs but I wanted highlight the standard behaviour.
If you want to store state while tombstoned, the convention is to use the OnNavigatedFrom and OnNavigatedTo events to store details in the State object.
There is a good example of how to do this on MSDN: How to: Preserve and Restore Page State for Windows Phone
If you want to preserve state across all executions of your app then you will need to use IsolatedStorage to store the details in a persistent location. Where and when you read and write the data will depend on where the data you need to persist is located.
If it's at an applicaiton level you may be able to use the application level events (Launching, Activated, Closing & Deactivated). If you have state data at page level it's probably be better to do it in the page level (Loaded/Unloaded or NavigatedFrom/To as appropriate).
If you want to store state across all executions of the application you probably need to look at both of the above options.
The System.IO.IsolatedStorage namespace is fine for this kind of behaviour, check it out here
Also check out this article on how to do what you are asking.
Saving Applications States