UnoDosCode UnoDosCode - 3 days ago 7
C# Question

How can I correctly create my own function to take a photo in Xamarin forms after 10 seconds?

i am following this project https://github.com/ThatCSharpGuy/Forms-FullCameraPage to implement a camera in xamarin forms. it works without any problem but i would like to create my own void to take the photo. The only thing i have changed in that project to my current one is that I have made the

CameraPage
to a Contentpage XAML instead of a class.

The idea is to make a function so the photo gets taken in 10 seconds and i want to control this in my shared code if it is possible.

if we look at the code that i have added this is what i got so far.

public CameraPage()
{
InitializeComponent();
loadCameraFunction (); //so this is the function that i created myself
}

//i added this and put the same value into them as the ones in `SetPhotoResult`
byte[] image;
int width = -1;
int height = -1;

//the void
async void loadCameraFunction()
{
await Task.Delay (10000); //wait 10 sec for the photo to be taken
SetPhotoResult(image, width, height); //i add the byte[] and two ints i created above that has the same value as the ones in SetPhotoResult
}

public delegate void PhotoResultEventHandler(PhotoResultEventArgs result);

public event PhotoResultEventHandler OnPhotoResult;


public void SetPhotoResult(byte[] image, int width = -1, int height = -1)
{
OnPhotoResult?.Invoke(new PhotoResultEventArgs(image, width, height));
}

public void Cancel()
{
OnPhotoResult?.Invoke(new PhotoResultEventArgs());
}

public class PhotoResultEventArgs : EventArgs
{

public PhotoResultEventArgs()
{
Success = false;
}

public PhotoResultEventArgs(byte[] image, int width, int height)
{
Success = true;
Image = image;
Width = width;
Height = height;
}

public byte[] Image { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public bool Success { get; private set; }
}

}


}

Problem i have with this code is that the result from my function seems to be null. It seems like i dont get the image. So my question is: Is the
SetPhotoResult
function what i need to call in order to take the photo? And if so, what am I doing wrong?

Answer

SetPhotoResult should be called once the photo is taken. If all you want to happen is that a photo is taken 10 seconds after you hit the "Take Photo" button on the FullCameraqPagePage then you will need to modify the code in the custom renderer. For iOS in the CameraPageRenderer class add the following to the end of the ViewDidLoad method:

await Task.Delay(10000);
var data = await CapturePhoto();
UIImage imageInfo = new UIImage(data);

(Element as FullCameraPage.CameraPage).SetPhotoResult(
        data.ToArray(),
        (int)imageInfo.Size.Width,
        (int)imageInfo.Size.Height);

This is the same code that is run when you click the circular button on the CameraPage but with the delay added.

It may also be a good idea to remove the cancel (x in the upper left) and the circular button that actually takes the photo (the "Take Photo" button on the first page only loads the camera page, it does not take the photo). To remove those buttons so the user can't interrupt your picture (well, they still can if they close the app) then remove these two lines of code from the SetupUserInterface method of CameraPageRenderer:

View.Add(takePhotoButton);
View.Add(cancelPhotoButton);

Of course you can remove all code related to those two buttons as well.

For Android the same idea should apply. Just add the following to the OnElementChanged method in the Android CameraPageRenderer class:

await Task.Delay(5000);
        var bytes = await TakePhoto();
        (Element as CameraPage).SetPhotoResult(bytes, liveView.Bitmap.Width, liveView.Bitmap.Height);

and to get rid of the the manual take photo button, remove the following from the SetupUserInterface method:

mainLayout.AddView(capturePhotoButton);

EDIT: To do it all in the shared code:

Add a class property to CameraPage of type Action:

public Action TakePicture { get; set; }

Set the code for the Action in CameraPageRenderer:

(Android):

(Element as CameraPage).TakePicture = async () =>
{
     var bytes = await TakePhoto();
    (Element as CameraPage).SetPhotoResult(bytes, liveView.Bitmap.Width, liveView.Bitmap.Height);
};

(iOS):

(Element as CameraPage).TakePicture = async () =>
{
    var data = await CapturePhoto();
    UIImage imageInfo = new UIImage(data);

    (Element as FullCameraPage.CameraPage).SetPhotoResult(data.ToArray(),
        (int)imageInfo.Size.Width,
        (int)imageInfo.Size.Height);
};

Then in CameraPage again:

protected override async void OnAppearing()
{
    base.OnAppearing();
    if (TakePicture != null)
    {
           await Task.Delay(5000);
           TakePicture();
    }
}

That oughta do it.

Comments