Better way to load image synchronously on Windows Phone? - c#

I'm new to do C# Windows Phone programming.
In a nutshell, I am currently building an app that will:
Load image A
Load image B
and then Load image C
then use these 3 images to do some post processing.
My Image B and Image C are build as Content within the project.
Image A is chosen from Gallery or taken via camera, or we can simply assume that Image A is load from Isolated Storage.
I am experiencing a problem which I believe caused by asynchronous image loading.
Here's my code:
...
// I intend to load the 3 pictures by calling the method: LoadImage(int id) and LoadCImage();
else if (ListBox.SelectedIndex == 0)
{
Debug.WriteLine("Selected 0");
PhotoProcessor pp = new PhotoProcessor();
WriteableBitmap imageA = new WriteableBitmap(AImage);
WriteableBitmap imageB = LoadImage(0);
WriteableBitmap imageC = LoadCImage();
WriteableBitmap mix = pp.Mix(pp.CalcAverageColour(0), imageA, imageB, imageC);
resultPic.Source = mix;
}
...
And:
private WriteableBitmap LoadImage(int id)
{
//String uriString = "/Assets/img0.jpg";
//BitmapImage img = new BitmapImage(new Uri(uriString, UriKind.Relative));
BitmapImage img = new BitmapImage();
img.CreateOptions = BitmapCreateOptions.None;
//img.SetSource(Application.GetResourceStream(new Uri("/Assets/facetemplate0.jpg", UriKind.Relative)).Stream);
img.UriSource = new Uri("/Assets/img" + id + ".jpg", UriKind.Relative);
//img.UriSource = new Uri(uriString, UriKind.Relative);
return new WriteableBitmap(img);
}
private WriteableBitmap LoadCImage()
{
//BitmapImage img = new BitmapImage(new Uri("/Assets/imgC.jpg", UriKind.Relative));
BitmapImage bmp = new BitmapImage();
bmp.CreateOptions = BitmapCreateOptions.None;
//img.SetSource(Application.GetResourceStream(new Uri("/Assets/imgC.jpg", UriKind.Relative)).Stream);
bmp.UriSource = new Uri("/Assets/imgC.jpg", UriKind.Relative);
return new WriteableBitmap(bmp);
}
Now my question is:
When I'm trying to run this code, it will throw a Null Reference Exception, which is because of the function mix can't load Image A B and C (loading this images are asynchronously).
I wonder if there's a way to let me sequentially load these images then let me to pass them to the mix function?
What I've tried:
By checking this great blog post, I'm able to know that there do have some way to load the image synchronously, but as you can see throughout my code, I tried to use SetSource(stream) like the blogpost, but unfortunately I got the same Null Reference Exception.
I've also thought about the EventHandler method, however I don't think its a good idea in this case. If I implement EventHandler, would it be something like(pseudo code):
imageA_Opened()
{
LoadImageB += imageB_Opened();
}
imageB_Opened()
{
LoadImageC += imageC_Opened();
}
imageC_Opened()
{
PhotoProcessor pp = new PhotoProcessor();
pp.Mix(averageColour, A, B, C);
}
Am I right?

