Xamarin 自定义视图按钮绑定

Xamarin Custom View Button Binding

我有一个自定义视图,里面有 2 个按钮 - 一个在左边,一个在右边。

我想有一个可绑定的属性来指定每个按钮将调用哪个函数,但我想调用的函数在原始内容页面中,而不是自定义控件中。

我知道你不能将 void 作为可绑定对象 属性 所以我不确定如何实现这一点。

这是我的自定义控件 xaml:

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="EngineerApp.HeaderBar"  HeightRequest="50">
    <BoxView x:Name="banner" BackgroundColor="#edeff2"
        RelativeLayout.WidthConstraint="{ ConstraintExpression 
            Type=RelativeToParent,
            Property=Width,
            Factor=1 }"
        RelativeLayout.HeightConstraint="{ ConstraintExpression 
        Type=RelativeToParent,
        Property=Height,
        Factor=1 }">
    </BoxView>
    <Button 
        Text="Left"
        x:Name="btnLeft"
        Style="{StaticResource headerBarButton}"
        RelativeLayout.WidthConstraint="{ ConstraintExpression 
            Type=RelativeToView,
            ElementName=banner,
            Property=Width,
            Factor=0.5 }"       
        RelativeLayout.HeightConstraint="{ ConstraintExpression 
            Type=RelativeToView,
            ElementName=banner,
            Property=Height,
            Factor=1 }"
        >
    </Button>
    <Button 
        Text="Right" 
        Style="{StaticResource headerBarButton}"
        RelativeLayout.XConstraint="{ ConstraintExpression 
            Type=RelativeToView,
            ElementName=banner,
            Property=Width, 
            Factor=0.5,
            Constant=1
        }"
        RelativeLayout.WidthConstraint="{ ConstraintExpression 
            Type=RelativeToView,
            ElementName=banner,
            Property=Width,
            Factor=0.5 }"       
        RelativeLayout.HeightConstraint="{ ConstraintExpression 
            Type=RelativeToView,
            ElementName=banner,
            Property=Height,
            Factor=1 }"
        >
    </Button>
</RelativeLayout>

这是后端代码:

using System;
using System.Collections.Generic;
using System.Windows.Input;
using Xamarin.Forms;

namespace EngineerApp
{
    public partial class HeaderBar : RelativeLayout
    {

        public HeaderBar()
        {

            InitializeComponent();
        }

    }
}

最后,我像往常一样在

中加入了自定义新内容
<local:HeaderBar></local:HeaderBar>

如何将 2 个按钮的单击事件中的每一个绑定到我的内容页面中的方法?

我遇到了类似的问题。 我创建了一个 CalculatorPage.xaml(我的自定义控件)和一个链接的 CalculatorViewModel。

对于自定义控件中的每个按钮:

    <Button Grid.Row="0" Grid.Column="1" Font="Large" Command="{Binding Calculator.KeyPressCommand}" CommandParameter="Eight" Text="8" />

在上面的示例中,"KeyPressCommand" 存在于 CalculatorViewModel 中。但是 "Calculator" 不存在。

我新建了一个MainView(我的主View)和对应的MainViewModel。

像你一样,我在 XAML 中包含自定义控件,如下所示:

<common:CalculatorView></common:CalculatorView>

在 MainViewModel 中,我有一个 属性

public CalculatorViewModel Calculator { get; private set; } = new CalculatorViewModel();

您定义自定义控件的 BindingContext 可能有更好的解决方案,但我的解决方案运行良好

解决方案一

您可以在自定义控件中公开几个事件。

步骤:

  1. 在自定义 HeaderBar 控件中创建 2 个事件。

    public event EventHandler RightButtonClickEvent;
    public event EventHandler LeftButtonClickEvent;
    
  2. 在XAML中分配Clicked个事件处理程序,并在其中调用这些事件

    void RightButton_Clicked(object sender, EventArgs e)
    {
        RightButtonClickEvent?.Invoke(sender, e);
    }
    
    void LeftButton_Clicked(object sender, EventArgs e)
    {
        LeftButtonClickEvent?.Invoke(sender, e);
    }
    
  3. 将自定义事件与 ContentPage

    中的事件处理程序绑定
    <local:HeaderBar
       RightButtonClickEvent="OnRightButtonClick"
       LeftButtonClickEvent="OnLeftButtonClick" />
    

示例代码 - HeaderBar.xaml.cs

public partial class HeaderBar : RelativeLayout
{
    public HeaderBar()
    {
        InitializeComponent();
    }

    public event EventHandler RightButtonClickEvent;
    public event EventHandler LeftButtonClickEvent;

    void RightButton_Clicked(object sender, EventArgs e)
    {
        RightButtonClickEvent?.Invoke(sender, e);
    }

    void LeftButton_Clicked(object sender, EventArgs e)
    {
        LeftButtonClickEvent?.Invoke(sender, e);
    }
}

