title: Difficulty on sharing image on Facebook + asynchronization
body: <p>I am preparing an application that when user selects a photo from gallery &amp; clicks on share button from Application Bar, it must be shared on Facebook wall.
  I taken One canvas (tempcanvas), added image on it &amp; i have to share that image.</p>
  
  <p>My <code>MainPage.xaml</code> contains..</p>
  
  <pre><code>//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();
  }
  </code></pre>
  
  <p>My <code>LoginPage.xaml</code> contains a webbrowser which is used to display login page &amp; authentication.</p>
  
  <pre><code>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("&lt;/PRE&gt;");
          strPart = strPart.Substring(0, nPos);
          //REMOVE EXPIRES IF FOUND!
          nPos = strPart.IndexOf("&amp;amp;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());
  }                      
  </code></pre>
  
  <p><code>FBUris.cs</code> contains...</p>
  
  <pre><code>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}&amp;redirect_uri=http://www.facebook.com/connect/login_success.html&amp;type=user_agent&amp;display=touch&amp;scope=publish_stream,user_hometown";
      private static string m_strLoginURL = "https://graph.facebook.com/oauth/authorize?client_id={0}&amp;redirect_uri=http://www.facebook.com/connect/login_success.html&amp;display=touch&amp;scope=publish_stream,user_hometown";
      private static string m_strGetAccessTokenURL = "https://graph.facebook.com/oauth/access_token?client_id={0}&amp;redirect_uri=http://www.facebook.com/connect/login_success.html&amp;client_secret={1}&amp;code={2}";
      private static string m_strQueryUserURL = "https://graph.facebook.com/me?fields=id,name,gender,link,hometown,picture&amp;locale=en_US&amp;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 GetTokenLoadUri(string strCode)
      {
          return (new Uri(string.Format(m_strGetAccessTokenURL, m_strAppID, m_strAppSecret, strCode), UriKind.Absolute));
      }
  }
  </code></pre>
  
  <p><code>FBPhotoPost.cs</code> contains..</p>
  
  <pre><code>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) &amp;&amp; (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) =&gt; { 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(() =&gt; { 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(() =&gt; { 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(() =&gt; { 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
  }
  </code></pre>
  
  <p>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 &amp; executes <code>postPhotoToFacebook()</code>.
  <code>postPhotoToFacebook()</code> uses <code>FBFBPhotoPost</code> 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).</p>
  
  <p>I also taken <code>postPhotoToFacebook()</code> on LoginPage, but canvas (from MainPage.xaml) cannot be accessed from LoginPage.
  After coming back from LoginPage, i have to execute <code>postPhotoToFacebook()</code>.</p>
  
  <p>Please help.</p>