Servy is correct in saying you shouldn't block the UI with synchronous calls.
With that being said, I had a similar requirement in a WP7 app. I used "Async CTP" to add the ability to write synchronous like functions that wait until it's done before making the next call. I had API calls that required data from earlier calls to function correctly.
I believe this was included in .NET 4.5 and works on WP8.
http://msdn.microsoft.com/en-ca/library/vstudio/hh191443.aspx
Here is what I wrote to pull data for my app (Notice the "async" and "await" keywords):
public async Task<bool> GetDefaultData()
{
try
{
_cancellation = new CancellationTokenSource();
UpdateProgress(DateTime.Now + ": Download Started.\n");
List<string> data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetBaseDataUriList());
App._apiConnection.Done(data);
UpdateProgress(DateTime.Now + ": Countries: " + App._context.Countries.Count() + "\n");
UpdateProgress(DateTime.Now + ": Regions: " + App._context.Regions.Count() + "\n");
UpdateProgress(DateTime.Now + ": Income Levels: " + App._context.IncomeLevels.Count() + "\n");
UpdateProgress(DateTime.Now + ": Indicators: " + App._context.Indicators.Count() + "\n");
data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetCountryUriList("CA"));
App._apiConnection.Done(data);
UpdateProgress(DateTime.Now + ": CA Population: " + App._context.PopulationDatas.Count(c => c.Country.Iso2Code == "CA") + "\n");
data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetCountryUriList("US"));
App._apiConnection.Done(data);
UpdateProgress(DateTime.Now + ": US Population: " + App._context.PopulationDatas.Count(c => c.Country.Iso2Code == "US") + "\n");
data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetCountryUriList("CN"));
App._apiConnection.Done(data);
UpdateProgress(DateTime.Now + ": CN Population: " + App._context.PopulationDatas.Count(c => c.Country.Iso2Code == "CN") + "\n");
return true;
}
catch (OperationCanceledException)
{
MessageBox.Show("Operation Cancelled");
return false;
}
catch (Exception ex)
{
MessageBox.Show("getDefaultData Exception: " + ex.Message);
return false;
}
}

You're not supposed to be able to download an image sequentially. It would certainly be easier to develop, yes, but it wouldn't be nearly as effective because you would be blocking the processor for an extended period of time, thus freezing your application.
I've also thought about the EventHandler method, however I don't think its a good idea in this case. If I implement EventHandler, would it be something like (pseudo code):
Yep, it would follow that general pattern as you have described it. That's the appropriate way to address this problem.

Related

Can Anyone help me retrieve data from parse using unity please?

I have managed to store data, but I can't retrieve it and i would be so grateful if someone could just help me get at least 1 example working.
First I am storing data when the user signs up:
public void SetupNewParseMember(ParseUser user)
{
ParseObject gameScore = new ParseObject("GameScore");
gameScore["cash"] = 500;
gameScore["playerName"] = user.Username;
gameScore["HighestCash"] = 500;
gameScore["GamesPlayed"] = 0;
Task saveTask = gameScore.SaveAsync();
}
This works fine, I can see the data in parse and all seems ok..
The problem is when i try to retrieve the objects.
public void SetupMainScreen(ParseUser user)
{
var query = ParseObject.GetQuery("GameScore").WhereEqualTo("playerName", user.Username);
query.FindAsync().ContinueWith(t =>
{
IEnumerable<ParseObject> results = t.Result;
List<ParseObject> resultsList = results.ToList();
DealWithResults(resultsList, user);
});
}
public void DealWithResults(List<ParseObject> resultsList, ParseUser me)
{
userGamesPlayed = resultsList[1].Get<int>("GamesPlayed");
userHighestCash = resultsList[2].Get<int>("HighestCash");
userCash = resultsList[3].Get<int>("Cash");
WelcomeText.text = "Welcome, " + me.Username + "\n" +
"Cash: $" + userCash + "\n" +
"Highest Cash: $" + userHighestCash + "\n" +
"Games Played: " + userGamesPlayed;
}
First I tried just making changes to the unity ui from inside the Query but that did not work, So i made an outside function and passed the results to it that way, and that still does not work?
I tried to debug what i was getting in the list with this:
foreach (var res in resultsList)
{
Debug.Log("Class Name = " + res.ClassName + "| Keys are: " + res.Keys);
}
But all it returned was:
Class Name = GameScore| Keys are: System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]
Can anyone offer any insights?
EDIT2:
ok so first i found results list and its contents
http://i.imgur.com/IKcBbey.png
Then if i open it, it seems to be null ref?
http://i.imgur.com/VmSpi9c.png
But if i go digging, i found the info i need all the way down here
http://i.imgur.com/1Wwu5uc.png
Now just need to work out how to get it?
As there is only one set of data it is always accessible through resultsList[0]. What you want is:
double cash = (double)resultsList[0]["cash"];
string playerName = (string)resultsList[0]["playerName"];
double highestCash = (double)resultsList[0]["HighestCash"];
int gamesPlayed = (int)resultsList[0]["GamesPlayed"];
Though you probably want to check that resultsList is not null and contains one element before you try to dereference it.
Also as your ParseObject appears to be a Dictionary you might find this MSDN page useful.
Ended up solving it.. Much different to the examples...
I had to make a coroutine that called a function on callback to access the variables outside of the query.
I called it with
StartCoroutine(SetupMainScreen(me, DealWithResults));
then called this.
public IEnumerator SetupMainScreen(ParseUser user, Action<GameScore> callback)
{
var query = ParseObject.GetQuery("GameScore").WhereEqualTo("playerName", user.Username).FirstOrDefaultAsync();
while (!query.IsCompleted)
{
yield return null;
}
if (query.IsFaulted || query.IsCanceled)
{
Debug.Log("Getting of GameScores faulted or cancelled...");
}
else
{
var obj = query.Result;
if (obj != null)
callback(new GameScore(obj.Get<int>("cash"),obj.Get<string>("playerName"),obj.Get<int>("HighestCash"),obj.Get<int>("GamesPlayed")));
}
}
public void DealWithResults(GameScore gs)
{
WelcomeText.text = "Welcome, " + gs.Username + "\n" +
"Cash: $" + gs.Cash + "\n" +
"Highest Cash: $" + gs.HighestCash + "\n" +
"Games Played: " + gs.GamesPlayed;
}
And i just made a class to hold the objects.. Hopefully this helps someone else.

