Xamarin - 从外部 ViewModel 调用控制器方法

问题描述 投票:0回答:2

我对 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,是的,它是控制器内的按钮,它可以工作,但需要将其删除,这就是为什么我尝试以不同的方式触发保存并在不同的文件中。

xamarin.forms signaturepad
2个回答
0
投票

最后我找到了一种触发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 吗?谁知道呢。

谢谢大家的建议。


0
投票

从您的代码中,我假设您希望在弹出窗口(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;
© www.soinside.com 2019 - 2024. All rights reserved.