如何在Xamarin.Forms页面中通过XAML将按钮作为CommandParameter传递?

23
我想将Xamarin.Forms.Button传递到自己的Command中作为CommandParameter到我的ViewModel。我知道如何从代码后台实现这一点,例如...

XAML(省略大多数属性)


<Button x:Name="myButton"
    Text="My Button"
    Command="{Binding ButtonClickCommand}"/>

XAML.cs

public partial class MyTestPage
{
    public MyTestPage()
    {
        InitializeComponent();

        myButton.CommandParameter = myButton;
    }
}

视图模型

public class MyViewModel : ViewModelBase
{
    public MyViewModel()
    {
        ButtonClickCommand = new Command(
            (parameter) =>
            {
                var view = parameter as Xamarin.Forms.Button;
                if (view != null)
                {
                    // Do Stuff
                }
            });
    }

    public ICommand ButtonClickCommand { get; private set; }
}

...但是在XAML本身中声明CommandParameter是否可能?换句话说,如何使用绑定语法将参数设置为按钮本身?

<Button x:Name="myButton"
        Text="My Button"
        Command="{Binding ButtonClickCommand}"
        CommandParameter="{[WHAT WOULD GO HERE]}"/>
< p>顺便说一句,我已经尝试过 CommandParameter="{Binding RelativeSource={RelativeSource Self}}",但那样做不起作用。

谢谢,


为什么你的虚拟机需要这个按钮? - Alex Anderson
嗨@AlexAnderson。是的,我也不是特别热衷于它。我们正在将Xamarin.Forms引入现有的Xamarin iOS项目中。只是试验从Xamarin.Form页面显示本地UIPopoverController的方法。目前没有Forms支持弹出窗口,所以只是在寻找解决方法,其中一个障碍是我需要知道从哪个UIElement显示弹出窗口...因此传递按钮。就像我说的...感觉有点假。我会尝试你下面的建议。谢谢。 - Gavin Sutherland
关于弹出窗口,请查看 ContentPage.DisplayActionSheet(...) 的实现 - 如果操作表不够用,您可以反向工程显示它的代码。而获取按钮引用仍需要从其中找到 UIButton 引用。使用自定义渲染器会更好。 - Sten Petrov
嗨@StenPetrov。创建弹出窗口的自定义渲染器的问题在于UIPopoverController是NSObject而不是UIView对象。 - Gavin Sutherland
4个回答

32

Xamarin.Forms具有一个引用标记扩展,可以实现这一点:

Xamarin.Forms具有一个Reference标记扩展,可以实现这一点:

<Button x:Name="myButton"
    Text="My Button"
    Command="{Binding ButtonClickCommand}"
    CommandParameter="{x:Reference myButton}"/>

虽然这是我第一次看到这个需求,你可能更好地将你的视图与视图模型分离,并通过使用更清晰的模式或者不要跨按钮共享命令来解决这个问题。


嗨@StephaneDelcroix。不幸的是,那也没用..“目标调用引发了异常。” - Gavin Sutherland
对不起,@GavinSutherland,但是我刚在1.2.3-pre-2上测试了一下,它的表现和预期的一样。 - Stephane Delcroix
嗨@StephaneDelcroix。我会检查命名空间和xf版本。如果它们是最新的,那么我可能会在一个空项目中尝试它。感谢更新。 - Gavin Sutherland
嗨@StephaneDelcroix。我正在使用v1.2.2,我声明了以下命名空间:xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"。这看起来正确吗? - Gavin Sutherland
@GavinSutherland:是的,没问题。我还没有尝试过1.2.2版本。 - Stephane Delcroix
显示剩余4条评论

8
 <Button x:Name="myButton"
        Text="My Button"
        Command="{Binding ButtonClickCommand}"
        CommandParameter="{x:Reference myButton}"/>

在你的ViewModel中
public YourViewModel()
{
    ButtonClickCommand= new Command(ButtonClicked);
}

private async void ButtonClicked(object sender)
{
    var view = sender as Xamarin.Forms.Button;
}

2
无法与Prism一起工作,传递命令时要求参数。 - R15
1
谢谢!这真的帮了我很多。 - Wouter Klopper

3

一种简单的方法是:

在XAML中:

 <Button Text="BUTTON-TEST"
            Clicked="Avaliar"
            CommandParameter="like"/>

在C#中:

private void Avaliar(object sender, EventArgs e)
{
     Console.WriteLine(((Button)sender).CommandParameter);
}

不遵循MVVM,我猜这就是为什么OP在使用VM的原因。 - Sparers

0
<Button x:Name="myButton"
    Text="My Button"
    Command="{Binding ButtonClickCommand}"
    CommandParameter={Binding RelativeSource=
                               {RelativeSource
                                Mode=FindAncestor,
                                AncestorType={x:Type Button}}/>

应该可以工作,但我仍然不明白为什么你需要这个按钮?MVVM 的重点是将数据和 UI 分离。你需要做的一切与按钮有关的事情都可以通过 DataBindings 完成。

如果上述方法不起作用,唯一尝试的另一件事就是给按钮一个 x:Key,并将 CommandParamter 设置为 {StaticResource 'x:Key'}


2
Xamarin.Forms 绑定没有任何 RelativeSource 属性,也没有 RelativeSource 标记扩展。 - Stephane Delcroix
1
嗨@AlexAnderson...很抱歉,这些建议都没有起作用。 - Gavin Sutherland
@Alex 如果你想改变Caller按钮的VisualState,我认为我们需要这样做。 - Sumit Gupta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接