How to obtain the values of a method async c# windows phone 8.1

I have the following code
async void getLocation1()
{
try {
var geolocator = new Geolocator();
Geoposition position = await geolocator.GetGeopositionAsync();
// reverse geocoding
BasicGeoposition myLocation = new BasicGeoposition
{
Longitude = position.Coordinate.Longitude,
Latitude = position.Coordinate.Latitude
};
Geopoint pointToReverseGeocode = new Geopoint(myLocation);
MapLocationFinderResult result = await MapLocationFinder.FindLocationsAtAsync(pointToReverseGeocode);
// here also it should be checked if there result isn't null and what to do in such a case
PostalCode1 = result.Locations[0].Address.PostCode;
Country1 = result.Locations[0].Address.Country;
City1 = result.Locations[0].Address.Town;
State1 = result.Locations[0].Address.Region;
guardarLatit = myLocation.Latitude.ToString();
guardarLong = myLocation.Longitude.ToString();
await GeolocationWait();
MessageDialog msgbox3 = new MessageDialog("Latitud: " + guardarLatit + "Longitud: " + guardarLong);
MessageDialog msgbox4 = new MessageDialog("PostalCode: " + PostalCode1 + " Country: " + Country1 + "City: " + City1 + "State: " + State1);
geolocation.Add("Latitud: " + guardarLatit);
geolocation.Add("Longitud: " + guardarLong);
geolocation.Add("PostalCode: " + PostalCode1);
geolocation.Add("Country: " + Country1);
geolocation.Add("City: " + City1);
geolocation.Add("State: " + State1);
await msgbox3.ShowAsync();
await msgbox4.ShowAsync();
} catch (Exception ex)
{
MessageDialog msgboxE = new MessageDialog("Error");
await msgboxE.ShowAsync();
geolocation.Add("Latitud: null");
geolocation.Add("Longitud: null");
geolocation.Add("PostalCode: null");
geolocation.Add("Country: null");
geolocation.Add("City: null");
geolocation.Add("State: null");
}
}
but I need to do it in the same method without the asynchronous method return values I certainly would be some way to tell me all my asynchronous it stops to get that values.
My problem is that when I print the longitude and latitude zero throws me because of what the asynchronous method sends the values certainly not on time.
Thank you
Ok, so first of all you need to know that you shouldn't use async void.
It is a construction that allows you to use await inside it, but if you await getLocation1() your program will not wait for it.
Instead, you should always use async Task when it's possible. So please try to change getLocation1 to async Task and then, when you await it, after that you will be sure of completed tasks inside of it.

