Tombstoning the last visited page the user was on - silverlight

I want to tombstone the last page that the user was on and to retrieve it when the user comes back to the app. All of the tombstoning examples on the Internet deal with saving some data or the state of the page that the user has edited somehow (i.e inputed text in the textbox). In my app I don't have anything for the user to modify/edit so I just want to save the last visited page that the user was on. I tried to use some online examples that used PhoneApplicationService.Current.State but with no success.
Thank you to anyone who would like to help me out resolving this issue!

To locally store persistent data (data that should remain even when the user closes the app), you can use Isolated Storage.
So, in your app's Deactivated event, you can write the page's name to Isolated Storage like this:
//You get the Isolated Storage for your app (other apps can't access it)
IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
//if the file already exists, delete it (since we're going to write a new one)
if (isf.FileExists("lastpage.txt")) isf.DeleteFile("lastpage.txt");
using (var isoFileStream = new IsolatedStorageFileStream("lastpage.txt", FileMode.OpenOrCreate, isf))
{
//open a StreamWriter to write the file
using (var sw = new StreamWriter(isoFileStream))
{
//NavigationService.CurrentSource returns the current page
//we can write this to the file
sw.WriteLine((Application.Current.RootVisual as PhoneApplicationFrame).CurrentSource.ToString());
}
}
This will write the current page's name to the Isolated Storage. Then, in your OnNavigatedto method of your main page (the page that first opens normally) you can read the file name and navigate to it:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
string lastpage = string.Empty;
if (isf.FileExists("lastpage.txt"))
{
using (var isoFileStream = new IsolatedStorageFileStream("lastpage.txt", FileMode.Open, isf))
{
//read the file using a StreamReader
using (var sr = new StreamReader(isoFileStream))
{
//get the uri we wrote and then convert it from a String to a Uri
lastpage = sr.ReadLine().Replace("file:///", "");
}
}
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri(lastpage, UriKind.Relative));
}
base.OnNavigatedTo(e);
}
This should read in the file you saved and then convert the string into an actual URI that you can pass to the NavigationService.
You can then delete the text file after it's been read so that it doesn't always keep jumping to that page.

In addition you can use this for getting the page name ,string PageName = (Application.Current.RootVisual as PhoneApplicationPage).Name; for getting the current page name

While I agree all the above options are possible, they are not really the correct way of doing something within a WP7.
It's better to construct a navigation page at the start of your app for properly controlling navigation, it also helps with managing back key events while using the app and prevents hiccups.
See Here for one example of implementing this:
Properly Exiting Silverlight-based WP7
With this done use the advice on storing values in isolated storage / application settings to then just store the "Current Page" state value (e.g. value of Page.GamePage) then the app navigation will direct you accordingly.
BUT beware when just storing the current page itself as you also need to save the correct state of any values or User entered data on that page when it tombstones as well, this the above advice should lead you in the right direction.
Hope this helps

Related

Access Shared Preferences externally / Store a value into a new file and access it externally

