Xamarin.Forms按钮的内容

我正在尝试将自定义内容添加到Xamarin Forms中的按钮。

默认情况下,按钮创建如下:

但我想创建此按钮的自定义内容。 通常使用WPF,我会这样做:

  

但这不起作用。

我也在寻找一个DataTemplate属性,但还没有找到它。

如何在Xamarin.Forms中做到这一点?

谢谢保罗,

我创建了自己的UserControl来处理它

这里是:

 public partial class ContentButton : ContentView { public ContentButton() { InitializeComponent(); } public event EventHandler Tapped; public static readonly BindableProperty CommandProperty = BindableProperty.Create(c => c.Command, null); public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } private void TapGestureRecognizer_OnTapped(object sender, EventArgs e) { if(Tapped != null) Tapped(this,new EventArgs()); } } 

并查看代码:

       

感谢Tomasz,很好的灵感。 但对我来说,你的控件没有在所有平台上获取tap事件,并使用过时的Xamarin.Forms方法“BindableProperty.Create <”和。 所以我想出了这个。

这里是:

 public class ContentButton:ContentView { private readonly TapGestureRecognizer _tapGestureRecognizer; public ContentButton() { _tapGestureRecognizer = new TapGestureRecognizer(); GestureRecognizers.Add(_tapGestureRecognizer); } protected override void OnChildAdded(Element child) { base.OnChildAdded(child); if (child is View childview) { childview.GestureRecognizers.Add(_tapGestureRecognizer); } } public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(ContentButton), null, BindingMode.Default, null, CommandPropertyChanged); private static void CommandPropertyChanged(BindableObject bindable, object oldValue, object newValue) { if (newValue is ICommand command && bindable is ContentButton contentButton) { contentButton._tapGestureRecognizer.Command = command; } } public ICommand Command { get => (ICommand)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } } 

不幸的是,目前Xamarin.Forms不支持Button的Content属性。

您必须使用其他控件的组合创建自己的用户控件,以尝试重新创建Button控件。 然后,您可以将用户控件的一部分作为ContentView,创建BindableProperty以将Grid绑定到,然后使用BindingPropertyChangedDelegate分配ContentView的Content属性。

感谢Tomasz创建ContentButton

我已成功使用它,以类似的方式添加CommandParameter

    public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(ContentButton)); public object CommandParameter { get { return (object)GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } 

我偶然发现了一个问题,结果certificate这是最近描述的一个错误。

它迫使我进行下面的黑客攻击,我认为这对其他人来说很有用。 在ShoppingCartSummaryView直接设置BackgroundColorTapGestureRecognizer不起作用。

        

这是我对带内容的按钮的实现,它有一些额外的东西可以更好地模仿实际的按钮:

  • ICommand Command
  • object CommandParameter
  • 事件:
    • Clicked
    • Pressed
    • Released
    • VisuallyPressedChanged (应该更改按钮的样式以让用户知道按钮已被按下时发生)

它使用TouchTracking.Forms包处理触摸事件,您可以使用NuGet下载它。

 public class ContentButton : ContentView { public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(ContentButton), null, BindingMode.Default); public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(ContentButton)); ///  /// Occurs when the Button is clicked. ///  public event EventHandler Clicked; ///  /// Occurs when the Button is pressed. ///  public event EventHandler Pressed; ///  /// Occurs when the Button is released. /// The released event always occur before the clicked event. ///  public event EventHandler Released; ///  /// Occurs when the style of the button should be changed to let the user know that the button has been pressed. /// If the argument is true, it means that the Button was just pressed. /// If the argument is false, it means that the Button was just released or that the user has moved his finger out of the buttons boundaries. ///  public event EventHandler VisuallyPressedChanged; ///  /// Gets or sets the command to invoke when the button is activated. This is a bindable property. ///  public ICommand Command { get => (ICommand)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } ///  /// Gets or sets the parameter to pass to the Command property. This is a bindable property. ///  public object CommandParameter { get => GetValue(CommandParameterProperty); set => SetValue(CommandParameterProperty, value); } private bool isVisuallyPressed; public ContentButton() { var touchEffect = new TouchEffect { Capture = true }; touchEffect.TouchAction += TouchEffect_TouchAction; Effects.Add(touchEffect); } protected override void OnChildAdded(Element child) { base.OnChildAdded(child); // so that the touch events are ignored and bypassed to this control if(child is VisualElement visualChild) { visualChild.InputTransparent = true; } } private long? currentId; private object touchEffect_lock = new object(); private void TouchEffect_TouchAction(object sender, TouchActionEventArgs e) { // only track one touch if(currentId != e.Id && e.Type!=TouchActionType.Pressed) { return; } lock(touchEffect_lock) { switch(e.Type) { case TouchActionType.Pressed: currentId = e.Id; Pressed?.Invoke(this, EventArgs.Empty); isVisuallyPressed = true; VisuallyPressedChanged?.Invoke(this, true); break; case TouchActionType.Moved: if(isVisuallyPressed) { bool isInside = e.Location.X >= 0 && e.Location.Y >= 0 && e.Location.X <= Bounds.Width && e.Location.Y <= Bounds.Height; if(!isInside) { isVisuallyPressed = false; VisuallyPressedChanged?.Invoke(this, false); } } break; case TouchActionType.Cancelled: currentId = null; isVisuallyPressed = false; VisuallyPressedChanged?.Invoke(this, false); break; case TouchActionType.Released: currentId = null; if(isVisuallyPressed) { Released?.Invoke(this, EventArgs.Empty); Clicked?.Invoke(this, EventArgs.Empty); if(Command != null && Command.CanExecute(CommandParameter)) { Command.Execute(CommandParameter); } isVisuallyPressed = false; VisuallyPressedChanged?.Invoke(this, false); } break; } } } }