Check file size before adding background transfer request

I'm kind of newbie and i'm working on a background transfer feature to download files. It's for windows phone 7. But the problem is files over 100 MB can't be downloaded with "Transfer Preference = Allow Battery" and if i use "Transfer Preference = None" the phone must be connected to a power source in order to transfer (any file size). So far this is what i have tried but it just doesn't work with files over 100MB. Any help, or suggestion would be great. Thanks!
private void downloadTrigger()
{
string transferFileName = urlTextBox.Text;
var transferUri = new Uri(Uri.EscapeUriString(transferFileName), UriKind.Absolute);
BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(transferUri);
transferRequest.Method = "GET";
string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);
Uri downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.Relative);
transferRequest.DownloadLocation = downloadUri;
transferRequest.Tag = downloadFile;
if (transferRequest.TotalBytesToReceive >= 104857600)
{
try
{
transferRequest.TransferPreferences = TransferPreferences.None;
MessageBox.Show("For files over 100MB an external power is required to start copy.", "News box", MessageBoxButton.OK);
BackgroundTransferService.Add(transferRequest);
feedbackTextBlock.Text = "Queueing " + downloadFile;
return;
}
catch
{
}
}
try
{
transferRequest.TransferPreferences = TransferPreferences.AllowBattery;
BackgroundTransferService.Add(transferRequest);
feedbackTextBlock.Text = "Copying " + downloadFile;
}
catch
{
}
}

c# application doesn't work properly in some pc

