How to return result to UI thread in Windows Phone? - windows-phone-7

Does anyone know great idea How to return result to UI thread ?
I wrote this code, but It will be compile error because it can't return "img" in async.
public byte[] DownloadAsync2(Uri address)
{
byte[] img;
byte[] buffer = new byte[4096];
var wc = new WebClient();
wc.OpenReadCompleted += ((sender, e) =>
{
using (MemoryStream memoryStream = new MemoryStream())
{
int count = 0;
do
{
count = e.Result.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, count);
} while (count != 0);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (e.Error == null) img = memoryStream.ToArray();
});
}
}
);
wc.OpenReadAsync(address);
return img; //error : Use of unassigned local variable 'img'
}

Change your method to:
public void DownloadAsync2(Uri address, Action<byte[]> callback, Action<Exception> exception)
{
var wc = new WebClient();
wc.OpenReadCompleted += ((sender, e) =>
{
using (MemoryStream memoryStream = new MemoryStream())
{
int count = 0;
do
{
count = e.Result.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, count);
} while (count != 0);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (e.Error == null) callback(memoryStream.ToArray());
else exception(e.Error);
});
}
}
);
wc.OpenReadAsync(address);
}
Usage:
DownloadAsync2(SomeUri, (img) =>
{
// this line will be executed when image is downloaded,
// img - returned byte array
},
(exception) =>
{
// handle exception here
});
Or (old-style code without lambda expressions):
DownloadAsync2(SomeUri, LoadCompleted, LoadFailed);
// And define two methods for handling completed and failed events
private void LoadCompleted(byte[] img)
{
// this line will be executed when image is downloaded,
// img - returned byte array
}
private void LoadFailed(Exception exception)
{
// handle exception here
}

Related

Action.Picker returns invalid/wrong Uri (How to get path or byte[] from multiple picked gallery img)

