phone:webbrowser does not open PDF files (Windows Phone 8) - c#

I have build an app with a webbrowser in it. It's working fine but when I try to navigate to an adress like bla.pdf the webbrowser shows nothing.
I solved this problem with automatically open the Internet Explorer if the adress is linking to a pdf file.
Is there a better solution? I want to open that PDF file in my own app and I dont want to open the Internet Explorer everytime. Any suggestions?

If you've got a locally downloaded PDF that is in Isolated Storage you can launch the PDF Reader application (or any other applications registered to open PDF files) using LaunchFileAsync.
private async void LaunchFileButton_Click(object sender, RoutedEventArgs rea)
{
// Access isolated storage.
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
// Access the PDF.
StorageFile pdfFile = await local.GetFileAsync("file1.pdf");
// Launch the bug query file.
Windows.System.Launcher.LaunchFileAsync(pdfFile);
}
(adapted from MSDN, see section on "launching a file").
If it's a remote URL then you can use LaunchUriAsync (which will use IE to download the file first).
You will need to try this on a device with the PDF Reader application installed - it won't work on the Emulator.

You should read following article if you are not familiar with Async: MSDN Asynchronous Programming with Async and Await
I couldn't test my app because my WP8 Phone is currently not available and I can't install an PDF reader on the emulator.
Call following method to start the download
WebClient pdfDownloader = null;
string LastFileName = ""; //To save the filename of the last created pdf
private void StartPDFDownload(string URL)
{
pdfDownloader = new WebClient(); //prevents that the OpenReadCompleted-Event is called multiple times
pdfDownloader.OpenReadCompleted += DownloadPDF; //Create an event handler
pdfDownloader.OpenReadAsync(new Uri(URL)); //Start to read the website
}
async void DownloadPDF(object sender, OpenReadCompletedEventArgs e)
{
byte[] buffer = new byte[e.Result.Length]; //Gets the byte length of the pdf file
await e.Result.ReadAsync(buffer, 0, buffer.Length); //Waits until the rad is completed (Async doesn't block the GUI Thread)
using (IsolatedStorageFile ISFile = IsolatedStorageFile.GetUserStoreForApplication())
{
try
{
LastFileName = "tempPDF" + DateTime.Now.Ticks + ".pdf";
using (IsolatedStorageFileStream ISFileStream = ISFile.CreateFile(LastFileName))
{
await ISFileStream.WriteAsync(buffer, 0, buffer.Length);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.HResult,
ex.Source, MessageBoxButton.OK);
//Catch errors regarding the creation of file
}
}
OpenPDFFile();
}
private async void OpenPDFFile()
{
StorageFolder ISFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
try
{
IStorageFile ISFile = await ISFolder.GetFileAsync(LastFileName);
await Windows.System.Launcher.LaunchFileAsync(ISFile);
//http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206987%28v=vs.105%29.aspx
}
catch (Exception ex)
{
//Catch unknown errors while getting the file
//or opening the app to display it
}
}
To call these methods from your WebBrowser-Control you need to catch the navigating event.
YourWebBrowserControl.Navigating += YourWebBrowserControl_Navigating;
void YourWebBrowserControl_Navigating(object sender, NavigatingEventArgs e)
{
if(e.Uri.AbsolutPath.EndsWith("pdf"))
{
StartPDFDownload(e.Uri.ToString());
}
}
Don't forget that you'll have to delete the files created someday.

Try this to open a PDF from a WebControl:
void MyWebBrowserControl_Navigating(object sender, NavigatingEventArgs e)
{
if (e.Uri.AbsolutPath.ToLower().EndsWith(".pdf"))
{
var success = Windows.System.Launcher.LaunchUriAsync(e.Uri);
}
}

Related

Download pdf to LocalFolder in UWP

I've a UWP app that downloads a pdf file from a website to ApplicationData.Current.LocalFolder, but when I use the Explorer to open the downloaded file, its size is always 0KB and it can't be opened.
For downloading, I used following code:
using System.Diagnostics;
using Windows.Networking.BackgroundTransfer;
using Windows.Storage;
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
Uri source = new Uri("http://www.sachsen.schule/~goethe-gym-auerbach/vplan/VertretungsplanMo.pdf");
StorageFile destinationFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("VertretungsplanMo.pdf", CreationCollisionOption.ReplaceExisting);
BackgroundDownloader downloader = new BackgroundDownloader();
DownloadOperation download = downloader.CreateDownload(source, destinationFile);
Debug.WriteLine("Download successfull");
}
catch (Exception ex)
{
Debug.WriteLine("Download error. Exception: " + ex);
}
}
Although I never get a download error, the file is always 0 KB.
you are forgetting to call download.StartAsync()
Beside that the BackgroundDownload api's are very powerful because it will make sure the files are downloaded also when the app is not running. But they are not that easy neither. So i recommend to use just the HttpClient for simplicity or check some samples with the backgrounddownloader.
See https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BackgroundTransfer for more samples around background tranfser

