【问题标题】:Xamarin Forms Popup Page Button Command Called when Page Appears页面出现时调用 Xamarin 窗体弹出页面按钮命令
【发布时间】:2019-02-28 18:21:46
【问题描述】:

我正在使用 Rg.Plugins.Popup,并且我有一个带有按钮的弹出页面,我想用它来关闭弹出窗口。弹出窗口显示得很好,我现在可以通过背景选择将其关闭。但是对于好的用户体验来说,也需要一个按钮。按钮是这样连接的:

在我的 XAML 中:

<Button BackgroundColor="#2B653E"
                Margin="0,20,0,0"
                Padding="10,10,10,10"
                Command="{Binding OnBtnOkTapped}"
                Text="OK"
                TextColor="White"
                x:Name="btnOk"/>

在我的 ViewModel 中:

public ICommand OnBtnOkTapped = new Command(async () => { await PopupNavigation.Instance.PopAllAsync(); });

我已经确认绑定工作正常(其他属性工作正常)。但是当我点击按钮时什么都没有发生。所以我在这一行放了一个断点,发现它在弹出窗口出现时被调用了。

当我在弹出窗口中点击此按钮时,它不会被调用(即我没有命中断点)。

谁能告诉我为什么会这样?

编辑:做了一些进一步的测试,从 Command 更改为 Clicked 并在后面的代码中处理而不是在 ViewModel 中产生预期的结果。只是不明白为什么在页面加载时调用 ICommand 而不是在单击按钮时调用。

编辑 2:

根据@G.hakim 的要求,这里是此页面的完整 XAML:

<?xml version="1.0" encoding="UTF-8"?>
<pages:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
             xmlns:animations="clr-namespace:Rg.Plugins.Popup.Animations;assembly=Rg.Plugins.Popup"
             xmlns:lottie="clr-namespace:Lottie.Forms;assembly=Lottie.Forms"
             x:Class="MyApp.PopUpPages.ReservationResult"
             BackgroundColor="Transparent">
    <pages:PopupPage.Animation>
        <animations:ScaleAnimation
            PositionIn="Center"
            PositionOut="Center"
            ScaleIn="1.2"
            ScaleOut="0.8"
            DurationIn="400"
            DurationOut="300"
            EasingIn="SinIn"
            EasingOut="SinOut"
            HasBackgroundAnimation="false"/>
    </pages:PopupPage.Animation>
    <StackLayout
        HorizontalOptions="Center"
        VerticalOptions="Center"
        WidthRequest="300"
        HeightRequest="400"
        BackgroundColor="White"
        Padding="30">
        <lottie:AnimationView x:Name="ResultAnimation"
             Animation="{Binding AnimationRef}"
             AutoPlay="true"
             Loop="false"
             VerticalOptions="Center"
             HorizontalOptions="Center"
             HeightRequest="200"
             WidthRequest="200"
             Scale="1"/>
        <Label Text="{Binding ResponseTitle}"
           Margin="0,20,0,0"
           HorizontalOptions="Center"
           VerticalOptions="Start"
           TextColor="#2B653E"
           FontAttributes="Bold"
           FontSize="Large"/>

        <Label Text="{Binding ResponseMessage}"
           HorizontalOptions="Center"
           VerticalOptions="End"
           TextColor="#2B653E"/>

        <Button BackgroundColor="#2B653E"
                Margin="0,20,0,0"
                Padding="10,10,10,10"
                Clicked="Handle_Clicked"
                Text="OK"
                TextColor="White"
                x:Name="btnOk"/>       
    </StackLayout>
</pages:PopupPage>

这里是 ViewModel:

using System;
using System.Windows.Input;
using Rg.Plugins.Popup.Services;
using MyApp.Models;
using Xamarin.Forms;

namespace MyApp.ViewModels
{
    public class ReservationResultViewModel : ViewModel
    {
        public string ResponseTitle { get; set; }
        public string ResponseMessage { get; set; }
        public string AnimationRef { get; set; }

        public ICommand OnBtnOkTapped = new Command(async () => { await PopupNavigation.Instance.PopAllAsync(); });

        public ReservationResultViewModel(ReservationStatus status)
        {
            switch (status.status)
            {
                case ReservationStatus.Status.Booked:
                    //
                    ResponseTitle = "Booked!";
                    ResponseMessage = "We've received your reservation, see you then!";
                    AnimationRef = "1166-tick.json";
                    break;
                case ReservationStatus.Status.Full:
                    //
                    ResponseTitle = "Well this is embarrassing...";
                    ResponseMessage = "Looks like this is a really popular time and we're full. Head over to the Contact page though, we still might be able to help!";
                    AnimationRef = "4284-notification.json";
                    break;
                case ReservationStatus.Status.HttpError:
                    //
                    ResponseTitle = "Hmmm...";
                    ResponseMessage = "Something went wrong, but we're pretty sure its our fault. Can you check your form and try again?";
                    AnimationRef = "3932-error-cross.json";
                    break;
                case ReservationStatus.Status.ServerUnavailable:
                    //
                    ResponseTitle = "It's not you, it's me...";
                    ResponseMessage = "So sorry, it looks like the reservation service is down! Please head over to the Contact page, or try again later.";
                    AnimationRef = "4386-connection-error.json";
                    break;
            }

        }
    }
}

