我对 Xamarin 不太熟悉,我不知道如何解决我当前的情况,简而言之,我不知道如何从控制器外部调用我的方法 SaveSignature - 下面有一些解释流程(为了简单起见,我删除了一些代码)
我有这个控制器SignaturePadController.xaml:
<?xml version="1.0" encoding="UTF-8"?>
<Frame
xmlns:signature="clr-namespace:SignaturePad.Forms;assembly=SignaturePad.Forms"
xmlns:lang="clr-namespace:Mobile.Business.Extensions;assembly=Mobile.Business"
x:Class="Mobile.UI.Controls.SignaturePadControl"
x:Name="this">
<StackLayout>
<signature:SignaturePadView
x:Name="SignaturePad"
x:FieldModifier="Public"/>
<controls:LabelEntryLayout x:Name="HiddenRecipientSignature" Value="{Binding RecipientSignature}" IsVisible="false"/>
</StackLayout>
</Frame>
SignaturePadController.xaml.cs:
namespace Mobile.UI.Controls
{
public partial class SignaturePadControl : Frame
{
public SignaturePadControl()
{
InitializeComponent();
}
public async void SaveSignature(object sender, EventArgs e)
{
var base64String = string.Empty;
using (var stream = AsyncHandler.RunSync(async () => await SignaturePad.GetImageStreamAsync(SignatureImageFormat.Png)))
{
if (stream == null) return;
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
HiddenRecipientSignature.Value = Convert.ToBase64String(bytes);
}
}
}
}
我在名为 BatchReviewPage 的视图中使用它,如下所示:
<controls:SignaturePadControl
x:Name="SignaturePadControl"/>
上述视图的视图模型称为 BatchReviewViewModel,它具有保存后将包含签名的属性:
private string _recipientSignature;
public string RecipientSignature
{
get => _recipientSignature;
set => SetAndRaiseIfChanged(ref _recipientSignature, value);
}
现在,我需要从另一个名为 TargetViewModel 的视图模型调用 SaveSignature 方法 - 我该怎么做?
这是我需要调用 SaveSignature 方法的代码:
var batchReviewVm = await ShowPopup<BatchReviewViewModel>();
if (batchReviewVm == null) return;
batchReviewVm.OnPopupClose = async () =>
{
switch (batchReviewVm.SelectedCloseOption)
{
case Batch.BatchViewModelBase<TrackerBatchItemModel>.CloseOption.Confirm:
//NEED TO CALL SaveSignature
break;
default:
break;
}
};
我将解释一下上面的代码。
我有一个项目列表,只要单击其中一个,我就会打开弹出的 BatchReviewPage.xaml,填写提供的表单并添加签名,单击“确认”后,我需要保存/检索该项目签名。
谢谢您的帮助
评论回复: 我百分百同意你的观点@Jason,我知道目前这是错误的。
我现在已经在 SignaturePadControl 上创建了一个可绑定属性,这是我正在使用的库https://github.com/xamarin/SignaturePad。
private static readonly Type _thisType = typeof(SignaturePadControl);
public static BindableProperty SignatureProperty =
BindableProperty.Create(
propertyName: nameof(Signature),
returnType: typeof(string),
declaringType: _thisType,
defaultValue: null,
defaultBindingMode: BindingMode.OneWay);
public string Signature
{
get => (string)GetValue(SignatureProperty);
set => SetValue(SignatureProperty, value);
}
这就是我使用控制器的方式:
<controls:SignaturePadControl
IsVisible="{Binding ShowRecipientSignaturePad}"
IsOkayVisible="True"
Signature="{Binding RecipientSignature}"/>
我仍然很难理解如何触发保存签名,我想在 BatchReviewViewModel 上执行此操作,但不知道如何告诉我的代码是时候保存签名了。
我尝试向签名添加属性:SignaturePadView,例如 Focused、Unfocused 等...以便在用户添加签名后触发事件?!但这没有任何作用。
谢谢你的帮助
@Liqun Shen-MSFT,是的,它是控制器内的按钮,它可以工作,但需要将其删除,这就是为什么我尝试以不同的方式触发保存并在不同的文件中。
最后我找到了一种触发SaveSignature的方法,虽然不太理想。
我设法在 SignaturePadView 上找到 2 个属性,以便在用户插入或清除签名(StrokeCompleted 和 Cleared)时触发。
这就是我的 SignaturePadControl.xaml 的样子:
<signature:SignaturePadView
x:Name="SignaturePad"
x:FieldModifier="Public"
BackgroundColor="#FAFAD2"
CaptionText=""
ClearText="Clear"
ClearTextColor="#B8860B"
CaptionTextColor="#B8860B"
HeightRequest="300"
HorizontalOptions="FillAndExpand"
PromptText="{lang:Translate SIGNATURE}"
PromptTextColor="#B8860B"
SignatureLineColor="#B8860B"
StrokeColor="Black"
StrokeWidth="5"
StrokeCompleted="SaveSignature"
Cleared="ClearSignature"
VerticalOptions="CenterAndExpand" />
<controls:LabelEntryLayout x:Name="HiddenRecipientSignature" Value="{Binding RecipientSignature}" IsVisible="false"/>
这是背后的代码:
public void SaveSignature(object sender, EventArgs e)
{
var base64String = string.Empty;
using (var stream = AsyncHandler.RunSync(async () => await SignaturePad.GetImageStreamAsync(SignatureImageFormat.Png)))
{
if (stream == null) return;
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
HiddenRecipientSignature.Value = Convert.ToBase64String(bytes);
}
}
public void ClearSignature(object sender, EventArgs e)
{
HiddenRecipientSignature.Value = null;
}
我的 BatchReviewViewModel 保持不变:
private string _recipientSignature;
public string RecipientSignature
{
get => _recipientSignature;
set => SetAndRaiseIfChanged(ref _recipientSignature, value);
}
这对我有用,我现在会保持原样。
我尝试按照建议使用 BindebleProperty,但失败了。
这是我创建的 BindableProperty,但我感到迷失,因为我不确定如何继续:
private static readonly Type _thisType = typeof(SignaturePadControl);
public static BindableProperty SignatureProperty =
BindableProperty.Create(
propertyName: nameof(Signature),
returnType: typeof(string),
declaringType: _thisType,
defaultValue: null,
defaultBindingMode: BindingMode.OneWay);
public string Signature
{
get => (string)GetValue(SignatureProperty);
set => SetValue(SignatureProperty, value);
}
我应该将 Signature 绑定到 StrokeCompleted 吗?谁知道呢。
谢谢大家的建议。
从您的代码中,我假设您希望在弹出窗口(BatchReviewPage)关闭时将签名保存到
RecipientSignature
属性。但我对你的代码有点困惑。您使用名为 LabelEntryLayout
的自定义控件并从签名Pad 获取流。尽管您将 IsVisible
设置为 false。那为什么要用它呢?
作为替代方案,我想使用 BindableProperty 和 检测属性更改。
在SignaturePadControl.cs
public static readonly BindableProperty NeedSaveProperty =BindableProperty.Create("NeedSave", typeof(bool), typeof(SignaturePadControl), false,propertyChanged:OnNeedSavePropertyChanged);
public bool NeedSave
{
get { return (bool)GetValue(NeedSaveProperty); }
set { SetValue(NeedSaveProperty, value); }
}
private static async void OnNeedSavePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var ob = bindable as SignaturePadControl;
using (var stream = await ob.SignaturePad.GetImageStreamAsync(SignatureImageFormat.Png))
{
if (stream == null) return;
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
var viewModel = ob.BindingContext as BatchReviewViewModel;
viewModel.RecipientSignature = Convert.ToBase64String(bytes);
}
}
在上面的代码中,我们首先创建一个名为
NeedSave
的BindableProperty。然后注册一个属性改变的回调方法。当 NeedSave
的值发生变化时,将会调用回调方法。
在BatchReviewPage中,我们使用自定义控件,
我们可以轻松地将
NeedSave
BindableProperty 绑定到 BatchReviewViewModel 中的属性。
<controls:SignaturePadControl ...
NeedSave="{Binding NeedSaveFlag}"/>
所以在BatchReviewViewModel中,我们定义了Property,
private bool needSaveFlag = false;
public bool NeedSaveFlag
{
get
{
return needSaveFlag;
}
set
{
needSaveFlag = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(NeedSaveFlag)));
}
}
好吧,假设当我们在 TargetViewModel 时,我们只需获取
BatchReviewViewModel
实例并将 NeedValueFlag 设置为 true。
var viewModel = page.BindingContext as BatchReviewViewModel;
viewModel.NeedSaveFlag = true;