I have the two following methods and I am using them to store a special value locally and be able to access it on application restart:
(Store value locally:)
private void SaveSet(string key, string value)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
ISharedPreferencesEditor prefEditor = prefs.Edit();
prefEditor.PutString(key, value);
// editor.Commit(); // applies changes synchronously on older APIs
prefEditor.Apply(); // applies changes asynchronously on newer APIs
}
(Read it again:)
private string RetrieveSet(string key)
{
ISharedPreferences prefs = PreferenceManager.GetDefaultSharedPreferences(this);
return prefs.GetString(key, null);
}
This works perfectly. Now is it possible to access and edit this Shared Preferences externally? Unfortunately, I cannot find any file when searching in folder
Phone\Android\data\com.<company_name>.<application_name>\files
nor anywhere else. I want / try to edit this value from my computer, after connecting the phone to it. Is this possible?
Alternatively: Can anyone maybe show me how to create a new file in the given path above, write/read it programmatically and how it stays there, even if application is closed / started again? So I can then edit this file with my computer anyhow?
I tried it with the following code, but unfortunately it doesn't work / no file is created or at least i cannot see it in the given path above:
//"This code snippet is one example of writing an integer to a UTF-8 text file to the internal storage directory of an application:"
public void SaveValueIntoNewFile(int value)
{
var backingFile = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "newFile.txt");
using (var writer = System.IO.File.CreateText(backingFile))
{
writer.WriteLine(value.ToString());
}
}
Would be very happy about every answer, thanks in advance and best regards
What you're looking for is where Android stores the Shared Preference file for applications that make use of it's default PreferenceManager.
I'd refer to this SO post which answers your question pretty well
SharedPreferences are stored in an xml file in the app data folder,
i.e.
/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PREFS_NAME.xml
or the default preferences at:
/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME_preferences.xml
SharedPreferences added during runtime are not stored in the Eclipse
project.
Note: Accessing /data/data/ requires superuser
privileges
A simple method is to use Android Device Monotor,you can open it by clicking Tools--> android-->Android Device Monotor...
For example:
The path in my device is as follows:
/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME_preferences.xml
And we notice three buttons in the upper right corner of the picture.
The first one is used toPull a file from the device,the second one is used to Push a file onto the device,and the last one is used to delete the preferences.xml file.
So we can pull the preferences.xml file from current device to our computer and edit it as we want, and then push the updated preferences.xml to the folder again.Then we will get the value of preferences.xml file .

Deleting file from IsolatedStorageFile causes "IsolatedStorageException: Operation not permitted" when lock screen image wants to update

When generating a lock screen image for Windows Phone 8.0 silverlight app, I use the following code:
fileName = Guid.NewGuid() + ".jpg";
using (var iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var isostream = iso.CreateFile(fileName))
{
Extensions.SaveJpeg(bmp, isostream, bmp.PixelWidth, bmp.PixelHeight, 0, 100);
isostream.Close();
}
}
This works absolutely fine both when I run the app or via the background task (assuming the lock screen setting is on).
I've recently added code that runs whenever I launch the app to delete previous lock screen images for storage efficiency purposes.
This is the code which is used in App.xaml.cs:
using (var iso = IsolatedStorageFile.GetUserStoreForApplication() )
{
foreach (string file in GetAllFiles("*.jpg", iso))
{
iso.DeleteFile(file);
}
iso.Dispose();
}
The GetAllFiles method was copied from: http://msdn.microsoft.com/en-us/library/zd5e2z84%28v=vs.110%29.aspx.
When debugging this works fine; all lock screen images that were created since the last time the app launched would get successfully deleted. Just to be clear, the only jpg's stored by the app are the lock screen images.
However, the problem is whenever I do include this delete operation, the lock screen image stops updating from that moment onwards. I get this exception whenever any attempt is made to update it:
System.IO.IsolatedStorage.IsolatedStorageException: Operation not permitted on IsolatedStorageFileStream.
at System.IO.IsolatedStorage.IsolatedStorageFileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, IsolatedStorageFile isf)
at System.IO.IsolatedStorage.IsolatedStorageFile.OpenFile(String path, FileMode mode)
...
A few things to keep in mind:
1) whenever the app is launched, the delete operation is run first in App.xaml.cs, whereas the lock screen image gets updated at a later point by the view model (this is for a weather app, so the new lock screen image is created after the weather is returned).
2) the delete operation is only run when the app is actively opened AND the lock screen setting is on; it isn't called at all in the background task.
What is weird is when I do a fresh install of the app, the lock screen setting by default is off. When I turn the lock screen on, the lock screen image gets created successfully. If I close the app and never relaunch it (thereby never calling the delete operation code), the lock screen image never gets updated because the background task runs into the same previously referenced exception.
If I follow the same exact steps but with no delete operation code in App.xaml.cs, the lock screen image gets updated successfully every time.
3) the live tile continues to be updated without any problems, both when the app is launched or in the background task (that it shares with the lock screen).
Any ideas what's going on here, and what I can do to address this?
can you please provide the code snippet for getting image from isolated storage and updating it to lock screen
Usually this exception is thrown when two threads are trying to access the same isolated storage. This can occur only when it is not attached to debugger (in your case). It is tricky to find. I think while the images are deleted, in same moment the image is also getting saved.
The documentation suggests just alternating between two file names like such:
string fileName;
var currentImage = LockScreen.GetImageUri();
if (currentImage.ToString().EndsWith("_A.jpg"))
{
fileName = "LiveLockBackground_B.jpg";
}
else
{
fileName = "LiveLockBackground_A.jpg";
}
var lockImage = string.Format("{0}", fileName);
I use this approach in one of my apps without issue.
If you wish to continue to use the random Guid, then you should check that the file name is not the same as the current lockscreen before trying to delete.
var currentImage = LockScreen.GetImageUri();
using (var iso = IsolatedStorageFile.GetUserStoreForApplication() )
{
foreach (string file in GetAllFiles("*.jpg", iso))
{
if(AreFilesTheSame(currentImage, file) == false)
{
iso.DeleteFile(file);
}
}
}