I have developed an application that loaded many images in a listview using ImageList in c# .net framework 4. The images are also compressed. When many many images are loaded and compressed then it takes a long time. So I call the method in backgroundworker. In the backgroundworker I had to add images to ImageList and add ImageList to ListView. So I have used safeinvoke() method listView1.SafeInvoke(d=>d.Items.Add(item)).
Everything works fine. Images are displayed one by one in the listview.
But the release of the application doesn’t work properly in some pc and properly works in some other pc. Doesn’t work properly means, If 100 images are browsed using OpenFileDialog to load then some images are loaded and added to listview and then the loading is automatically stopped without adding all images to the listview and no exception shows.
I have spent many times to solve this problem but couldn’t figure out the problem. . Where is the problem? Can anybody help me?
private void bgwLoading_DoWork(object sender, DoWorkEventArgs e)
{
ArrayList a = (ArrayList)e.Argument;
string[] fileNames = (string[])a[0];
this.loadMultiImages(fileNames);
}
private void loadMultiImages(string[] fileNames)
{
int i = 1;
int totalFiles = fileNames.Count();
foreach (string flName in fileNames)
{
if (!flName.Contains("Thumbs.db"))
{
Bitmap newBtmap = (Bitmap)Image.FromFile(flName);
FileInfo fi = new FileInfo(flName);
long l = fi.Length;
if (l > compressSize)
{
newBtmap = resizeImage(newBtmap, 1024,768) ;
newBtmap = saveJpeg(IMAGE_PATH + (SCANNING_NUMBER +
) + ".jpg", newBtmap, IMAGE_QUALITY);
}
else
{
File.Copy(flName, TEMP_IMAGE_PATH + (SCANNING_NUMBER + 1) + ".jpg");
}
if (!bgwLoading.CancellationPending)
{
CommonInformation.SCANNING_NUMBER++;
this.SafeInvoke(d => d.addItemToLvImageContainer(newBtmap));
bgwLoading.ReportProgress((int)Math.Round((double)i / (double)
(totalFiles) * 100));
i++;
}
}
}
}
}
public void addItemToLvImageContainer(Bitmap newBtmap)
{
imageList.Images.Add(newBtmap);
ListViewItem item;
item = new ListViewItem();
item.ImageIndex = SCANNING_NUMBER - 1;
item.Text = SCANNING_NUMBER.ToString();
lvImageContainer.Items.Add(item);
lvImageContainer.Items[item.ImageIndex].Focused = true;
}
To find out the error I have modified the code as follows:
I have commented the two lines
//newBtmap = resizeImage(newBtmap, 1024, 768);
// newBtmap = saveJpeg(IMAGE_PATH + scanning_number + ".jpg", newBtmap, Image_Quality );
and added try-catch as follows:
try
{
Bitmap newBtmap = (Bitmap)Image.FromFile(flName);
File.Copy(flName, CommonInformation.TEMP_IMAGE_PATH +
(CommonInformation.SCANNING_NUMBER + 1) + ".jpg");
if (!bgwLoading.CancellationPending)
{
this.SafeInvoke(d => d.imageList.Images.Add(newBtmap));
ListViewItem item;
item = new ListViewItem();
CommonInformation.SCANNING_NUMBER++;
item.ImageIndex = CommonInformation.SCANNING_NUMBER - 1;
item.Text = CommonInformation.SCANNING_NUMBER.ToString();
this.SafeInvoke(d => d.lvImageContainer.Items.Add(item));
bgwLoading.ReportProgress((int)Math.Round((double)i /
(double)(totalFiles) * 100));
this.safeInvoke(d=>d.addItemImageContainer(newBtmap))
catch (Exception ex)
{
MessageBox.Show( ex.Message);
}
It shows the error message after loading some images as "OutOfMemoryException"
Most probably the following line creates the exception:
Bitmap newBtmap = (Bitmap)Image.FromFile(flName);
But the image files are not corrupted and their file extension is .JPG.
How to get rid of this problem?
I have no answer, but i have some suggestions:
Check .NET framework version on computers with problems
Check, if you have permissions for files you trying to read
Use "try-catch" when you accessing files
And questions:
Is this project written in older version of .NET and migrated/upgraded to .NET 4.0?
Are you using any non-built-in assemblies or external dll's for image processing?

Progress Bar not updating

I have the following piece of code to write data to an XML file.
private void WriteResidentData()
{
int count = 1;
status = "Writing XML files";
foreach (Site site in sites)
{
try
{
//Create the XML file
StreamWriter writer = new StreamWriter(path + "\\sites\\" + site.title + ".xml");
writer.WriteLine("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>");
writer.WriteLine("<customer_list>");
foreach (Resident res in site.GetCustomers())
{
bw.ReportProgress((count / customers) * 100);
writer.WriteLine("\t<customer>");
writer.WriteLine("\t\t<customer_reference>" + res.reference + "</customer_reference>");
writer.WriteLine("\t\t<customer_name>" + res.name + "</customer_name>");
writer.WriteLine("\t\t<customer_address>" + res.address + "</customer_address>");
writer.WriteLine("\t\t<payment_method>" + res.method + "</payment_method>");
writer.WriteLine("\t\t<payment_cycle>" + res.cycle + "</payment_cycle>");
writer.WriteLine("\t\t<registered>" + CheckWebStatus(res.reference) + "</registered>");
writer.WriteLine("\t</customer>");
count++;
}
writer.WriteLine("</customer_list>");
writer.Close();
}
catch (Exception ex)
{
lastException = ex;
}
}
}
It's using the same BackgroundWorker that gets the data from the database. My progress bar properly displays the progress whilst it is reading from the database. However, after zeroing the progress bar for the XML writing it simply sits at 0 even though the process is completing correctly.
Can anyone suggest why?
Could it be that (count / customers) is truncated to zero (division between two integers)?
I think that should be (count*100)/customers, assuming you wanted a percentage complete.
This has to do with threading. Because you are updating your GUI in the same thread as your work is being done.
Does the progressbar fill up when the task is fully complete?
Hmmmzz, you are using a bw in there... so that might be your backgroundworker-process.

Categories

Resources