How to load, edit and save xml in uwp app

Title says it all really. I've been stuck on this one for days and would appreciate some help. I've a main page and a settings page when the main page loads first time it tests for settings.xml in local folder and copies it if not found. Then when the user opens settings page it's supposed to load details from local folder allowing the user to edit before saving them back to the local folder from OnNavigatedFrom event.
Code to load from installation folder to local folder
// Has the file been copied already?
bool blFileExist = false;
try
{
await ApplicationData.Current.LocalFolder.GetFileAsync("settings.xml");
// No exception means it exists
blFileExist = true;
btnSettings.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
}
catch (System.IO.FileNotFoundException)
{
// The file obviously doesn't exist
blFileExist = false;
btnSettings.Foreground = new SolidColorBrush(Windows.UI.Colors.Red);
}
catch (Exception)
{
}
if (!blFileExist)
{
try
{
// Cant await inside catch, but this works anyway
StorageFile stopfile = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync("settings.xml");
await stopfile.CopyAsync(ApplicationData.Current.LocalFolder);
}
catch (System.IO.FileNotFoundException)
{
}
catch (Exception)
{
}
}
Code to load and save settings page
private void loadSettings()
{
try
{
doc = XElement.Load("settings.xml");
nAIPlayers = int.Parse(doc.Element("ai_players").Value);
strCardBack = doc.Element("back").Value;
comboBoxAIPlayers.SelectedIndex = nAIPlayers - 1;
}
catch (System.IO.FileNotFoundException)
{
}
catch (Exception ex)
{
}
}
private async void saveSettings()
{
//try
//{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("settings.xml");
using (Stream fileStream = await file.OpenStreamForWriteAsync())
{
doc.SetElementValue("ai_players", nAIPlayers);
doc.SetElementValue("back", "Back_0");
doc.Save(fileStream);
}
/*}
catch (System.IO.FileNotFoundException)
{
}
catch (Exception ex)
{
}*/
}
I think the problem is I'm accessing the local file to save it and the installation file to load it. The result is no matter what I save it always reads the values in the original settings.xml
How do I load this from the local folder?
doc = XElement.Load("settings.xml");
Update
On the first iteration the code runs fine and the settings page code opens as it should. It's only after leaving the settings page and running saveSettings() method that it fails and throws an error when reloading the settings page and running loadSettings().
System.Xml.XmlException: Data at the root level is invalid. Line 5, position 12
You are doing it wrong because you are using XElement.Load(string) where string stands for URI, which in this case should be:
The Uri parameter must be a file system relative or absolute path.
and with that you will have a problem in UWP as normally you don't have the permission. It also won't work here with URIs like: "ms-appdata:///settings.xml".
Probably you can read a path to your LocalFolder and use it (may work, though haven't tested it), but much easier is to load the content from stream (or read string from file and then load XML from that string), for example like this:
var file = await ApplicationData.Current.LocalFolder.GetFileAsync("settings.xml");
using(var stream = await file.OpenStreamForReadAsync())
{
var doc = XElement.Load(stream);
// ...
}
Note also that there are other classes like XDocument or XmlDocument where you can load and manage you xml file. Everything depends on your needs.

Json serializer - how to create a stream

public static async Task Store(ObservableCollection<Product> list)
{
Uri path = new Uri("ms-appx:///ListCollection.json");
var store = await StorageFile.GetFileFromApplicationUriAsync(path);
var stream = File.OpenWrite(store.Path);
var serialize = new DataContractJsonSerializer(typeof(ObservableCollection<Product>));
serialize.WriteObject(stream, list);
}
Ok this is the piece of code that I used to serialize a collection , works very well , no problem with it , but what I want and tried and no success. I created a JSON file in my project. I want to store and stream data to that file. I tried some methods but no success , how do I open a stream to a file that is currently in my project?
EDITED : Commented the code that was working and wrote what I intend to do. Thanks for support.
When I get to this line
var stream = File.OpenWrite(store.Path); it says that is inaccesible.
What I intend to do is serialize some data to a file called ListCollection.json that is emtpy , that file is project file. It might be the stream or it might be the file that gives me that error. No idea.
My guess is that your project file is located in the installation directory of your application and as far as I know you can't just write to that directory.
You would have to put a deployment action in your solution that writes the desired project file to the application data directory. There you should be able to write it.
I looked through some of the documentation and came accross this:
MSDN
The app's install directory is a read-only location.
I found a Link which makes use of a little hack or so it seems.
I am not sure if this will work if the application is deployed etc.
but you can try this to write the file.
I am not sure if you need a stream or not but feel free to comment:
private void Button_Click(object sender, RoutedEventArgs e)
{
ObservableCollection<string> list = new ObservableCollection<string>();
list.Add("Hallo");
list.Add("Welt");
Task t = Store(list);
}
public static async Task Store(ObservableCollection<string> list)
{
StorageFile file = await GetStorageFileFromApplicationUriAsync();
if (file == null)
{
file = await GetStorageFileFromFileAsync();
}
if (file != null)
{
await file.DeleteAsync();
await CreateFileInInstallationLocation(list);
}
}
private static async Task<StorageFile> GetStorageFileFromFileAsync()
{
StorageFile file = null;
if (file == null)
{
try
{
StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
file = await folder.GetFileAsync("ListCollection.json");
}
catch
{ }
}
return file;
}
private static async Task<StorageFile> GetStorageFileFromApplicationUriAsync()
{
StorageFile file = null;
try
{
Uri path = new Uri("ms-appx:///ListCollection.json");
file = await StorageFile.GetFileFromApplicationUriAsync(path);
}
catch
{ }
return file;
}
private static async Task CreateFileInInstallationLocation(ObservableCollection<string> list)
{
var pkg = Windows.ApplicationModel.Package.Current;
var installedLocationFolder = pkg.InstalledLocation;
try
{
var file = await installedLocationFolder.CreateFileAsync("ListCollection.json", Windows.Storage.CreationCollisionOption.GenerateUniqueName);
var filePath = file.Path;
DataContractJsonSerializer serialize = new DataContractJsonSerializer(typeof(ObservableCollection<String>));
using (Stream stream = await file.OpenStreamForWriteAsync())
{
serialize.WriteObject(stream, list);
stream.Flush();
}
}
catch (Exception ex)
{
var msg = ex.Message;
}
}
What this basically does is:
Find the file
Delete the file
Create a new file
Write your JSON to the file
I am really not an expert on this matter and it even to me seems pretty hacky but it apparently does the job.
If you can avoid writing to the install directory do it and use the method Frank J proposed

How to access isolated storage file from HTML or Javascript for Windows Phone and PhoneGap Application

I am using PhoneGap to develop application for Windows, Android and iOS platform.
I have one problem and need expert assistance from you guys.
I have created one plugin for Windows Phone. Plugin is basically download images from URL and stored in isolated storage folder inside Downloads folder this is working successfully.
Now my problem is does there any way to access isolated storage files from javascript. for example i have downloaded one image and stored in isolated storage ("Download/logo.png) now i have to set this image to my html image source. e.g. <img src="ms-appdata:///local/Downloads/logo.png"/>
But couldn't get success. i have tried several way without luck.
I have using following code to save files in isolated storage.
//This code is working fine for saving image from url to isolated storage
IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication();
//Create directory if does not exists
if (ISF.DirectoryExists(IMAGE_FOLDER_PATH) == false)
{
Debug.WriteLine("Directory created");
ISF.CreateDirectory(IMAGE_FOLDER_PATH);
}
WebClient client = new WebClient();
string modeuleName = hamBurgerMenu[MODULENAME_COLUMN_INDEX];
client.OpenReadCompleted += (s, e) =>
{
if (e.Error == null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
string fullPath = Path.Combine(IMAGE_FOLDER_PATH, modeuleName + ".png");
var bi = new BitmapImage();
bi.SetSource(e.Result);
var wb = new WriteableBitmap(bi);
using (var isoFileStream = isoStore.CreateFile(fullPath))
{
var width = wb.PixelWidth;
var height = wb.PixelHeight;
Extensions.SaveJpeg(wb, isoFileStream, width, height, 0, 100);
}
}
});
}
};
client.OpenReadAsync(new Uri(imageURL, UriKind.Absolute));
I have tried following solutions but couldn't get success at all.
<img src="file:///C:|/Data/Users/DefApps/AppData/{9DB..............0CC}/local/Downloads/logo.png"/>
<img src="ms-appdata:///local/Downloads/logo.png"/>
<img src="ms-appx:///Downloads/logo.png"/>
Your comments or suggestion would be highly appreciated!
Thanks & Regards,
Imdadhusen
I have resolved the issue using below code. The purpose of posting answer is it might help other people who are searching for the same.
Now i am saving downloaded images at app's Local Folder.
Following function will download image from live URL.
private void downloadImage(string imageURL, string[] hamBurgerMenu)
{
string ext = Path.GetExtension(imageURL.Trim());
try
{
WebClient client = new WebClient();
client.OpenReadCompleted += (s, e) =>
{
if (e.Error == null)
{
Deployment.Current.Dispatcher.BeginInvoke(async () =>
{
await saveImage(e.Result, imageURL);
});
}
else
{
//Download Image Not Found
}
};
client.OpenReadAsync(new Uri(imageURL, UriKind.Absolute));
}
catch (Exception e)
{
//Download Error
}
}
Now i am saving the downloaded image using below function
// Save a downloaded images to the app’s local folder.
public async Task saveImage(Stream photoToSave, string imageURL)
{
StorageFile photoFile = null;
try
{
string ext = Path.GetExtension(imageURL.Trim());
photoFile = await localFolder.CreateFileAsync(ext, CreationCollisionOption.ReplaceExisting);
using (var photoOutputStream = await photoFile.OpenStreamForWriteAsync())
{
await photoToSave.CopyToAsync(photoOutputStream);
}
}
catch (Exception e)
{
//Error while saving file
}
}
Now we can access the file using following path at HTML page or Client side script
Important:- <APP_ID> e.g. {8A027331-C7348-182D188-8A02473-1247801} should be replace with your Application ID. It will be 32 digit key.
<img src="C:\\Data\\Users\\DefApps\\AppData\\<APP_ID>\\local\\ Mobile.jpg" alt="Mobile.jpg" />