更新了示例代码 - HeaderBar.xaml

<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="EngineerApp.HeaderBar"  HeightRequest="50">
<BoxView x:Name="banner" BackgroundColor="#edeff2"
    RelativeLayout.WidthConstraint="{ ConstraintExpression 
        Type=RelativeToParent,
        Property=Width,
        Factor=1 }"
    RelativeLayout.HeightConstraint="{ ConstraintExpression 
    Type=RelativeToParent,
    Property=Height,
    Factor=1 }">
</BoxView>
<Button 
    Text="Left"
    x:Name="btnLeft"
    Clicked="LeftButton_Clicked"
    Style="{StaticResource headerBarButton}"
    RelativeLayout.WidthConstraint="{ ConstraintExpression 
        Type=RelativeToView,
        ElementName=banner,
        Property=Width,
        Factor=0.5 }"       
    RelativeLayout.HeightConstraint="{ ConstraintExpression 
        Type=RelativeToView,
        ElementName=banner,
        Property=Height,
        Factor=1 }"
    >
</Button>
<Button 
    Text="Right" 
    x:Name="btnRight"
    Clicked="RightButton_Clicked"
    Style="{StaticResource headerBarButton}"
    RelativeLayout.XConstraint="{ ConstraintExpression 
        Type=RelativeToView,
        ElementName=banner,
        Property=Width, 
        Factor=0.5,
        Constant=1
    }"
    RelativeLayout.WidthConstraint="{ ConstraintExpression 
        Type=RelativeToView,
        ElementName=banner,
        Property=Width,
        Factor=0.5 }"       
    RelativeLayout.HeightConstraint="{ ConstraintExpression 
        Type=RelativeToView,
        ElementName=banner,
        Property=Height,
        Factor=1 }"
    >
</Button>
</RelativeLayout>

示例代码 - MyContentPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
  xmlns:local="clr-namespace:EngineerApp" 
  x:Class="EngineerApp.MyContentPage">
  <local:HeaderBar
    RightButtonClickEvent="OnRightButtonClick"
    LeftButtonClickEvent="OnLeftButtonClick" />
</ContentPage>

示例代码 - MyContentPage.xaml.cs

public partial class MyContentPage : ContentPage
{
    public MyContentPage()
    {
        InitializeComponent();
    }

    void OnRightButtonClick(object sender, EventArgs e)
    {
        //handle right-button click here
    }

    void OnLeftButtonClick(object sender, EventArgs e)
    {
        //handle left-button click here
    }
}

解决方案 2(如果您使用 MVVM,推荐使用)

将两个命令公开为可绑定属性(这些属性又将绑定到内部按钮控件)。然后,您可以将这些新命令绑定到 ContentPageViewModel

中的属性

示例代码 - Header.xaml.cs

public partial class HeaderBar : RelativeLayout
{
    public HeaderBar()
    {
        InitializeComponent();

        //create binding between parent control and child controls
        btnLeft.SetBinding(Button.CommandProperty, new Binding(nameof(LeftButtonCommand), source: this));
        btnRight.SetBinding(Button.CommandProperty, new Binding(nameof(RightButtonCommand), source: this));
    }

    public static readonly BindableProperty LeftButtonCommandProperty =
        BindableProperty.Create(
        "ILeftButtonCommand", typeof(ICommand), typeof(HeaderBar),
            defaultValue: null);

    public ICommand LeftButtonCommand
    {
        get { return (ICommand)GetValue(LeftButtonCommandProperty); }
        set { SetValue(LeftButtonCommandProperty, value); }
    }

    public static readonly BindableProperty RightButtonCommandProperty =
        BindableProperty.Create(
        "RightButtonCommand", typeof(ICommand), typeof(HeaderBar),
            defaultValue: null);

    public ICommand RightButtonCommand
    {
        get { return (ICommand)GetValue(RightButtonCommandProperty); }
        set { SetValue(RightButtonCommandProperty, value); }
    }
} 

示例代码 - MyContentPage.xaml

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
  xmlns:local="clr-namespace:EngineerApp" 
  x:Class="EngineerApp.MyContentPage">
  <local:HeaderBar
      LeftButtonCommand="{Binding LeftClickCommand}"
      RightButtonCommand="{Binding RightClickCommand}" />
</ContentPage>

示例代码 - MyContentPageViewModel.cs

public class MyContentPageViewModel : ViewModelBase //base implementation for INotifyPropertyChanged
{
    private ICommand _leftClickCommand; 
    public ICommand LeftClickCommand
    {
        get
        {
            return _leftClickCommand ??
                (_leftClickCommand = new Command((obj) =>
                {
                    //handle left button click here.
                }));
        }
    }

    private ICommand _rightClickCommand;
    public ICommand RightClickCommand
    {
        get
        {
            return _rightClickCommand ??
                (_rightClickCommand = new Command((obj) =>
                {
                    //handle right button click here.
                }));
        }   
    }
}