I'm trying to launch a pdf app viewer when the page on the webview is a pdf file, but i can´t find how to make this, is it possible?
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.
Related
I'm using a post call to get a byte stream with all the data for a PDF, then I want to open the PDF using the default program in Android. Will later do for iOS.
Here's my code:
async void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
Publication p = (Publication)e.SelectedItem;
Debug.WriteLine(p);
if (p.folderID.Equals("-1"))
{
using (Stream respStream = await post(p.docNum))
{
byte[] buffer = new byte[respStream.Length];
respStream.Read(buffer, 0, buffer.Length);
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
File.WriteAllBytes(path + "foo.pdf", buffer);
Device.OpenUri(new Uri(path + "foo.pdf"));
}
}
else
{
await Navigation.PushAsync(new PublicationsPage(p.folderID));
}
}
private async Task<Stream> post(string id)
{
Dictionary<string, string> dir = new Dictionary<string, string>();
dir.Add("LoginID", App.user.login_id);
dir.Add("docID", id);
var jsonReq = JsonConvert.SerializeObject(dir);
Debug.WriteLine("req: " + (String)jsonReq);
var content = new StringContent(jsonReq, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var responseStream = await response.Content.ReadAsStreamAsync();
return responseStream;
}
What I have now downloads the pdf as a byte stream then makes a window pop up then close. What should I do to fix? I'd rather not pay for any packages and ideally I'd like to have it prompt for what program to open with.
The file system is different between Ios and Android. So, you need use DependencyService to save and load the PDF file on different platform.
Thanks #B.6242, in this issue, #B.6242 has implemented it in both Android and Ios with DependencyService, you can refer to it.
Here is an issue about how to use the file system on different platforms.
Got it to work by following this: https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/controls/display-pdf/
In the code above, change OnItemSelected to this, where PDFViewPage uses the customWebView described in the above link:
async void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
Publication p = (Publication)e.SelectedItem;
Debug.WriteLine(p);
if (p.folderID.Equals("-1"))
{
using (Stream respStream = await post(p.docNum))
{
byte[] buffer = new byte[respStream.Length];
respStream.Read(buffer, 0, buffer.Length);
string path = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
File.WriteAllBytes(path + "foo.pdf", buffer);
await Navigation.PushAsync(new PDFViewPage(path + "foo.pdf"));
//Device.OpenUri(new Uri(path + "foo.pdf"));
}
}
else
{
await Navigation.PushAsync(new PublicationsPage(p.folderID));
}
}
When I finish developing app on Windows Phone 8 in Visual Studio 2013 and start testing it on my physical device - everything works perfect.
After publishing app in Windows Mobile Store, when i download app on device, it giving me error in moment i want to download and save file into IsolatedStorage. This occurs in this fragment.
I missing some permissions? Why when I debug app via VS everything is okay, but after publishing - fails?
private Task<Stream> DownloadFile(Uri url)
{
var task = new TaskCompletionSource<Stream>();
var webClient = new WebClient();
webClient.OpenReadCompleted += (s, e) =>
{
if (e.Error != null) task.TrySetException(e.Error);
else if (e.Cancelled) task.TrySetCanceled();
else task.TrySetResult(e.Result);
};
webClient.OpenReadAsync(url);
return task.Task;
}
private async Task<Problem> DownloadFileFromWeb(Uri uriToDownload, string fileName, CancellationToken cToken)
{
try
{
using (Stream stream = await DownloadFile(uriToDownload))
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (storage.FileExists(fileName)) return Problem.Other;
using (IsolatedStorageFileStream file = storage.CreateFile(fileName))
{
const int BUFFER_SIZE = 8192;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await stream.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
{
cToken.ThrowIfCancellationRequested();
file.Write(buf, 0, bytesread);
}
}
}
return Problem.Ok;
}
catch (Exception exc)
{
if (exc is OperationCanceledException)
return Problem.Cancelled;
else return Problem.Other;
}
}
I need to download files like ".Doc , .pdf , .xls , .Jpeg, .PNG etc" from the server and store into phone memory not to Isolated. I have search a lot but can not get any things for .doc , .pdf. I got a link Downloading and saving a file Async in Windows Phone 8
but can not work. So if any one can do this please let me know.
Thanks in advance.
I have done with FileSavePicker , here is code
public void DownloadFiles(Uri url)
{
var wc = new WebClient();
wc.OpenReadCompleted +=async (s, e) =>
{
Stream st = e.Result;
buf = ReadFully(st);
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("PDF", new List<string>() { ".pdf" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = "New Document";
savePicker.PickSaveFileAndContinue();
StorageFile SF = await KnownFolders.PicturesLibrary.CreateFileAsync
("Guide.pdf", CreationCollisionOption.ReplaceExisting);
var fs = await SF.OpenAsync(FileAccessMode.ReadWrite);
StorageStreamTransaction transaction = await SF.OpenTransactedWriteAsync();
DataWriter dataWriter = new DataWriter(transaction.Stream);
dataWriter.WriteBytes(buf);
transaction.Stream.Size = await dataWriter.StoreAsync(); // reset stream size to override the file
await transaction.CommitAsync();
};
wc.OpenReadAsync(url);
}
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
private async void ContinueFileOpenPicker(FileSavePickerContinuationEventArgs args)
{
StorageFile file = args.File;
if (file != null)
{
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
// write to file
await FileIO.WriteBytesAsync(file, buf);
// Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
if (status == FileUpdateStatus.Complete)
{
Debug.WriteLine("File " + file.Name + " was saved.");
}
else
{
Debug.WriteLine("File " + file.Name + " couldn't be saved.");
}
}
else
{
Debug.WriteLine("Operation cancelled.");
}
await Windows.System.Launcher.LaunchFileAsync(file);
}
For More information Please go with this url How to continue your Windows Phone app after calling a file picker
I don't think you'll be able to directly download and store the files into the memory card as they have restricted access for security purposes. I guess Isolated Storage could be the option.
Reference
I'm using Xamarin for Android. I load an image and put it in ImageView, then I edit the image. Next I want to save that image to SD card.
Anyone know how to save the image into SD card because I only can find it in Java Android. I already try to convert the code from Java to C# but still get an error.
Any help, thanks in advance.
I get an error at InputStream iS = Resources.OpenRawResource(Resource.Drawable.Icon); as the error is "cannot implicitly convert type 'System.IO.Stream' to 'Java.IO.InputStream'"
Here's the code:
Java.IO.File path = Android.OS.Environment.GetExternalStoragePublicDirectory (Android.OS.Environment.DirectoryPictures);
Java.IO.File file = new Java.IO.File (path, "Icon.png");
try {
path.Mkdirs();
InputStream iS = Resources.OpenRawResource(Resource.Drawable.Icon);
OutputStream oS = new FileOutputStream(file);
byte[] data = new byte[iS.Available()];
iS.Read(data);
oS.Write(data);
iS.Close();
oS.Close();
} catch (Exception ex) {
// ...
}
I use this to save the captured photo to sdcard:
public void OnPictureTaken(byte[] data, Android.Hardware.Camera camera)
{
// Save the image JPEG data to the SD card
FileOutputStream outStream = null;
File dataDir = Android.OS.Environment.ExternalStorageDirectory;
if (data!=null)
{
try
{
outStream = new FileOutputStream(dataDir + "/" + PICTURE_FILENAME);
outStream.Write(data);
outStream.Close();
}
catch (FileNotFoundException e)
{
Android.Util.Log.Debug("SIMPLECAMERA", e.Message);
}
catch (IOException e)
{
Android.Util.Log.Debug("SIMPLECAMERA", e.Message);
}
File file = new File(dataDir + "/" + PICTURE_FILENAME);
try
{
ExifInterface exif = new ExifInterface(file.CanonicalPath);
// Read the camera model and location attributes
exif.GetAttribute(ExifInterface.TagModel);
float[] latLng = new float[2];
exif.GetLatLong(latLng);
// Set the camera make
exif.SetAttribute(ExifInterface.TagMake, “My Phone”);
exif.SetAttribute(ExifInterface.TagDatetime,
System.DateTime.Now.ToString());
}
catch (IOException e) {
Android.Util.Log.Debug("SIMPLECAMERA", e.Message);
}
}
else
{
Toast.MakeText(this, "No Image Captured", ToastLength.Long);
}
}
found the answer, credit to Mohd Riyaz.
var yourImageView = new ImageView(this); //Your image view
var fetchedDrawable = yourImageView.Drawable;
BitmapDrawable bitmapDrawable = (BitmapDrawable)fetchedDrawable;
var bitmap = bitmapDrawable.Bitmap;
using (var stream = new FileStream("AbsolutePath_File", FileMode.Create))
{
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 100, stream);
}
I'm going in circles searching and reading forums on how to solve this problems. After a day of trying I'm still at a loss how to solve my problem. I'm uploading a file and need to return the % in a a textbox. I'm having no problem with the upload portion and have no problems returning the values using the BackgroundWorker if I include all my code within the same class. However, what I'm doing is calling an ftp class from form1. I need the ftp class to return the percentage to form1 so I can can display in my UI and also need to have the server response codes returned from my ftp class to display in my form1. Everything was working ok before I tried to run this in a BackgroundWorker process, with the exception of course that the UI becomes unresponsive and returns all status messages after upload completed. Heres my code as it stands now. How do I get the percentage from ftp class and pass it back to form1, as well as the server response code once completed?
public partial class Form1 : Form
{
private BackgroundWorker bw = new BackgroundWorker();
private string ftpServer = #"ftp://10.0.0.0";
private string ftpUser = #"user";
private string ftpPass = #"pass";
private string ftpRemoteFile = #"myfile.exe";
private string ftpLocalFile = #"C:\Uploads\file.exe";
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void sendButton_Click(object sender, EventArgs e)
{
progressRichTextBox.Text = "Sending";
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ftp ftpClient = new ftp(ftpServer, ftpUser, ftpPass);
ftpClient.upload(progressRichTextBox, ftpRemoteFile, ftpLocalFile);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!(e.Error == null))
{
this.progressRichTextBox.Text = ("Error: " + e.Error.Message);
}
else
{
this.progressRichTextBox.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressRichTextBox.Text = (e.ProgressPercentage.ToString() + "%");
}
}
And heres the ftp class:
public void upload(System.Windows.Forms.RichTextBox progressRichTextBox, string remoteFile, string localFile)
{
FileInfo fileInfo = new FileInfo(localFile);
/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + "/" + remoteFile);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* Specify generic group name for faster upload */
ftpRequest.ConnectionGroupName = "AffiliateUpload";
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
/* Server connection options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
ftpRequest.ContentLength = fileInfo.Length;
/* Buffer for the Data */
byte[] buff = new byte[bufferSize];
int contentLen;
/* Open a File Stream to Read the File for Upload */
FileStream localFileStream = fileInfo.OpenRead();
try
{
// Stream to which the file to be upload is written
ftpStream = ftpRequest.GetRequestStream();
// Read from the file stream 2kb at a time
contentLen = localFileStream.Read(buff, 0, bufferSize);
// Till Stream content ends
while (contentLen != 0)
{
// Write Content from the file stream to the
// FTP Upload Stream
ftpStream.Write(buff, 0, contentLen);
contentLen = localFileStream.Read(buff, 0, bufferSize);
}
// Close the file stream and the Request Stream
ftpStream.Close();
localFileStream.Close();
ftpRequest = null;
}
catch (Exception ex)
{
Console.WriteLine("Failed sending to " + host + "/" + remoteFile + " (" + ex.Message + ")");
}
}
You don't need to update progressRichTextBox in your upload method. Remove that parameter. You need to provide the worker object to your upload method and call worker.ReportProgress on it.