How can i save files in the phone accessible by several apps?

I try to develop several WP8 apps using the same credentials for all(same user and password).So if the user choose to change his credentials he does only once in one app and it will change for all.
Until now i used Isolatedstorage to save the credentials(as shown below) but im wondering if the files would be accessible by all the apps...i guess they would not.
So what solution do you have ?
thanks for your help
public static void SaveToFile(byte[] Encryptedfile, string FileName)
{
using (var SaveApplicationFile = IsolatedStorageFile.GetUserStoreForApplication())
{
SaveApplicationFile.DeleteFile(FileName);
using (IsolatedStorageFileStream fileAsStream = new IsolatedStorageFileStream(FileName, System.IO.FileMode.Create, FileAccess.Write, SaveApplicationFile))
{
using (Stream writer = new StreamWriter(fileAsStream).BaseStream)
{
writer.Write(Encryptedfile, 0, Encryptedfile.Length);
}
}
}
}
You can't access IsolatedStorage of other App.
Nor you can't save on SD card.
Maybe consider using Skydrive or other exteral storage.
Another idea, I'm thinking about - maybe you can use MediaLibrary and Save Picture there. And use this picture as a container for some data - maybe using Steganography ;)

Silverlight: Business Application Needs Access To Files To Print and Move

I have the following requirement for a business application:
(All of this could be on local or server)
Allow user to select folder location
Show contents of folder
Print selected items from folder (*.pdf)
Display which files have been printed
Potentially move printed files to new location (sub-folder of printed)
How can I make this happen in Silverlight?
Kind regards,
ribald
First of all, all but the last item can be done (the way you expect). Due to security protocols, silverlight cannot access the user's drive and manipulate it. The closest you can get is accessing silverlight's application storage which will be of no help to you whatsoever in this case. I will highlight how to do the first 4 items.
Allow user to select folder location & Show contents of folder
public void OnSelectPDF(object sender)
{
//create the open file dialog
OpenFileDialog ofg = new OpenFileDialog();
//filter to show only pdf files
ofg.Filter = "PDF Files|*.pdf";
ofg.ShowDialog();
byte[] _import_file = new byte[0];
//once a file is selected proceed
if (!object.ReferenceEquals(ofg.File, null))
{
try
{
fs = ofg.File.OpenRead();
_import_file = new byte[fs.Length];
fs.Read(_import_file, 0, (int)fs.Length);
}
catch (Exception ex)
{
}
finally
{
if (!object.ReferenceEquals(fs, null))
fs.Close();
}
//do stuff with file - such as upload the file to the server
};
}
If you noticed, in my example, once the file is retrieved, i suggest uploading it to a webserver or somewhere with temporary public access. I would recommend doing this via a web service. E.g
//configure the system file (customn class)
TSystemFile objFile = new TNetworkFile().Initialize();
//get the file description from the Open File Dialog (ofg)
objFile.Description = ofg.File.Extension.Contains(".") ? ofg.File.Extension : "." + ofg.File.Extension;
objFile.FileData = _import_file;
objFile.FileName = ofg.File.Name;
//upload the file
MasterService.ToolingInterface.UploadTemporaryFileAsync(objFile);
Once this file is uploaded, on the async result, most likely returning the temporary file name and upload location, I would foward the call to some javascript method in the browser for it to use the generic "download.aspx?fileName=givenFileName" technique to force a download on the users system which would take care of both saving to a new location and printing. Which is what your are seeking.
Example of the javascript technique (remember to include System.Windows.Browser):
public void OnInvokeDownload(string _destination)
{
//call the browser method/jquery method
//(I use constants to centralize the names of the respective browser methods)
try
{
HtmlWindow window = HtmlPage.Window;
//where BM_INVOKE_DOWNLOAD is something like "invokeDownload"
window.Invoke(Constants.TBrowserMethods.BM_INVOKE_DOWNLOAD, new object[] { _destination});
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); }
}
Ensure you have the javascript method existing either in an included javaScript file or in the same hosting page as your silverlight app. E.g:
function invokeDownload(_destination) {
//some fancy jquery or just the traditional document.location change here
//open a popup window to http://www.myurl.com/downloads/download.aspx? fileName=_destination
}
The code for download.aspx is outside the scope of my answer, as it varies per need and would just lengthen this post (A LOT MORE). But from what I've given, it will "work" for what you're looking for, but maybe not in exactly the way you expected. However, remember that this is primarily due to silverlight restrictions. What this approach does is rather than forcing you to need a pluging to view pdf files in your app, it allows the user computer to play it's part by using the existing adobe pdf reader. In silverlight, most printing, at least to my knowledge is done my using what you call and "ImageVisual" which is a UIElement. To print a pdf directly from silverlight, you need to either be viewing that PDF in a silverlight control, or ask a web service to render the PDF as an image and then place that image in a control. Only then could you print directly. I presented this approach as a lot more clean and direct approach.
One note - with the temp directory, i would recommend doing a clean up by some timespan of the files on the server side everytime a file is being added. Saves you the work of running some task periodically to check the folder and remove old files. ;)

