When displaying textual information to your user, you want it to be well displayed with good font size, appropriate style, text color… But you also want the user to edit this information with minimum efforts. You can build a custom control in Xamarin Forms for this purpose. Let’s say you have a page in your app with a title, or several labels containing text. And you want the user to edit these as he wish, without switching to a new page. A good scenario will be to tap on the label and edit the test as it focus and display the text as it was, when focus is lost.

This is seen already in several applications. It could be achieved easily in Xamarin Forms by applying custom modifications to Android’s EditText and iOS’ UITextField, then call these as Custom Renderers. But we will achieve this using XAML and only code in the shared project. This blog post is about building this edit label custom control in xamarin forms xaml.

An overview of the control

This control is not complicated and the logic behind it is that. It behaves like a text entry when focused and it behaves like a label when it loses focused. So, to implement it in Xamarin Forms XAML, we will use a contentview, leverage Visual States, Gesture Recognizers and add a few bindable properties to make our control.

Here is the source code for this control

Building our custom control in

Xamarin Forms

First, we create a ContentView which will have the atrribute (x:Name=”thisEdiableLabel”), this attribute will be used for referencing in XAML.

We then add a bunch of bindable properties which will be used to customize our control. The most important property here is the “IsFocusedMode” Property, which we will use to play with the views contained in the ContentView.

public static readonly BindableProperty IsFocusedModeProperty = BindableProperty.Create("IsFocusedMode", typeof(bool), typeof(EditableLabel), default(bool), propertyChanged: OnIsFocusedModePropertyChanged); public bool IsFocusedMode { get { return (bool)GetValue(IsFocusedModeProperty); } set { SetValue(IsFocusedModeProperty, value); } } 1 2 3 4 5 6 public static readonly BindableProperty IsFocusedModeProperty = BindableProperty . Create ( "IsFocusedMode" , typeof ( bool ) , typeof ( EditableLabel ) , default ( bool ) , propertyChanged : OnIsFocusedModePropertyChanged ) ; public bool IsFocusedMode { get { return ( bool ) GetValue ( IsFocusedModeProperty ) ; } set { SetValue ( IsFocusedModeProperty , value ) ; } }

Initially, our control will need to display already available information. So, the content view’s primary content is a label to display this information. This ContentView will switch to edit mode once the Label gets tapped as shown below.

<Label x:Name="MainLabel" FontAttributes="{Binding FontAttributes, Source={x:Reference thisEdiableLabel}}" FontFamily="{Binding FontFamily, Source={x:Reference thisEdiableLabel}}" Text="{Binding Text, Source={x:Reference thisEdiableLabel}, Mode=TwoWay}" TextColor="{Binding TextColor, Source={x:Reference thisEdiableLabel}}" FontSize="{Binding FontSize, Source={x:Reference thisEdiableLabel}}"> <Label.GestureRecognizers> <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/> </Label.GestureRecognizers> </Label> 1 2 3 4 5 6 < Label x : Name = "MainLabel" FontAttributes = "{Binding FontAttributes, Source={x:Reference thisEdiableLabel}}" FontFamily = "{Binding FontFamily, Source={x:Reference thisEdiableLabel}}" Text = "{Binding Text, Source={x:Reference thisEdiableLabel}, Mode=TwoWay}" TextColor = "{Binding TextColor, Source={x:Reference thisEdiableLabel}}" FontSize = "{Binding FontSize, Source={x:Reference thisEdiableLabel}}" > < Label . GestureRecognizers > < TapGestureRecognizer Tapped = "TapGestureRecognizer_Tapped" / > < / Label . GestureRecognizers > < / Label >

When tapped, the IsFocusedMode property will be set to true and this will activate the ContentView’s trigger to switch from the label to the entry.

To detect when the user has finished editing and leaves the entry, we will use the Focus Visual State of the Entry. When this visual state is set to false, we launch a Trigger on the ContentView.

<DataTrigger TargetType="local:EditableLabel" Binding="{Binding IsFocused, Source={x:Reference MainEntry}}" Value="False"> <Setter Property="IsFocusedMode" Value="False"/> </DataTrigger> 1 2 3 < DataTrigger TargetType = "local:EditableLabel" Binding = "{Binding IsFocused, Source={x:Reference MainEntry}}" Value = "False" > < Setter Property = "IsFocusedMode" Value = "False" / > < / DataTrigger >

