Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin.Forms Content of a button

I'm trying to add a custom content to a button in Xamarin Forms.

By default Button is created like this:

<Button d:DataContext="{d:DesignInstance viewModel:AssessmentItemCategory}"
                        Clicked="Button_OnClicked"
                        Style="{StaticResource CategoryButtonStyle}"
                        Text={Binding Text} />

But I would like to create custom content of this button. Normally with WPF I would do it like this:

<Button d:DataContext="{d:DesignInstance viewModel:AssessmentItemCategory}"
          Clicked="Button_OnClicked"
        Style="{StaticResource CategoryButtonStyle}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="20" />
        </Grid.ColumnDefinitions>
        <Label Text="{Binding Text}" Grid.Column="0" TextColor="Black"/>
        <Label Text="-" Grid.Column="1" TextColor="Black"/>
    </Grid>

</Button>

But this isn't working.

I was also looking for a DataTemplate property, but haven't found this.

How to do it in Xamarin.Forms?

like image 1000
Tomasz Avatar asked Apr 17 '15 08:04

Tomasz


3 Answers

Thanks Paul,

I have created my own UserControl which handles that

Here it is:

public partial class ContentButton : ContentView
{
    public ContentButton()
    {
        InitializeComponent();
    }

    public event EventHandler Tapped;

    public static readonly BindableProperty CommandProperty = BindableProperty.Create<ContentButton, ICommand>(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());
    }
}

And view code:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="RFA.Wireframes.Controls.ContentButton"
             x:Name="ContentButtonView">
  <ContentView.GestureRecognizers>
    <TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped" Command="{Binding Source={x:Reference ContentButtonView}, Path=Command}"></TapGestureRecognizer>
  </ContentView.GestureRecognizers>

</ContentView>
like image 138
Tomasz Avatar answered Oct 27 '22 22:10

Tomasz


Unfortunately, at the moment Xamarin.Forms does not support a Content property for the Button.

You would have to create your own User Control with a combination of other controls to try and recreate a Button control. You could then make part of your User Control a ContentView, create a BindableProperty to bind your Grid to, then use the a BindingPropertyChangedDelegate to assign the Content property of your ContentView.

like image 21
Paul Diston Avatar answered Oct 27 '22 23:10

Paul Diston


Thanks Tomasz, good inspiration. However for me, your control didn´t pick up the tap-event on all platforms and used obsolete Xamarin.Forms methods "BindableProperty.Create<" and . So I came up with this one.

Here it is:

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);
    }
}
like image 23
Till Avatar answered Oct 27 '22 23:10

Till