12

Isn't there anything like a LinkButton in Xamarin?

I want to create a label with the looks of an url link that once tapped opens the external browser.

I also need to know how to open the device's external browser (to open an specified url) in a Portable Project.

Thanks

3 Answers 3

11

The Xamarin.Forms way to open an URL string in the default mobile browser:

Device.OpenUri(new Uri("http://example.com"))

While a Forms' Label does not have a click event, you can add a TapGestureRecognizer so when the label is tapped it executes Device.OpenUri.

Example:

var myURLLabel = new Label
{
    Text = "https://xamarin.com"
};

myURLLabel.GestureRecognizers.Add(new TapGestureRecognizer
{
    Command = new Command(() => {
        Device.OpenUri(new Uri(myURLLabel.Text));
    })
});

Xamarin-Forms-Labs' ExtendedLabel allows you style a label's text as underlined....

Ref: https://github.com/XLabs/Xamarin-Forms-Labs/wiki/ExtendedLabel

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Sad that I need an external lib. Xamarin is looking very disappointing.
2

Create a label that can display underlined (or use Xamarin Forms Labs ExtendedLabel):

using Xamarin.Forms;

public class ExtendedLabel : Label
{
    public static readonly BindableProperty IsUnderlinedProperty = BindableProperty.Create<ExtendedLabel, bool>(p => p.IsUnderlined, false);

    public bool IsUnderlined
    {
        get { return (bool)GetValue(IsUnderlinedProperty); }
        set { SetValue(IsUnderlinedProperty, value); }
    }

    // ...other custom properties

}

Handle the IsUnderlined property in your custom renderers:

public class ExtendedLabelRenderer : LabelRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
    {
        base.OnElementChanged(e);

        // ...
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName == ExtendedLabel.IsUnderlinedProperty.PropertyName)
        {
            RefreshControl(Control);
        }
    }

    private void RefreshControl(UILabel control)
    {
        if (control == null) return;

        // Apply based on IsUnderlined property
        if (!string.IsNullOrEmpty(control.Text)) control.AttributedText = new NSMutableAttributedString(control.Text, underlineStyle: view.IsUnderlined ? NSUnderlineStyle.Single : NSUnderlineStyle.None);            

        // ...apply based on other custom properties
    }
}

Add your label control to YourPage.xaml and add a gesture recognizer to handle tap:

<controls:ExtendedLabel
    Text="View in browser"
    TextColor="Blue"
    IsUnderlined="True">
    <controls:ExtendedLabel.GestureRecognizers>
        <!--TODO:<TapGestureRecognizer Command="TapCommand" /> Couldn't do this for some reason so use Tapped handler-->
        <TapGestureRecognizer
            Tapped="OnOpenInBrowserTapGestureRecognizerTapped"
            NumberOfTapsRequired="1" />
    </controls:ExtendedLabel.GestureRecognizers>
</controls:ExtendedLabel>

Handle the tap in code behind YourPage.xaml.cs:

private void OnOpenInBrowserTapGestureRecognizerTapped(object sender, EventArgs args)
{
    var labelViewSender = (ExtendedLabel)sender;

    labelViewSender.Opacity = 0.6;
    labelViewSender.FadeTo(1);

    var viewModel = BindingContext as YourPageViewModel;
    if (viewModel == null) return;

    if (viewModel.NavigateToUrlCommand.CanExecute(null)) viewModel.NavigateToUrlCommand.Execute(null);
}

The view model:

public class YourPageViewModel : ViewModelBase
{
    public const string NavigateToUrlMessage = "NavigateToUrl";

    private string _url;
    public string Url
    {
        get { return _url; }
        set { SetProperty(ref _url, value); }
    }

    //...

    private Command _navigateToUrlCommand;
    public ICommand NavigateToUrlCommand
    {
        get { return _navigateToUrlCommand ?? (_navigateToUrlCommand = new Command(param => NavigateToUrl(), CanNavigateToUrl)); }
    }

    public bool CanNavigateToUrl(object parameter) => true;

    private void NavigateToUrl()
    {
        MessagingCenter.Send(this, NavigateToUrlMessage, Url);
    }

    //...
}

Subscribe to and handle the NavigateToUrlMessage message in the YourPage.xaml.cs code behind:

    protected override void OnAppearing()
    {
        MessagingCenter.Subscribe<YourPageViewModel, string>(this, YourPageViewModel.NavigateToUrlMessage, (sender, args) =>
        {
            var context = (BindingContext as YourPageViewModel);
            if (context == null) return;

            if (string.IsNullOrEmpty(args)) return;

            Device.BeginInvokeOnMainThread(() =>
            {
                Device.OpenUri(new Uri(args));
            });
        });

        //...

        base.OnAppearing();
    }

    protected override void OnDisappearing()
    {
        MessagingCenter.Unsubscribe<YourPageViewModel, string>(this, YourPageViewModel.NavigateToUrlMessage);

        //...

        base.OnDisappearing();
    }

1 Comment

Wow! Thanks! But if I need all that just for a LinkButton I'd ratter learn Objective C. I could do the same thing in an Android and an iOS project faster than once in Xamarin. I'm beginning to think this Xamarin is a waste of time. It's not that new to lack such a simple thing.
0

For Xamarin.Forms 3.2 and above

<Label>
    <Label.FormattedText>
        <FormattedString>
            <Span Text="{Binding Url, Mode=OneWay}" TextColor="Blue">
                <Span.GestureRecognizers>
                        <TapGestureRecognizer 
                            Command="{Binding TapCommand, Mode=OneWay}"
                            CommandParameter="https://www.xamarin.com"/>
                </Span.GestureRecognizers>
            </Span>
        </FormattedString>
    </Label.FormattedText>
</Label>

You may use commands with or without parameters, or just the tapped event.

Example :

<Label>
            <Label.FormattedText>
                <FormattedString>
                    <Span Text="Xamarin" TextColor="Blue">
                        <Span.GestureRecognizers>
                            <TapGestureRecognizer 
                                Command="{Binding TapCommand, Mode=OneWay}"
                                CommandParameter="https://www.xamarin.com"/>
                        </Span.GestureRecognizers>
                    </Span>
                </FormattedString>
            </Label.FormattedText>
        </Label>

in the ViewModel :

private ICommand _tapCommand;
public ICommand TapCommand =>
_tapCommand ?? (_tapCommand = new Command<string>(OpenUrl));

void OpenUrl(string url)
{
   Device.OpenUri(new Uri(url));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.