I have an forms app where i need to pick "1 to many" images from the phone storage.
For this i use the dependency injection system.
My problem is the somewhere i get an Android.netUri that resolves to a file that do not exist... and to a file name that i have never seen before.
The kicker is that if i pick pictures that was takes within the last couple of hours this code works...
Im am at the end of my hoap, i really hope someone can point me to something that i'm doing wrong.
i start the Picker activity with:
[assembly: Dependency(typeof(ImagePickerService))]
namespace MyApp.Droid
{
public class ImagePickerService : Java.Lang.Object, IImagePickerService
{
public async Task OpenGallery()
{
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Storage);
if (status != PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Storage))
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Need Storage permission to access to your photos.", ToastLength.Long).Show();
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(new[] { Permission.Storage });
status = results[Permission.Storage];
}
if (status == PermissionStatus.Granted)
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Pick max 20 images", ToastLength.Long).Show();
var imageIntent = new Intent(Intent.ActionPick);
imageIntent.SetType("image/*");
imageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
imageIntent.SetAction(Intent.ActionPick);
CrossCurrentActivity.Current.Activity.StartActivityForResult(Intent.CreateChooser(imageIntent, "Pick pictures"), 100);
}
else if (status != PermissionStatus.Unknown)
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Permission Denied. Can not continue, try again.", ToastLength.Long).Show();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Error. Can not continue, try again.", ToastLength.Long).Show();
}
}
}
then in my MainActivity.cs i have the OnActivityResult
I have tried to use the ContentResolver.OpenInputStream to get the image bytes with no luck, so this is commented out atm.
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == OPENGALLERYCODE && resultCode == Result.Ok)
{
List<string> images = new List<string>();
if (data != null)
{
ClipData clipData = data.ClipData;
if (clipData != null)
{
for (int i = 0; i < clipData.ItemCount; i++)
{
ClipData.Item item = clipData.GetItemAt(i);
/*
var stream = ContentResolver.OpenInputStream(item.Uri); //This throws "FileNotFound"
byte[] byteArray;
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
byteArray = memoryStream.ToArray();
stream.Close();
stream = null;
}
stream = ContentResolver.OpenInputStream(item.Uri);
var exif = new ExifInterface(stream);
stream.Close();
*/
Android.Net.Uri uri = item.Uri;
var path = GetActualPathFromFile(uri);
if (path != null)
{
var tmpImgPath = RotateToOriginalDimention(path);
images.Add(tmpImgPath);
}
}
}
else
{
Android.Net.Uri uri = data.Data;
var path = GetActualPathFromFile(uri);
if (path != null)
{
var tmpImgPath = RotateToOriginalDimention(path);
images.Add(tmpImgPath);
}
}
MessagingCenter.Send<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", images);
}
}
}
And the GetActualPathFromFile (also in my MainActivity.cs)
The hole func is below but i hit this part of the code and get at "FileNotFound"
(...)
else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
var retval2 = getDataColumn(this, uri, null, null);
if (File.Exists(retval2)) //<----------------------- This returns "false"
{
return retval2;
}
else
{
throw new Exception("file not found " + retval2);
}
}
(...)
The Hole GetActualPathFromFile
private string GetActualPathFromFile(Android.Net.Uri uri)
{
bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;
if (isKitKat && DocumentsContract.IsDocumentUri(this, uri))
{
// ExternalStorageProvider
if (isExternalStorageDocument(uri))
{
string docId = DocumentsContract.GetDocumentId(uri);
char[] chars = { ':' };
string[] split = docId.Split(chars);
string type = split[0];
if ("primary".Equals(type, StringComparison.OrdinalIgnoreCase))
{
var retval = Android.OS.Environment.ExternalStorageDirectory + "/" + split[1];
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri))
{
string id = DocumentsContract.GetDocumentId(uri);
Android.Net.Uri contentUri = ContentUris.WithAppendedId(
Android.Net.Uri.Parse("content://downloads/public_downloads"), long.Parse(id));
//System.Diagnostics.Debug.WriteLine(contentUri.ToString());
var retval = getDataColumn(this, contentUri, null, null);
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
// MediaProvider
else if (isMediaDocument(uri))
{
String docId = DocumentsContract.GetDocumentId(uri);
char[] chars = { ':' };
String[] split = docId.Split(chars);
String type = split[0];
Android.Net.Uri contentUri = null;
if ("image".Equals(type))
{
contentUri = MediaStore.Images.Media.ExternalContentUri;
}
else if ("video".Equals(type))
{
contentUri = MediaStore.Video.Media.ExternalContentUri;
}
else if ("audio".Equals(type))
{
contentUri = MediaStore.Audio.Media.ExternalContentUri;
}
String selection = "_id=?";
String[] selectionArgs = new String[]
{
split[1]
};
var retval = getDataColumn(this, contentUri, selection, selectionArgs);
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
}
// MediaStore (and general)
else if ("content".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
// Return the remote address
if (isGooglePhotosUri(uri))
{
var retval = uri.LastPathSegment;
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
var retval2 = getDataColumn(this, uri, null, null);
if (File.Exists(retval2))
{
return retval2;
}
else
{
throw new Exception("file not found " + retval2);
}
}
// File
else if ("file".Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
{
var retval = uri.Path;
if (File.Exists(retval))
{
return retval;
}
else
{
throw new Exception("file not found " + retval);
}
}
throw new Exception("file not found ");
}
public static String getDataColumn(Context context, Android.Net.Uri uri, String selection, String[] selectionArgs)
{
ICursor cursor = null;
String column = "_data";
String[] projection =
{
column
};
try
{
cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.MoveToFirst())
{
int index = cursor.GetColumnIndexOrThrow(column);
return cursor.GetString(index);
}
}
finally
{
if (cursor != null)
cursor.Close();
}
return null;
}
//Whether the Uri authority is ExternalStorageProvider.
public static bool isExternalStorageDocument(Android.Net.Uri uri)
{
return "com.android.externalstorage.documents".Equals(uri.Authority);
}
//Whether the Uri authority is DownloadsProvider.
public static bool isDownloadsDocument(Android.Net.Uri uri)
{
return "com.android.providers.downloads.documents".Equals(uri.Authority);
}
//Whether the Uri authority is MediaProvider.
public static bool isMediaDocument(Android.Net.Uri uri)
{
return "com.android.providers.media.documents".Equals(uri.Authority);
}
//Whether the Uri authority is Google Photos.
public static bool isGooglePhotosUri(Android.Net.Uri uri)
{
return "com.google.android.apps.photos.content".Equals(uri.Authority);
}
Found out that the real problem was that Google Photos App was not updating and was still showing images that were deleted.
After 2x reboot of the phone, Google Photos app finally updated.
So this looks more like a cache problem with Google Foto than a xamarin problem.

while streaming video file, file is getting locked by another process using PushStreamContent..how to solve it

I am trying to stream video file . when i open the same video file in another tab of browser , i get the message "file is being used by another process" . if I use FileShare.ReadWrite in file.open method then error goes away but video doesn't play in browser . can someone pl. help .
public HttpResponseMessage Get([string id)
{
var path = HttpContext.Current.Server.MapPath(ConfigurationManager.AppSettings["path"] + "/" + id);
var video = new VideoStream(path);
HttpResponseMessage response = Request.CreateResponse();
var contentType = ConfigurationManager.AppSettings[Path.GetExtension(id)];
response.Content = new PushStreamContent(video.WriteToStream, new MediaTypeHeaderValue(contentType));
return response;
}
public class VideoStream
{
private readonly string _filename;
public VideoStream(string filename)
{
_filename = filename;
}
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[65536];
using (var video = File.Open(_filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
var length = (int) video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
await outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
video.Flush();
}
}
}
catch (HttpException ex)
{
return;
}
finally
{
// outputStream.Close();
// outputStream.Flush();
}
}
}
You should use:
File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
Assuming the file lock comes from the server. Is that the case, or is it a client side thing?

Windows Phone 7 - Upload file to FTP server

Hy.
I do an application in WP7 which is connet a FTP server. I would like to upload a photo(with photochoosertask).
I wrote a PhotoChooserTask() which I could choose a photo. The program save the photo name(samplephoto01.jpg) and the photo route.
And I wrote a code which send command to FTP server:
public static void Execute(String msg)
{
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
Byte[] cmd = Encoding.UTF8.GetBytes((msg + "\r\n").ToCharArray());
socketEventArg.SetBuffer(cmd, 0, cmd.Length);
socket.SendAsync(socketEventArg);
}
This code i can chose the photo:
public void SelectAndUpLoad()
{
PhotoChooserTask p = new PhotoChooserTask();
p.Completed += new EventHandler<PhotoResult>(pt_Completed);
p.ShowCamera = true;
p.Show();
}
void pt_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
BitmapImage img = new BitmapImage();
img.SetSource(e.ChosenPhoto);
MediaLibrary library = new MediaLibrary();
string PhotoPath = e.OriginalFileName;
// MessageBox.Show(PhotoPath);
for (int i = 0; i < library.Pictures.Count; i++)
{
Stream s = library.Pictures[i].GetImage();
if (s.Length == e.ChosenPhoto.Length)
{
string filename = library.Pictures[i].Name;
MessageBoxResult m = MessageBox.Show(filename, "Upload?", MessageBoxButton.OKCancel);
if (m == MessageBoxResult.OK)
{
Ftp.UploadFile(PhotoPath);
}
else
{
return;
}
break;
}
}
}
}
And this is the code whic i would like to upload the file:
public static void UploadFile(string file)
{
FileStream stream = new FileStream(file, FileMode.Open);
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Execute("STRO " + file);
stream.Seek(0, SeekOrigin.Begin);
stream.Close();
}
But when i use the UploadFile(); method the program answer this:
MethodAccessException was unhandled
This code:
.
.
Ftp.UploadFile(PhotoPath);
}
else
{ //MethodAccessException
return;
}
break;
}
What was the wrong? Thank you!
I rewrote this code with IsolatedStorage to this:
for (int i = 0; i < library.Pictures.Count; i++)
{
Stream s = library.Pictures[i].GetImage();
if (s.Length == e.ChosenPhoto.Length)
{
string filename = library.Pictures[i].Name;
MessageBoxResult m = MessageBox.Show(filename, "Upload?", MessageBoxButton.OKCancel);
if (m == MessageBoxResult.OK)
{
IsolatedStorageFile iss = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream fs = iss.OpenFile(PhotoPath, FileMode.Open);
Ftp.UploadFile(fs, filename);
fs.Close();
}
else
{
return;
}
break;
}
}
And the UploadFile() method:
public static void UploadFile(IsolatedStorageFileStream file, string RemoteFile)
{
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
int bytes;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Execute("STRO " + RemoteFile);
file.Seek(0, SeekOrigin.Begin);
while ((bytes = file.Read(buffer, 0, buffer.Length)) > 0)
{
socketEventArg.SetBuffer(buffer, bytes, 0);
socket.SendAsync(socketEventArg);
}
}
But i get an exception in this source:
IsolatedStorageFileStream fs = iss.OpenFile(PhotoPath, FileMode.Open);
The exception is: IsolatedStorageException was unhadnled.
What is wrong?
I think your problem lies in the line:
FileStream stream = new FileStream(file, FileMode.Open);
You can't open files this way on WP7. To get a stream to a file, you can either open it from the Isolated Storage (given that the file is stored there), or use the stream provided by a built-in method.
In your case, you have the stream with the property e.ChosenPhoto. Why don't you use it directly?
public static void UploadFile(Stream stream, string file)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Execute("STRO " + file);
stream.Seek(0, SeekOrigin.Begin);
stream.Close();
}
Then call UploadFile using e.ChosenPhoto as the first argument.

