Tak właśnie zrobiłem, bo nic innego nie wykminiłem:
Kopiuj
<StackLayout>
<StackLayout.IsVisible>
<Binding Path="Signature">
<Binding.Converter>
<conv:IsNullToBooleanConverter IsNull="False"/>
</Binding.Converter>
</Binding>
</StackLayout.IsVisible>
<Image HeightRequest="88">
<Image.Source>
<Binding Path="Signature">
<Binding.Converter>
<conv:StreamToImageSourceConverter/>
</Binding.Converter>
</Binding>
</Image.Source>
</Image>
<uc:SimpleButton x:Name="hClearSignature" Text="Wyczyść" Clicked="hClearSignature_Clicked"/>
</StackLayout>
<Grid HorizontalOptions="FillAndExpand">
<Grid.IsVisible>
<Binding Path="Signature">
<Binding.Converter>
<conv:IsNullToBooleanConverter IsNull="True"/>
</Binding.Converter>
</Binding>
</Grid.IsVisible>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="96"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<si:SignaturePadCanvasView BindingContextChanged="hSignature_BindingContextChanged" x:Name="hSignature" BackgroundColor="White"/>
<uc:SimpleButton Grid.Row="1" x:Name="hSaveSignature" Text="Zapisz" Clicked="hSaveSignature_Clicked"/>
</Grid>
</Grid>
xaml.cs
Kopiuj
public partial class FillTaskFormPage : ContentPage
{
public FillTaskFormPage()
{
SignatureList = new List<SignaturePadCanvasView>();
InitializeComponent();
hViewModel.Model = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
SignatureList.Clear();
hViewModel.OnAppearing();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
hViewModel.OnDisappearing();
SignatureList.Clear();
}
List<SignaturePadCanvasView> SignatureList { get; }
private void hSignature_BindingContextChanged(object sender, EventArgs e)
{
if((sender as SignaturePadCanvasView).BindingContext != null)
SignatureList.Add(sender as SignaturePadCanvasView);
Debug.WriteLine($"========================= ({SignatureList.Count().ToString()}) > { ((sender as SignaturePadCanvasView).BindingContext as TaskFormModelElement).Question}");
}
private async void hSaveSignature_Clicked(object sender, EventArgs e)
{
TaskFormModelElement model = (sender as SimpleButton).BindingContext as TaskFormModelElement;
SignaturePadCanvasView canvas = SignatureList.FirstOrDefault(x => x.BindingContext as TaskFormModelElement == model);
await hViewModel.SaveSignature(canvas, model);
canvas.Clear();
}
private async void hClearSignature_Clicked(object sender, EventArgs e)
{
TaskFormModelElement model = (sender as SimpleButton).BindingContext as TaskFormModelElement;
SignaturePadCanvasView canvas = SignatureList.FirstOrDefault(x => x.BindingContext as TaskFormModelElement == model);
await hViewModel.ClearSignature(canvas, model);
}
}
viewmodel:
Kopiuj
public async Task SaveSignature(SignaturePadCanvasView canvas, TaskFormModelElement model)
{
try
{
Stream stream = await canvas.GetImageStreamAsync(SignatureImageFormat.Png, true, false);
model.Signature = stream;
}
catch (Exception e)
{
UserDialogs.Instance.Toast($"Błąd: {e.Message}", new TimeSpan(0, 0, 3));
}
}
public async Task ClearSignature(SignaturePadCanvasView canvas, TaskFormModelElement model)
{
try
{
model.Signature = null;
}
catch (Exception e)
{
UserDialogs.Instance.Toast($"Błąd: {e.Message}", new TimeSpan(0, 0, 3));
}
}
Converter:
Kopiuj
public class StreamToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
MemoryStream destination = new MemoryStream();
using (Stream stream = (Stream)value)
{
if (stream != null && stream.CanRead)
{
stream.Position = 0;
stream.CopyTo(destination);
}
else
return null;
}
if (destination != null)
destination.Position = 0;
return ImageSource.FromStream(() => destination);
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Z tym rozwiązaniem wszystko ładnie działa dopóki nie obrócę ekranu telefonu (zmiana orientacji). Gdy obrócę ekran telefonu (zmienię orientację), konsola wykrywa zmianę BindingContext
. Jakim cudem?
Zrobiłem sobie mały teścik:
Kopiuj
private void hSignature_BindingContextChanged(object sender, EventArgs e)
{
if((sender as SignaturePadCanvasView).BindingContext != null)
SignatureList.Add(sender as SignaturePadCanvasView);
Debug.WriteLine($"============================== hSignature BindingContextChanged:");
var context = (sender as SignaturePadCanvasView).BindingContext;
if(context == null)
Debug.WriteLine($"============== Type: NULL");
else
{
Debug.WriteLine($"============== Type: {context.GetType()}");
Debug.WriteLine($"============== ElementType: {(context as TaskFormModelElement).ElementType}");
Debug.WriteLine($"============== Question: {(context as TaskFormModelElement).Question}");
}
}
I teraz ciekawostka. Po otwarciu okna kontrolki i konteksty wczytują się prawidłowo:
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== viewModel: Invalid ElementType
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== viewModel: Invalid ElementType
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== viewModel: Invalid ElementType
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== viewModel: Invalid ElementType
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== AddedToList:
[0:] ============== ElementType: Signature
[0:] ============== Question: Podpis klienta
Ten ostatni to właśnie właściwy typ gdzie faktycznie będziemy coś pisać w kontrolce. I teraz nic nie rysując, nic nie klikając po prostu obracam ekran i mam:
[EGL_emulation] eglMakeCurrent: 0xec905720: ver 2 0 (tinfo 0xd0fac690)
[EGL_emulation] eglMakeCurrent: 0xec905720: ver 2 0 (tinfo 0xd0fac690)
Z racji, że komórka jest teraz poziomo muszę przewinąć trochę w dół i gdy mój element hSignature
jest widoczny na ekranie dostaję na konsoli zmianę BindingContext
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== viewModel: Invalid ElementType
[0:] StreamToImageSourceConverter > stream NULL or CantRead
[0:] ============================== hSignature BindingContextChanged:
[0:] ============== AddedToList:
[0:] ============== ElementType: Signature
[0:] ============== Question: Podpis klienta
Co może być grane?