如何在 Xamarin 中从 ViewModel 创建警报弹出窗口?

Chr*_*ian 6 alert xamarin xamarin.forms

我正在使用 MVVM 模式开发 Xamarin 应用程序。我想在用户按下按钮时向用户显示警报。

我声明我的 ViewModel

class MainPageViewModel : BindableBase   {
Run Code Online (Sandbox Code Playgroud)

不幸的是,我无法Page直接从 ViewModel 中访问对象。我如何最好地显示我的警报?

小智 6

虽然迟到了,但正如 Nick Turner 在许多评论中提到的那样,到目前为止给出的解决方案要求视图模型引用视图,这是 MVVM 的反模式/侵权。此外,您会在视图模型单元测试中遇到错误,例如:您必须调用 Xamarin.Forms.Init(); 在使用它之前。

相反,您可以创建一个包含警报框代码的界面,然后在视图模型中使用,如下所示:

界面:

public interface IDialogService
{ 
    Task ShowAlertAsync(string message, string title, string buttonLabel); 
}
Run Code Online (Sandbox Code Playgroud)

实现(使用 ACR.UserDialogs NuGet 包):

public class DialogService : IDialogService
{
    public async Task ShowAlertAsync(string message, string title, string buttonLabel)
    {
        if (App.IsActive)
            await UserDialogs.Instance.AlertAsync(message, title, buttonLabel);            
        else
        {
            MessagingCenter.Instance.Subscribe<object>(this, MessageKeys.AppIsActive, async (obj) =>
            {
                await UserDialogs.Instance.AlertAsync(message, title, buttonLabel);
                MessagingCenter.Instance.Unsubscribe<object>(this, MessageKeys.AppIsActive);
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型:

public class TestViewModel
{    
    private readonly IDialogService _dialogService;

    public TestViewModel(IDialogService dialogService)
    {
         //IoC handles _dialogService implementation
         _dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService));
    }

    public ICommand TestCommand => new Command(async () => await TestAsync());

    private async Task TestAsync()
    {
        await _dialogService.ShowAlertAsync("The message alert will show", "The title of the alert", "The label of the button");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后可以将 TestCommand 绑定到 xaml 中的按钮:

<Button x:Name="testButton" Command="{Binding TestCommand}">
Run Code Online (Sandbox Code Playgroud)


Arv*_*iya 2

要显示,Alert请在 ViewModel 类中写入以下代码

public class MainViewModel
{
    public ICommand ShowAlertCommand { get; set; }
    public MainViewModel()
    {
        ShowAlertCommand = new Command(get => MakeAlter());
    }
    void MakeAlter()
    {
        Application.Current.MainPage.DisplayAlert("Alert", "Hello", "Cancel", "ok");
    }
}
Run Code Online (Sandbox Code Playgroud)

在 xaml 中设置CommandButton

<StackLayout>
<Button Text="Click for alert" Command="{Binding ShowAlertCommand}"
   HorizontalOptions="Center"
   VerticalOptions="CenterAndExpand" />
</StackLayout>
Run Code Online (Sandbox Code Playgroud)

BindingContext在 xaml 文件后面的代码中设置。如果你的xaml文件MainPage.xaml

public MainPage()
{
    InitializeComponent();
    BindingContext = new MainViewModel();

}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这是正确的?这会将 UI 代码直接放入 ViewModel 中。如果您切换到新的 UI 平台会怎样?你所有的代码都被破坏了。如果视图模型被重用怎么办?又坏了。至少可以说,这应该是抽象的。 (5认同)
  • 另一点是,ViewModel 不再可测试。您不能模拟直接引用。这应该使用一个接口,这样就可以测试了。如果业务部门说我们想要自定义对话框,那么您将面临重构噩梦。 (5认同)