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 可能有更好的解决方案,但我的解决方案运行良好
解决方案一
您可以在自定义控件中公开几个事件。
步骤:
在自定义 HeaderBar
控件中创建 2 个事件。
public event EventHandler RightButtonClickEvent;
public event EventHandler LeftButtonClickEvent;
在XAML中分配Clicked
个事件处理程序,并在其中调用这些事件
void RightButton_Clicked(object sender, EventArgs e)
{
RightButtonClickEvent?.Invoke(sender, e);
}
void LeftButton_Clicked(object sender, EventArgs e)
{
LeftButtonClickEvent?.Invoke(sender, e);
}
将自定义事件与 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,推荐使用)
将两个命令公开为可绑定属性(这些属性又将绑定到内部按钮控件)。然后,您可以将这些新命令绑定到 ContentPage
的 ViewModel
中的属性
示例代码 - 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.
}));
}
}
}
我有一个自定义视图,里面有 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 可能有更好的解决方案,但我的解决方案运行良好
解决方案一
您可以在自定义控件中公开几个事件。
步骤:
在自定义
HeaderBar
控件中创建 2 个事件。public event EventHandler RightButtonClickEvent; public event EventHandler LeftButtonClickEvent;
在XAML中分配
Clicked
个事件处理程序,并在其中调用这些事件void RightButton_Clicked(object sender, EventArgs e) { RightButtonClickEvent?.Invoke(sender, e); } void LeftButton_Clicked(object sender, EventArgs e) { LeftButtonClickEvent?.Invoke(sender, e); }
将自定义事件与
中的事件处理程序绑定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,推荐使用)
将两个命令公开为可绑定属性(这些属性又将绑定到内部按钮控件)。然后,您可以将这些新命令绑定到 ContentPage
的 ViewModel
示例代码 - 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.
}));
}
}
}