From Silverlight, generate file to save on user's computer without hitting server

I have a Silverlight app where I want to do an export of some data. The file output format is most likely going to be PDF or Word. But let's assume I can generate the file contents appropriately. I want to be able to pop up a Save dialog for the user to save this data or open it directly in the program.
Now obviously I could just launch the user to a URL and do the export on the server, and change the MIME type of the response to be either Word or PDF. This would work just fine. However, the sticking point is that I already have the correct data on the client (including complex filters and the like) and recreating this data set on the server just to send it back to the client again seems silly if I can avoid it.
Is there any way to take an existing set of data in Silverlight and generate a Word or PDF file and get it onto the user's computer? I could also do it from JavaScript using browser interop from Silverlight. I don't want to use out-of-browser Silverlight.
You need to use the SaveFileDialog class. Note that due to Silverlight's security settings, the SaveFileDialog needs to be opened as the result of a user event (e.g., a button click).
The dialog can be configured (if you want) using properties such as DefaultExt or Filter before you display it using the ShowDialog() method.
The ShowDialog() method will return true if the user correctly specified a file and clicked OK. If this is the case, you can then call the SaveFileDialog.OpenFile() method to access this file and write your data to it.
Example:
private void Button_Click(object sender, EventArgs e)
{
SaveFileDialog saveDialog = new SaveFileDialog();
if (saveDialog.ShowDialog())
{
System.IO.Stream fileStream = textDialog.OpenFile();
System.IO.StreamWriter sw = new System.IO.StreamWriter(fileStream);
sw.Write("TODO: Generate the data you want to put in your file");
sw.Flush();
sw.Close();
}
}

Resources