how to overcome the high memory when use HttpWebRequest to download

in my project i use HttpWebRequest to download Feed. But when i download , memory increase and not decrease when they return to the previous form :
#region RequestDataFromServer
private void RequestDataFromServer(object o)
{
if (!string.IsNullOrEmpty(ServerUri))
{
if (DownloadStatus == DownloadState.Downloading)
return;
DownloadStatus = DownloadState.Downloading;
HttpWebRequest serverRequest = (HttpWebRequest)WebRequest.Create(ServerUri);
serverState = new ServerRequestUpdateState();
serverState.AsyncRequest = serverRequest;
IAsyncResult result =
(IAsyncResult)serverRequest.BeginGetResponse(new AsyncCallback(RequestResponse), serverState);
}
}
#endregion
#region RequestResponse
void RequestResponse(IAsyncResult asyncResult)
{
var offlineStream = IsolatedStorageSettings.ApplicationSettings;
serverState = (ServerRequestUpdateState)asyncResult.AsyncState;
HttpWebRequest serverRequest = (HttpWebRequest)serverState.AsyncRequest;
try
{
serverState.AsyncResponse = (HttpWebResponse)serverRequest.EndGetResponse(asyncResult);
if (serverState != null)
{
Stream stream = serverState.AsyncResponse.GetResponseStream();
if (stream != null && serverState.AsyncResponse.StatusCode == HttpStatusCode.OK)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
DownloadStatus = DownloadState.FileReady;
if (serverState != null)
{
try
{
if (offlineStream.Contains("streamOffline"))
{
offlineStream["streamOffline"] = null;
offlineStream.Remove("streamOffline");
}
offlineStream.Add("streamOffline", stream);
if (onComplete != null)
onComplete.Invoke(this, DownloadStatus, IndexImg);
stream.Close();
stream.Dispose();
stream = null;
}
catch (Exception)
{ }
}
});
}
}
}
catch (WebException ex)
{
DownloadStatus = DownloadState.Error;
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//if (onComplete != null)
// onComplete.Invoke(this, DownloadStatus, null, IndexImg);
});
}
catch (Exception)
{ }
finally
{
serverRequest = null;
}
}
#endregion
I thought I had destroyed all the things that can increase the memory, but the memory is still very high up, I saved Isostorage Stream I get into, but it still does not reduce
In .NET memory doesn't decrease at the moment you dispose an object. It would go down when the GC fires up next time.
Read more on... http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
How are you determining that memory is high?