Here is the XAML code for this content view.

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="EditableLabel.EditableLabel" xmlns:local="clr-namespace:EditableLabel" x:Name="thisEdiableLabel"> <ContentView.Triggers> <DataTrigger Binding="{Binding IsFocusedMode, Source={x:Reference thisEdiableLabel}}" Value="False" TargetType="ContentView"> <Setter Property="Content"> <Setter.Value> <Label x:Name="MainLabel" FontAttributes="{Binding FontAttributes, Source={x:Reference thisEdiableLabel}}" FontFamily="{Binding FontFamily, Source={x:Reference thisEdiableLabel}}" Text="{Binding Text, Source={x:Reference thisEdiableLabel}, Mode=TwoWay}" TextColor="{Binding TextColor, Source={x:Reference thisEdiableLabel}}" FontSize="{Binding FontSize, Source={x:Reference thisEdiableLabel}}"> <Label.GestureRecognizers> <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/> </Label.GestureRecognizers> </Label> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding IsFocusedMode, Source={x:Reference thisEdiableLabel}}" Value="True" TargetType="local:EditableLabel"> <Setter Property="Content"> <Setter.Value> <Entry Placeholder="{Binding PlaceHolder, Source={x:Reference thisEdiableLabel}}" FontAttributes="{Binding FontAttributes, Source={x:Reference thisEdiableLabel}}" x:Name="MainEntry" TextColor="{Binding TextColor, Source={x:Reference thisEdiableLabel}}" Text="{Binding Text, Source={x:Reference thisEdiableLabel}, Mode=TwoWay}" FontSize="{Binding FontSize, Source={x:Reference thisEdiableLabel}}"/> </Setter.Value> </Setter> <Setter Property="ContentChanged" Value="True" /> </DataTrigger> <DataTrigger TargetType="local:EditableLabel" Binding="{Binding IsFocused, Source={x:Reference MainEntry}}" Value="False"> <Setter Property="IsFocusedMode" Value="False"/> </DataTrigger> </ContentView.Triggers> </ContentView> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 < ContentView xmlns = "http://xamarin.com/schemas/2014/forms" xmlns : x = "http://schemas.microsoft.com/winfx/2009/xaml" x : Class = "EditableLabel.EditableLabel" xmlns : local = "clr-namespace:EditableLabel" x : Name = "thisEdiableLabel" > < ContentView . Triggers > < DataTrigger Binding = "{Binding IsFocusedMode, Source={x:Reference thisEdiableLabel}}" Value = "False" TargetType = "ContentView" > < Setter Property = "Content" > < Setter . Value > < Label x : Name = "MainLabel" FontAttributes = "{Binding FontAttributes, Source={x:Reference thisEdiableLabel}}" FontFamily = "{Binding FontFamily, Source={x:Reference thisEdiableLabel}}" Text = "{Binding Text, Source={x:Reference thisEdiableLabel}, Mode=TwoWay}" TextColor = "{Binding TextColor, Source={x:Reference thisEdiableLabel}}" FontSize = "{Binding FontSize, Source={x:Reference thisEdiableLabel}}" > < Label . GestureRecognizers > < TapGestureRecognizer Tapped = "TapGestureRecognizer_Tapped" / > < / Label . GestureRecognizers > < / Label > < / Setter . Value > < / Setter > < / DataTrigger > < DataTrigger Binding = "{Binding IsFocusedMode, Source={x:Reference thisEdiableLabel}}" Value = "True" TargetType = "local:EditableLabel" > < Setter Property = "Content" > < Setter . Value > < Entry Placeholder = "{Binding PlaceHolder, Source={x:Reference thisEdiableLabel}}" FontAttributes = "{Binding FontAttributes, Source={x:Reference thisEdiableLabel}}" x : Name = "MainEntry" TextColor = "{Binding TextColor, Source={x:Reference thisEdiableLabel}}" Text = "{Binding Text, Source={x:Reference thisEdiableLabel}, Mode=TwoWay}" FontSize = "{Binding FontSize, Source={x:Reference thisEdiableLabel}}" / > < / Setter . Value > < / Setter > < Setter Property = "ContentChanged" Value = "True" / > < / DataTrigger > < DataTrigger TargetType = "local:EditableLabel" Binding = "{Binding IsFocused, Source={x:Reference MainEntry}}" Value = "False" > < Setter Property = "IsFocusedMode" Value = "False" / > < / DataTrigger > < / ContentView . Triggers > < / ContentView >

Let’s add finishing touches. At this stage, the Entry when focused, does not always display the keyboard. The cursor is at the beginning of the text too. These can be corrected by setting a few properties when the FocusMode bindable property changes. In our case, the name of the method in charge of this is called : “OnIsFocusedModePropertyChanged”. This is done as shown below.

(bindable as EditableLabel).MainEntry.Focus(); (bindable as EditableLabel).MainEntry.CursorPosition = (bindable as EditableLabel).MainEntry.Text?.Length ?? 0; 1 2 ( bindable as EditableLabel ) . MainEntry . Focus ( ) ; ( bindable as EditableLabel ) . MainEntry . CursorPosition = ( bindable as EditableLabel ) . MainEntry . Text ? . Length ? ? 0 ;

Demo

Edit Label Custom Control In Xamarin.Forms demo

Conclusion

Building custom controls entirely with XAML and C# in the shared project only is easy and fast. Though it might not always be the best when it comes to performance. Here is a similar blog post about building a

SnackBar in Xamarin Forms with XAML. With this, we built our Entire edit label custom control in Xamarin Forms XAML. This required a bit of code behind to mage states and properties. As I said earlier, this could be achieved using custom renderers, but this approach allow’s saves us per platform modification of the control, though it might not be the best when it comes to performance.

References

https://docs.microsoft.com/fr-fr/xamarin/xamarin-forms/app-fundamentals/gestures/tap

https://docs.microsoft.com/fr-fr/xamarin/xamarin-forms/app-fundamentals/triggers

https://docs.microsoft.com/fr-fr/dotnet/api/xamarin.forms.visualelement.isfocused?view=xamarin-forms﻿

Like this: Like Loading...

Like this: Like Loading...

If this post was useful to you, please share it and follow me onor like mypage.Follow me on social media and stay updatedFollow me on social media and stay updated