Sharing photos on Facebook from your Windows Phone app is one of the scenarios for which you need Facebook inside your app. In my last article, I wrote about the first step of creating a Facebook enabled app, which is authentication. After the user is successfully authenticated, you can start doing things like sharing and uploading photos. This article will show you the simplest way to do it!
Let’s start with my last article – Facebook authentication from Windows Phone app. Finishing with implementing code from that article, I will assume that you have acquired AccessToken and UserID and serialized it to isolated storage. The class used for it was:
|
1 2 3 4 5 |
public class FacebookAccess { public string AccessToken { get; set; } public string UserId { get; set; } } |
I will also assume that the information is saved in a file called FacebookAccess. To share the photo, first of all you will need to load the information from isolated storage. Here is the method for it:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public static T LoadSetting(string fileName) { using (var store = IsolatedStorageFile.GetUserStoreForApplication()) { if (!store.FileExists(fileName)) return default(T); try { using (var stream = store.OpenFile(fileName, FileMode.Open, FileAccess.Read)) { var serializer = new DataContractSerializer(typeof(T)); return (T)serializer.ReadObject(stream); } } catch (Exception e) { Deployment.Current.Dispatcher.BeginInvoke( () => MessageBox.Show(e.Message)); return default(T); } } } |
It’s a generic method and you’ll use it to get back FacebookAccess object. You can skip that step if you already have the AccessToken in memory.
|
1 2 |
var file = SerializeHelper.LoadSetting("FacebookAccess"); SharePhoto(file, message.Text); |
file is the FacebookAccess object with authentication details, and message is a textbox with the message you’d like to share with the photo. SharePhoto method assumes that you have a WriteableBitmap photo defined and called LoadedPhoto. There are many ways you can get it – from PhotoChooserTask, CameraCaptureTask, isolated storage etc. It’s not important as long as you have the object. You start by creating a FacebookClient object from Facebook C# SDK (see the last article to learn how to get it in your project).
|
1 2 3 |
void SharePhoto(FacebookAccess file, string message) { var fb = new FacebookClient(file.AccessToken); |
After that, create a PostCompleted handler – what happens after the photo is posted (actually, after the request is done – the photo may not have been uploaded, an error might have occurred in the process).
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
fb.PostCompleted += (o, args) => { if (args.Error != null) { if (args.Error.Message.StartsWith("(OAuthException - #190)")) { Dispatcher.BeginInvoke(() => { // Error 190 means that the token has expired. You need to ask the user to get the token again before continuing. Handle this error gracefully here. }); } else { Dispatcher.BeginInvoke(() => { MessageBox.Show(args.Error.Message, "Error", MessageBoxButton.OK); }); } return; } else { Dispatcher.BeginInvoke(() => { MessageBox.Show("POSTED"); } ); } }; |
If there was an error, you need to handle it correctly. If error 190 happened, that means that the token has expired (learn more about expired tokens here: https://developers.facebook.com/docs/authentication/access-token-expiration/ ) and you need to get it again. Redirect user to the Facebook site and get the token again like I described in the previous article. If some other error happened, display the information to the user. Otherwise, the photo was posted successfully.
You will be posting your photo in the form of a FacebookMediaObject, object from Facebook C# SDK. You give it a name of your choice, and set the type (jpeg if photo is jpeg type)
|
1 2 3 4 5 |
var fbUpl = new Facebook.FacebookMediaObject { FileName = "TempPhoto.jpg", ContentType = "image/jpg" }; |
Create a byte array from your photo (assuming it’s called LoadedPhoto). Then just call the SetValue method on FacebookMediaObject object with that byte array as a parameter:
|
1 2 3 4 5 6 7 8 9 10 |
using (MemoryStream ms = new MemoryStream() { LoadedPhoto.SaveJpeg(ms, app.LoadedPhoto.PixelWidth, app.LoadedPhoto.PixelHeight, 0, 95); ms.Seek(0, 0); byte[] data = new byte[ms.Length]; ms.Read(data, 0, data.Length); ms.Close(); fbUpl.SetValue(data); } |
Now you have both the message and the photo. You just have to create a dictionary with those elements to be used as parameters for request, and start the asynchronous request:
|
1 2 3 4 5 |
var parameters = new Dictionary(); parameters["message"] = message; parameters["file"] = fbUpl; fb.PostAsync("me/photos", parameters); |
That’s it. Depending on the size, you have to wait a bit before the photo gets uploaded… You can notify the user that the photo is uploading by using performance progress bar, for example. This is what the sharing page will look like in my app Photo Light in a few days after it passes the certification.
In conclusion, I’d like to add that it could really take just 20 lines of code to share photo on Facebook. It takes more though if you wish to handle all the errors properly.
Cool cool ;) bravo bas mi to treba
Drago mi je da ce pomoci… :)
Great tutorial (as was your first one) Any chance you could upload the source code? I’m not always 100% sure where each part of the code goes.
I’ll upload it somewhere and let you know when I do. :)
Great, thank you!
If the app has several pages with several functions that all need the facebook token, you would deserialize the FacebookAccess class each time?
And is it necessary to serialize the class again after using it, or is the serialized version still there after reading it with the LoadSettings class?
Hi
the simplest way to be able to reuse token on many pages is to simply deserialize the file once on app launching and save it in App.xaml.cs object. You can access it from anywhere then. In case it’s null, deserialize it from file, in case it’s not – you have it already and you’re good to go.
Your file stays intact after loading, so you don’t have to save it again.
I just have one question… how to publish the photo on the user’s timeline/wall ?
I got an error in this section, esp. the “LoadedPhoto.SaveJpeg” method;
using (MemoryStream ms = new MemoryStream()
{
LoadedPhoto.SaveJpeg(ms, app.LoadedPhoto.PixelWidth, app.LoadedPhoto.PixelHeight, 0, 95);
ms.Seek(0, 0);
byte[] data = new byte[ms.Length];
ms.Read(data, 0, data.Length);
ms.Close();
fbUpl.SetValue(data);
}
Do you have any idea which reference I need to include?
Can you explain more details about this process?
Thank you in advance! :)
LoadedPhoto needs to be your writeable bitmap.
SaveJpeg is a standard method http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.extensions.savejpeg(v=vs.92) from System.Windows.Media.Imaging
Everything is work fine.
Thank you a million times! :D
:)
using (MemoryStream ms = new MemoryStream()
{
LoadedPhoto.SaveJpeg(ms, app.LoadedPhoto.PixelWidth, app.LoadedPhoto.PixelHeight, 0, 95);
ms.Seek(0, 0);
byte[] data = new byte[ms.Length];
ms.Read(data, 0, data.Length);
ms.Close();
fbUpl.SetValue(data);
}
it has errors: Error 4 Expected class, delegate, enum, interface, or struct C:UsersHPDocumentsVisual Studio 2010ProjectsAWARE-newAWARE-newbrowsercontrol.xaml.cs 26 12 AWARE-new
where should i put this?tnx
hi .. good eve, may i just ask a question? do you think i can tag a group / friend automatically after sharing the uploaded photo? if yes, could you help me how? thank you very much.
I am not sure. Maybe there is, I think you’ll need to browse the official Facebook API documentation… I don’t think you can tag people on the photo, but you could tag a person who was with you in a status or so…
It runs ok, but the uploaded photo is always black one :( and I don’t know why?
can you help please?
Hello, i have an error in LoadSetting with “T” –> “T could not be found”, Am i missing anything?? thanks
Hi igrali !
My name’s Nguyen. thanks for your post.
But now, i have a issue about type Dictionary. when i use it, i see it’s require key and value. and the values are the same in Dictionary. Can you help me fix this ????
Hello Igrali,
I couldn’t get this correctly.
using (MemoryStream ms = new MemoryStream()
{
LoadedPhoto.SaveJpeg(ms, LoadedPhoto.PixelWidth, app.LoadedPhoto.PixelHeight, 0, 95);
ms.Seek(0, 0);
byte[] data = new byte[ms.Length];
ms.Read(data, 0, data.Length);
ms.Close();
fbUpl.SetValue(data);
}
It always highlights ms variable says that it doesn’t exists in current context. How to solve this?
Thank you in advance.
Hello Igrali,
I get it right now, I missed the round bracket after the using statement. Now, it highlights app keyword. Where the app keyword comes from in this context? It says the app is not in the context.
LoadedPhoto.SaveJpeg(ms, LoadedPhoto.PixelWidth, app.LoadedPhoto.PixelHeight, 0, 95);
ms.Seek(0, 0);
byte[] data = new byte[ms.Length];
ms.Read(data, 0, data.Length);
ms.Close();
fbUpl.SetValue(data);
It’s just a path to a WriteableBitmap object called LoadedPhoto. app is “Application.Current as App” but it can be any WriteableBitmap you have somewhere in your app.
Thanks for sharing it, best windows phone facebook article! worked fine, only thing is it would be more easy if you shared the source code.