wp8-how to access the downloaded file into isolated storage

Hello in my app I download ".mp3" file into isolated storage and user should be able to listen this ".mp3" file but it seems i cant reach ".mp3" file in play click event
here is my code
private IsolatedStorageFile isoStore;
public mp3kuran()
{
InitializeComponent();
using ( isoStore= IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isoStore.DirectoryExists("/shared/transfers"))
{
isoStore.CreateDirectory("/shared/transfers");
}
}
}
string link= "https://dl.dropboxusercontent.com/u/75638865/001.mp3";
private BackgroundTransferRequest transferRequest;
here is my download button action it downloads the mp3 file
private void download_Click(object sender, RoutedEventArgs e)
{
Uri transferuri = new Uri(Uri.EscapeUriString(link), UriKind.RelativeOrAbsolute);
// Create the new transfer request, passing in the URI of the file to
// be transferred.
transferRequest = new BackgroundTransferRequest(transferuri);
// Set the transfer method. GET and POST are supported.
transferRequest.Method = "GET";
string downloadFile = link.Substring(link.LastIndexOf("/") + 1);
Uri downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.RelativeOrAbsolute);
transferRequest.DownloadLocation = downloadUri;
transferRequest.Tag = downloadFile;
// Add the transfer request using the BackgroundTransferService. Do this in
// a try block in case an exception is thrown.
try
{
BackgroundTransferService.Add(transferRequest);
}
catch (InvalidOperationException ex)
{
MessageBox.Show("Unable to add background transfer request. " + ex.Message);
}
catch (Exception)
{
MessageBox.Show("Unable to add background transfer request.");
}
}
here play button click event
private void play_Click(object sender, RoutedEventArgs e)
{
string fileName = transferRequest.Tag;
MessageBox.Show(fileName);
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isoStore.FileExists(fileName))
{MessageBox.Show("here");
using (var isoStream = isoStore.OpenFile(fileName, FileMode.Open, FileAccess.Read))
{
mediaSound.Stop();
mediaSound.SetSource(isoStream);
mediaSound.Position = System.TimeSpan.FromSeconds(0);
mediaSound.Volume = 20;
mediaSound.Play();
}
}
}
}
in play_clic event i try to reach mp3 from isolated storage but i couldnt solve what is wrong because when I click button ,it does nothing
Some ideas...
Are you checking the BackgroundTransferRequest has completed before allowing the play button to be clicked?
Are you sure the complete file has been successfully downloaded by checking for the presence of a physical file, the same size as the original? You can use a tool like Windows Phone Toolkit to check this.
It does the Tag property on your BackgroundTransferRequest maintain the correct value after the download is complete?
Normally you'd check the status of the BackgroundTransferRequest and copy the file out of "/shared/transfers" to your own location. You'd then play the file from that location.

Categories

Resources