1

using this recipe to try and choose an image from the gallery and then upload it to s3 but my path always returns null.

private string _imgPath;
        public void InitializeMediaPicker()
        {
                Intent = new Intent();
                Intent.SetType("image/*");
                Intent.SetAction(Intent.ActionGetContent);
                StartActivityForResult(Intent.CreateChooser(Intent, "Select Picture"), 1000);
        }

        public string GetImage()
        {
            InitializeMediaPicker();

            return _imgPath;
        }

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            if ((requestCode != 1000) || (resultCode != Result.Ok) || (data == null)) return;
            var uri = data.Data;
            _imgPath = GetPathToImage(uri);
        }

        private string GetPathToImage(Android.Net.Uri uri)
        {
            string path = null;
            // The projection contains the columns we want to return in our query.
            var projection = new[] { Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data };
            using (var cursor = ManagedQuery(uri, projection, null, null, null))
            {
                if (cursor == null) return path;
                var columnIndex = cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
                cursor.MoveToFirst();
                path = cursor.GetString(columnIndex);
            }
            return path;
        }
BillPull
  • 6,853
  • 15
  • 60
  • 99

2 Answers2

12

Here is a working implementation ported from this question and specifically, this answer.

Include the WRITE_EXTERNAL_STORAGE permission in your manifest for this code to work.

public delegate void OnImageResultHandler(bool success, string imagePath);

protected OnImageResultHandler _imagePickerCallback;
public void GetImage(OnImageResultHandler callback)
{
    if (callback == null) {
        throw new ArgumentException ("OnImageResultHandler callback cannot be null.");
    }

    _imagePickerCallback = callback;
    InitializeMediaPicker();
}

public void InitializeMediaPicker()
{
    Intent = new Intent();
    Intent.SetType("image/*");
    Intent.SetAction(Intent.ActionGetContent);
    StartActivityForResult(Intent.CreateChooser(Intent, "Select Picture"), 1000);
}

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    if ((requestCode != 1000) || (resultCode != Result.Ok) || (data == null)) {
        return;
    }

    string imagePath = null;
    var uri = data.Data;
    try {
        imagePath = GetPathToImage(uri);
    } catch (Exception ex) {
        // Failed for some reason.
    }

    _imagePickerCallback (imagePath != null, imagePath);
}

private string GetPathToImage(Android.Net.Uri uri)
{
    string doc_id = "";
    using (var c1 = ContentResolver.Query (uri, null, null, null, null)) {
        c1.MoveToFirst ();
        String document_id = c1.GetString (0);
        doc_id = document_id.Substring (document_id.LastIndexOf (":") + 1);
    }

    string path = null;

    // The projection contains the columns we want to return in our query.
    string selection = Android.Provider.MediaStore.Images.Media.InterfaceConsts.Id + " =? ";
    using (var cursor = ManagedQuery(Android.Provider.MediaStore.Images.Media.ExternalContentUri, null, selection, new string[] {doc_id}, null))
    {
        if (cursor == null) return path;
        var columnIndex = cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
        cursor.MoveToFirst();
        path = cursor.GetString(columnIndex);
    }
    return path;
}

Example Usage:

Button button = FindViewById<Button> (Resource.Id.myButton);

button.Click += delegate {
    GetImage(((b, p) => {
        Toast.MakeText(this, "Found path: " + p, ToastLength.Long).Show();
    }));
};

I've used a callback instead of returning the path for GetImage as the calling method would finish executing before OnActivityResult is called so the path returned would never be valid.

Community
  • 1
  • 1
matthewrdev
  • 11,930
  • 5
  • 52
  • 64
  • 2
    yea itd be awesome if there was like a company that you paid to work on documenting these type of things but idno no one stepping up to the plate – BillPull Oct 30 '14 at 05:41
  • Absolutely! There a lot of gaps in the advanced usage parts of Xamarin that could do with being filled. Do you need me to expand this answer more BillPull? If so, what additional info? – matthewrdev Oct 30 '14 at 05:57
6

I changed the GetPathToImage method from the Xamarin recipe to the code below and now it works!

private string GetPathToImage(Android.Net.Uri uri)
    {
        ICursor cursor = this.ContentResolver.Query(uri, null, null, null, null);
        cursor.MoveToFirst();
        string document_id = cursor.GetString(0);
        document_id = document_id.Split(':')[1];
        cursor.Close();

        cursor = ContentResolver.Query(
        Android.Provider.MediaStore.Images.Media.ExternalContentUri,
        null, MediaStore.Images.Media.InterfaceConsts.Id + " = ? ", new String[] { document_id }, null);
        cursor.MoveToFirst();
        string path = cursor.GetString(cursor.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Data));
        cursor.Close();

        return path;
    }
menno
  • 279
  • 3
  • 5