视图背后的代码:

using System;
using System.Collections.Generic;
using Rg.Plugins.Popup.Pages;
using Rg.Plugins.Popup.Services;
using MyAPp.Models;
using MyApp.ViewModels;
using Xamarin.Forms;

namespace MyApp.PopUpPages
{
    public partial class ReservationResult : PopupPage
    {
        public ReservationResultViewModel viewModel { get; set; }

        public ReservationResult(ReservationResultViewModel vm)
        {
            InitializeComponent();
            viewModel = vm;
            BindingContext = viewModel;
        }

        async void Handle_Clicked(object sender, System.EventArgs e)
        {
            await PopupNavigation.Instance.PopAllAsync();
            //throw new NotImplementedException();
        }
    }
}

【问题讨论】:

  • 您是否还在为此寻找ViewModel 解决方案,或者您对现有的感到满意?
  • 我更喜欢视图模型解决方案,尽管我当然可以用我现在所拥有的东西来发布它。但我想我还是想弄清楚为什么会这样。
  • 好的,所以我需要知道两件事,第一是您的命令之前在点击事件上工作,第二如果之前没有工作,您是否有单独的 ViewModel 用于弹出窗口
  • 是的,我有一个单独的 ViewModel 用于弹出窗口,这是我在问题中指的 ViewModel,而不是调用它的页面的 ViewModel。不能说它以前是否有效,我把它内置到弹出窗口中,我没有移动我已经在那里的东西。而且我没有使用 Clicked 对其进行测试,直到它不适用于 ViewModel 中的命令。
  • 您可以在问题中添加ViewModelView(xaml 和cs)吗?

标签: xamarin.forms


【解决方案1】:

所有 UI 特定的操作都需要在设备主线程(UI 线程)上执行。

所以你的命令应该是这样的:

public ICommand OnBtnOkTapped = new Command( Device.BeginInvokeOnMainThread(() => {PopupNavigation.Instance.PopAllAsync()} );

【讨论】:

  • 这似乎不正确。首先,当我从 Clicked 事件处理程序而不是命令调用它时,它工作得很好,无需针对主线程运行。其次,这并不能解释为什么这个方法在页面加载时被调用,而在我点击按钮时没有被调用(它是否有效甚至不是这里的问题,因为它没有被调用)。
  • 抱歉,您的情况有误。我虽然执行了按钮命令,但没有任何反应。再次查看您的代码,我注意到您 ICommand OnBtnTapped 只是一个字段而不是属性。尝试将其更改为 public public ICommand OnBtnOkTapped { get;内部集; } = 新命令(...)
  • 如果您想更新您的问题以反映这一点,并且如果您还可以回答为什么在页面加载时会触发命令的问题,我会接受您的回答。
【解决方案2】:

好的,您必须进行以下更改:

将命令添加到按钮(XAML),如下所示:

 Command="{Binding MoreButtonCommand}" 

将相同的属性添加到您的 ViewModel 类中,如下所示:

public ICommand MoreButtonCommand { get; set; }

在你的 ViewModel 的构造函数中初始化这个属性:

MoreButtonCommand = new Command(MoreButtonPressed);

然后制作一个返回void的方法作为命令的参数传递:

 private async void MoreButtonPressed(object obj)
    {
       await PopupNavigation.Instance.PopAllAsync();
    }

如果不能随意恢复,这应该对你有用

祝你好运

编辑:

原因,因为这不起作用,是因为您使用了一个字段,现在 FIELD 不是您与 BindingProperty 连接的内容。绑定属性仅接受属性,即 public ICommand MoreButtonCommand { get; set; } 作为其输入因此您之前无法连接它,但现在它可以工作了

【讨论】:

  • 谢谢。我应该澄清一下 - 按钮的代码现在已连接到 Clicked 事件处理程序,因为我对其进行了更改,因此它至少可以正常工作。您可以从问题中的原始代码中看到,我之前将它连接为命令,但它不起作用,并且从我将其更改为 Clicked 事件处理程序的编辑中可以看到。因此,除此之外,您的答案最终是要将 ICommand 从字段更改为属性。我会试试这个,但仅供参考,这也是@Jannik R. 在对他们上面的回答的评论中提供的。
  • 它不起作用的主要原因是因为它是一个字段,一旦您将其更改为属性并将其连接起来,如我上面所示,它将起作用,请确保删除事件处理程序在使用命令之前从 XAML 中获取,否则您将不知道它是否有效
  • 谢谢,我刚刚试过,它有效。您能否解释一下为什么当命令是一个字段时,当页面加载到您的答案时它会被调用?那我就接受了。
  • 好的,我给我一分钟
  • @MattG 我加了原因看看
猜你喜欢
  • 2019-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多