Difficulty on sharing image on Facebook + asynchronization
I am preparing an application that when user selects a photo from gallery & clicks on share button from Application Bar, it must be shared on Facebook wall. I taken One canvas (tempcanvas), added image on it & i have to share that image.
My MainPage.xaml
contains..
//When user clicks on share button of Application bar.
private void ApplicationBarShareButton_Click(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri("/LoginPage.xaml", UriKind.Relative));
postPhotoToFacebook();
}
//Share photo on Facebook by using FBPhotoPost.cs methods
public void postPhotoToFacebook()
{
FBPhotoPost objFBPhotoPost = new FBPhotoPost(); ;
objFBPhotoPost.PostStatus += new FBPhotoPost.PostStatusEventHandler(objFBPhotoPost_PostStatus);
objFBPhotoPost.ResetBoundaryString();
objFBPhotoPost.AccessToken = App.AccessToken;
objFBPhotoPost.PhotoToPost = objFBPhotoPost.GetBitmapImageFromUIElement(tempCanvas);
objFBPhotoPost.PostPhoto();
MessageBox.Show("Photo Posted");
}
void objFBPhotoPost_PostStatus(object sender, FBPhotoPost.PostStatusEventArgs e)
{
//throw new NotImplementedException();
}
My LoginPage.xaml
contains a webbrowser which is used to display login page & authentication.
public LoginPage()
{
InitializeComponent();
}
private void wbLogin_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
string strLoweredAddress = e.Uri.OriginalString.ToLower();
if (strLoweredAddress.StartsWith("http://www.facebook.com/connect/login_success.html?code="))
{
txtStatus.Text = "Trying to retrieve access token";
wbLogin.Navigate(FBUris.GetTokenLoadUri(e.Uri.OriginalString.Substring(56)));
return;
}
string strTest = wbLogin.SaveToString();
if (strTest.Contains("access_token"))
{
int nPos = strTest.IndexOf("access_token");
string strPart = strTest.Substring(nPos + 13);
nPos = strPart.IndexOf("</PRE>");
strPart = strPart.Substring(0, nPos);
//REMOVE EXPIRES IF FOUND!
nPos = strPart.IndexOf("&expires=");
if (nPos != -1)
{
strPart = strPart.Substring(0, nPos);
}
App.AccessToken = strPart;
//automaticall leave the page after login success.
NavigationService.GoBack();
return;
}
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
wbLogin.Navigate(FBUris.GetLoginUri());
}
FBUris.cs
contains...
public static class FBUris
{
#region AppID
private static string m_strAppID = " "; //APP ID
#endregion
#region AppSecret - only needed because of the fragment bug
private static string m_strAppSecret = ""; //APP secret.
#endregion
//the correct url - but not working due to the WebBrowser fragment bug
//private static string m_strLoginURL = "https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri=http://www.facebook.com/connect/login_success.html&type=user_agent&display=touch&scope=publish_stream,user_hometown";
private static string m_strLoginURL = "https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri=http://www.facebook.com/connect/login_success.html&display=touch&scope=publish_stream,user_hometown";
private static string m_strGetAccessTokenURL = "https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri=http://www.facebook.com/connect/login_success.html&client_secret={1}&code={2}";
private static string m_strQueryUserURL = "https://graph.facebook.com/me?fields=id,name,gender,link,hometown,picture&locale=en_US&access_token={0}";
private static string m_strLoadFriendsURL = "https://graph.facebook.com/me/friends?access_token={0}";
private static string m_strPostMessageURL = "https://graph.facebook.com/me/feed";
public static Uri GetLoadFriendsUri(string strAccressToken)
{
return (new Uri(string.Format(m_strLoadFriendsURL, strAccressToken), UriKind.Absolute));
}
public static Uri GetPostMessageUri()
{
return (new Uri(m_strPostMessageURL, UriKind.Absolute));
}
public static Uri GetQueryUserUri(string strAccressToken)
{
return (new Uri(string.Format(m_strQueryUserURL, strAccressToken), UriKind.Absolute));
}
public static Uri GetLoginUri()
{
return (new Uri(string.Format(m_strLoginURL, m_strAppID), UriKind.Absolute));
}
public static Uri GetTokenL开发者_JAVA百科oadUri(string strCode)
{
return (new Uri(string.Format(m_strGetAccessTokenURL, m_strAppID, m_strAppSecret, strCode), UriKind.Absolute));
}
}
FBPhotoPost.cs
contains..
public class FBPhotoPost
{
#region class setup
//local property variables
private string ms_boundary = string.Empty;
private string ms_accesstoken = string.Empty;
private BitmapImage mimg_phototopost;
private string ms_caption = "WP7 Upload Photo";
// some multipart constants we will use in the strings we create
private const string Prefix = "--";
private const string NewLine = "\r\n";
public FBPhotoPost() { }
public BitmapImage PhotoToPost
{
get {return mimg_phototopost;}
set {mimg_phototopost = value;}
}
public string PhotoCaption
{
get { return ms_caption; }
set { ms_caption = value; }
}
public String BoundaryString
{
get
{
if (ms_boundary == string.Empty)
{ ResetBoundaryString(); }
return ms_boundary;
}
}
public void ResetBoundaryString()
{
ms_boundary = "----------------------------"+ DateTime.Now.Ticks.ToString("x");
}
public String AccessToken
{
get{return ms_accesstoken;}
set{ ms_accesstoken = value;}
}
#endregion
#region Post Data Stuff
//builds a byte array with the image in it and passes it to PostPhotoHTTPWebRequest
//which sends the data via a POST to facebook
public void PostPhoto()
{
if ((mimg_phototopost != null) && (ms_accesstoken != String.Empty))
PostPhotoHTTPWebRequest(BuildPostData());
}
//Uses the PhotoToPost and BoundaryString to build a byte array we can use as the data in the POST message
private byte[] BuildPostData()
{
// Build up the post message header
var sb = new StringBuilder();
//accepts a message parameter which will be the caption to go with the photo
sb.Append(Prefix).Append(BoundaryString).Append(NewLine);
sb.Append("Content-Disposition: form-data; name=\"message\"");
sb.Append(NewLine);
sb.Append(NewLine);
sb.Append(PhotoCaption);
sb.Append(NewLine);
//data for the image
string filename = @"FacebookUpload.jpg";
string contenttype = @"image/jpeg";
sb.Append(Prefix).Append(BoundaryString).Append(NewLine);
sb.Append("Content-Disposition: form-data; filename=\"").Append(filename).Append("\"").Append(NewLine);
sb.Append("Content-Type: ").Append(contenttype).Append(NewLine).Append(NewLine);
byte[] ba_Header = Encoding.UTF8.GetBytes(sb.ToString());
byte[] ba_photo = ImageToByteArray(PhotoToPost);
byte[] ba_footer = Encoding.UTF8.GetBytes(String.Concat(NewLine, Prefix, BoundaryString, Prefix, NewLine));
// Combine all the byte arrays into one - this is the data we will post
byte[] postData = new byte[ba_Header.Length + ba_photo.Length + ba_footer.Length];
Buffer.BlockCopy(ba_Header, 0, postData, 0, ba_Header.Length);
Buffer.BlockCopy(ba_photo, 0, postData, ba_Header.Length, ba_photo.Length);
Buffer.BlockCopy(ba_footer, 0, postData, ba_Header.Length + ba_photo.Length, ba_footer.Length);
//Set the lastposteddata variable to we can show it
ms_lastposteddata = ByteArrayToString(postData);
//return the data as a byte array
return postData;
}
//Converts the raw post data so you can display it for testing, etc...
private string ByteArrayToString(byte[] bytes)
{
System.Text.Encoding enc = System.Text.Encoding.UTF8;
string PostString = enc.GetString(bytes, 0, bytes.Length);
return PostString;
}
private string ms_lastposteddata = "No Data Posted Yet";
public string LastPostedData
{
get { return ms_lastposteddata; }
}
#endregion
//Posts the data to Facebook - can only post to me/photos (no access to users wall)
#region HTTPWebRequest
private void PostPhotoHTTPWebRequest(byte[] postData)
{
try
{
//Fire up an HttpWebRequest and pass in the facebook url for posting as well as the AccessToken
//The AccessToken has to be in the URL - it didn't work just passing it as part of the POST data
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(string.Format("https://graph.facebook.com/me/photos?access_token={0}", App.AccessToken));
httpWebRequest.ContentType = String.Concat("multipart/form-data; boundary=", BoundaryString);
httpWebRequest.Method = "POST";
// start the asynchronous operation
httpWebRequest.BeginGetRequestStream((ar) => { GetRequestStreamCallback(ar, postData); }, httpWebRequest);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult, byte[] postData)
{
try
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
// Write to the request stream.
postStream.Write(postData, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
catch (Exception ex)
{
Deployment.Current.Dispatcher.BeginInvoke(() => { UpdatePostStatus("Error Uploading [GetRequestStreamCallback]:", ex.ToString()); });
}
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
System.Diagnostics.Debug.WriteLine(responseString);
//Update the UI
Deployment.Current.Dispatcher.BeginInvoke(() => { UpdatePostStatus("Upload Success! Picture ID:", responseString); });
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
}
catch (Exception ex)
{
//MessageBox.Show(ex.ToString());
Deployment.Current.Dispatcher.BeginInvoke(() => { UpdatePostStatus("Error Uploading [GetResponseCallback]:", ex.ToString()); });
}
}
#endregion
#region ImageManipulation
//Opens an image file in isolated storage and returns it as a
//BitmapImage object we could use as the image in the PostData method
public BitmapImage GetImageFromIsolatedStorage(String ImageFileName)
{
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
// Open the file
using (IsolatedStorageFileStream isfs = isf.OpenFile(ImageFileName, FileMode.Open, FileAccess.Read))
{
//use the stream as the source of the Bitmap Image
BitmapImage bmpimg = new BitmapImage();
bmpimg.SetSource(isfs);
isfs.Close();
return bmpimg;
}
}
}
}
//ImageToByteArray(BitmapImage) accepts a BitmapImage object and
//converts it to a byte array we can use in the POST buffer
private byte[] ImageToByteArray(BitmapImage bm_Image)
{
byte[] data;
{
// Get an Image Stream
MemoryStream ms_Image = new MemoryStream();
// write an image into the stream
System.Windows.Media.Imaging.Extensions.SaveJpeg(new WriteableBitmap(bm_Image), ms_Image, bm_Image.PixelWidth, bm_Image.PixelHeight, 0, 100);
// reset the stream pointer to the beginning
ms_Image.Seek(0, 0);
//read the stream into a byte array
data = new byte[ms_Image.Length];
ms_Image.Read(data, 0, data.Length);
ms_Image.Close();
}
//data now holds the bytes of the image
return data;
}
//GetBitmapImageFromUIElement accepts a UIElement (canvas, grid, image, etc...)1
//and builds a BitmapImage of it including any child elements
public BitmapImage GetBitmapImageFromUIElement(UIElement element)
{
try
{
WriteableBitmap bmp = new WriteableBitmap((int)element.RenderSize.Width, (int)element.RenderSize.Height);
bmp.Render(element, null);
bmp.Invalidate();
// Get an Image Stream
MemoryStream ms_Image = new MemoryStream();
// write the image into the stream
bmp.SaveJpeg(ms_Image, (int)element.RenderSize.Width, (int)element.RenderSize.Height, 0, 100);
// reset the stream pointer to the beginning
ms_Image.Seek(0, 0);
//use the stream as the source of the Bitmap Image
BitmapImage bmpimg = new BitmapImage();
bmpimg.SetSource(ms_Image);
ms_Image.Close();
return bmpimg;
}
catch (Exception ex)
{
UpdatePostStatus("Error Getting Bitmap from UIElement:", ex.Message);
return null;
}
}
#endregion
#region Events code
//Raise the PostStatus Event so the calling code knows whats going on
private void UpdatePostStatus(string strHeader, string strContents)
{
if (PostStatus != null)
{
PostStatus(this, new PostStatusEventArgs(strHeader, strContents));
}
}
public class PostStatusEventArgs : EventArgs
{
private readonly string msg_header = string.Empty;
private readonly string msg_contents = string.Empty;
// Constructor.
public PostStatusEventArgs(string msgHeader, string msgContents)
{
this.msg_header = msgHeader;
this.msg_contents = msgContents;
}
// Properties.
public string MessageHeader { get { return msg_header; } }
public string MessageContents { get { return msg_contents; } }
}
//the PostStatus Event sends status updates
public delegate void PostStatusEventHandler(object sender,PostStatusEventArgs e);
public event PostStatusEventHandler PostStatus;
#endregion
}
My Problem is asynchronization. When user clicks on share button on ApplicationBar, the 'LoginPage.xaml' is navigated. But before executing / loading the LoginPage.xaml, the returns back & executes postPhotoToFacebook()
.
postPhotoToFacebook()
uses FBFBPhotoPost
methods to share photo on facebook. As webbrowser is not completely loaded, the photo does not reaches when I clicks on ApplicationBar button. Sometimes, it reaches to facebook while sometimes not. I want that when user clicks on share button, image must be shared on facebook (ofcourse when user is logged in).
I also taken postPhotoToFacebook()
on LoginPage, but canvas (from MainPage.xaml) cannot be accessed from LoginPage.
After coming back from LoginPage, i have to execute postPhotoToFacebook()
.
Please help.
精彩评论