2017-08-30 2 views
1

Je développe une application Xamarin.Forms avec un framework Prism dans une architecture MVVM. J'ai besoin de collecter la signature à l'écran, j'ai donc décidé d'inclure la bibliothèque SignaturePad. Avec NuGet, j'ai inclus les paquets Xamarin.Controls.SignaturePad et Xamarin.Controls.SignaturePad.Forms. Dans la mise en page (construite avec XAML) Je le widget de signature:Récupération d'une image à partir de SignaturePadView avec l'architecture MVVM

<signature:SignaturePadView 
      x:Name="padView" 
      HeightRequest="130"         
      CaptionText="Sign" 
      CaptionTextColor="Black" 
      ClearText="Clean" 
      ClearTextColor="Black" 
      BackgroundColor="White" 
      SignatureLineColor="Black" 
      StrokeWidth="2" 
      StrokeColor="Black" 
      BindingContext="{Binding Sign, Mode=TwoWay}" /> 

Dans le ViewModel le widget de liaison:

private SignaturePadView _sign; 
public SignaturePadView Sign 
{ 
    get { return _sign; } 
    set { SetProperty(ref _sign, value); } 
} 

Dans le constructeur ViewModel:

_sign = new SignaturePadView(); 

Il est aussi un bouton, dans l'action de ce bouton j'ai besoin de lire l'image du signe et l'enregistrer dans la base de données. J'ai essayé ceci:

Stream sig = await Sign.GetImageStreamAsync(SignatureImageFormat.Png); 
var signatureMemoryStream = sig as MemoryStream; 
byte[] data = signatureMemoryStream.ToArray();    

Tout ce code est écrit dans le projet portable. Malheureusement, cela ne fonctionne pas car l'objet sig est toujours nul. Je pense que le problème est la liaison de widget mais je ne suis pas sûr.

Répondre

1

Voici une autre façon de travailler avec le SignaturePad (qui permet d'éviter de mettre des vues dans votre viewmodel). J'aurais pu utiliser un système d'agrégation d'événements pour envoyer un message de VM à View mais l'utilisation d'un Func était la solution la plus simple pour moi.

Faites attention, je ne pas utiliser Prism du tout, donc la solution finale pourrait être un peu différent ...

La partie XAML de la vue de la signature est presque le même sans BindingContext ensemble (de mon dossier 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" /> 

Dans le codebehind de ma 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); 
     }; 
    } 

Où ImageConverter.ReadFully (...) est juste un flux convertisseur d'octets

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(); 
     } 
    } 
} 

Et le viewmodel ressemble à ce

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 
    }); 
} 
+1

Merci pour votre aide. Cela fonctionne parfaitement aussi avec Prism. Juste une clarification: SignatureView.Points est un IEnumerable et ne supporte pas le nombre. – TeoVr81

+0

@ TeoVr81 si je me souviens, compte fonctionne grâce à Linq – hugoterelle

+0

vous avez raison, si j'inclus System.Linq cela fonctionne très bien sans autres solutions de contournement. Merci pour tout! – TeoVr81