silverlight 4 file upload to mvc 3 controller HttpPostedFileBase is null

I have a mvc 3 page that I want to be able to upload images to my website using silverlight to do the uploading and present a progress bar and a cancel button as it uploads. But I keep getting null value in my controller for the HttpPostedFileBase argument.
Here is my silverlight upload code ...
var client = new WebClient();
client.Headers[HttpRequestHeader.ContentType] = "multipart/form-data";
client.OpenWriteCompleted += (sender1, e1) =>
{
PushData(stream, e1.Result);
e1.Result.Close();
stream.Close();
};
client.UploadProgressChanged += (sender1, e1) =>
{
this.pbStatus.Value = e1.ProgressPercentage;
};
// get uri from params
param = App.Current.Host.InitParams["url"];
var uri = new Uri(param, UriKind.Relative);
client.OpenWriteAsync(uri, "POST");
Push Data method ...
private void PushData(Stream input, Stream output)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, bytesRead);
}
}
And my controller code ...
[HttpPost]
public ActionResult UploadTexture(HttpPostedFileBase file)
{
}
The file param in my controller is null when the controller is called. Anyone know what I am doing wrong ?
I've seen examples that implement a IHttpHandler but I'm trying to avoid doing that and stick with just straight mvc 3 controllers.
I was having the same issue that you were. I was able to solve this issue another way.
foreach (FileInfo fi in uploadedFiles)
{
UriBuilder ub = new UriBuilder(Application.Current.Host.Source.Host + "/Excel/?fileName=" + fi.Name);
WebClient wc = new WebClient();
wc.Headers[HttpRequestHeader.ContentType] = "multipart/form-data";
wc.OpenWriteCompleted += (sender, e) =>
{
FileStream data = fi.OpenRead();
PushData(data, e.Result);
e.Result.Close();
data.Close();
};
wc.OpenWriteAsync(ub.Uri, "POST");
}
Main difference you will see is that I attach the filename to the URL. My PushData() is the same. On the MVC side, I have:
[HttpPost]
public ActionResult Index(string fileName)
{
using (FileStream fs = System.IO.File.Create(Server.MapPath("~/FilesExcel/" + fileName)))
{
SaveFile(Request.InputStream, fs);
}
return View();
}
private void SaveFile(Stream stream, FileStream fs)
{
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
fs.Write(buffer, 0, bytesRead);
}
}

Resources