Retrieve image from SignaturePadView with MVVM architecture

这一生的挚爱 提交于 2019-12-04 07:56:40

Here is another way of working with the SignaturePad (which helps to avoid putting views in your viewmodel). I could have used a event aggregator system to send a message from VM to View but using a Func was a easiest solution for me.

Pay attention, I don't use Prism at all, so the final solution could be a bit different...

The XAML part of the signature view is almost the same without BindingContext set (from my file TestPage.xaml)

<signature:SignaturePadView Margin="-10, 0, -10, 0" 
    x:Name="SignatureView" 
    HorizontalOptions="FillAndExpand" 
    VerticalOptions="FillAndExpand" 
    HeightRequest="150" 
    CaptionText="Signature" 
    CaptionTextColor="Blue" 
    ClearText="Effacer" 
    ClearTextColor="Black" 
    PromptText=""
    PromptTextColor="Green" 
    BackgroundColor="Silver" 
    SignatureLineColor="Black" 
    StrokeWidth="3" 
    StrokeColor="Black" />

In the codebehind of my page (TestPage.xaml.cs)

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var vm = (TestViewModel)BindingContext; // Warning, the BindingContext View <-> ViewModel is already set

        vm.SignatureFromStream = async () =>
        {
            if (SignatureView.Points.Count() > 0)
            {
                using (var stream = await SignatureView.GetImageStreamAsync(SignaturePad.Forms.SignatureImageFormat.Png))
                {
                    return await ImageConverter.ReadFully(stream);
                }
            }

            return await Task.Run(() => (byte[])null);
        };
    }

Where ImageConverter.ReadFully(...) is just a stream to byte converter

public static class ImageConverter
{
    public static async Task<byte[]> ReadFully(Stream input)
    {
        byte[] buffer = new byte[16 * 1024];
        using (var ms = new MemoryStream())
        {
            int read;
            while ((read = await input.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            return ms.ToArray();
        }
    }
}

And the viewmodel looks like this

public class TestViewModel : ViewModelBase
{
    public Func<Task<byte[]>> SignatureFromStream { get; set; }
    public byte[] Signature { get; set; }

    public ICommand MyCommand => new Command(async () =>
    {
        Signature = await SignatureFromStream();
        // Signature should be != null
    });
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!