7

Tips and Ticks when creating a Custom Control in Xamarin Forms. Part. 1

 2 years ago
source link: https://xamgirl.com/tips-and-ticks-when-creating-a-custom-control-in-xamarin-forms-part-1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Creating a custom control is a common thing to do when developing a Xamarin Forms application. In many cases, the main purpose of creating one is to have a reusable control that we can use across all our application.

In this article, I’m NOT going to show you how to create a custom control (if you want to learn about that you can read this great article by the MFractor blog). My goal is to give some tips and tricks that you can apply when creating one.

Tip 1: Use Control Templates as part of your Control

If you are creating a Custom Control that has XAML + CodeBehind, using a Control Template in the control XAML will give you access to the control bindable properties.

For example:

If you are creating an ExpandableParagraph Control with some bindable properties that the user can set when interacting with it:

Screen-Shot-2021-07-28-at-2.24.39-PM.png?resize=467%2C194&ssl=1

public partial class ExpandParagraphControl : ContentView { public bool IsExpanded { get => (bool)GetValue(IsExpandedProperty); set => SetValue(IsExpandedProperty, value); }

... }

If you want to use the bindable properties of the control in the XAML part, the first thing that comes to mind is to change the BindingContext to be the control itself.

<?xml version="1.0" encoding="UTF-8" ?> <ContentView ... x:Class="ExpandParagraphControl.Controls.ExpandParagraphControl" x:Name="MyView"> <StackLayout BindingContext="{Binding Source={x:Reference MyView}}"> <Label Text="{Binding IsExpanded}"/> .... </StackLayout> </ContentView>

A better way to do this is to wrap the view within Control Template, that way the BindingContext will be the control itself:

<?xml version="1.0" encoding="UTF-8" ?> <ContentView ... x:Class="ExpandParagraphControl.Controls.ExpandParagraphControl"> <ContentView.ControlTemplate> <ControlTemplate> <StackLayout> <Label IsVisible="{Binding IsExpanded}"/> .... </StackLayout> </ControlTemplate> </ContentView.ControlTemplate> </ContentView>

Check the source of the control here.

Tip 2: Use C# code for controls with a Simple UI

If you are creating a control with a simple UI that creates/updates UI elements dynamically or the UI content for the elements will be defined where it’s used. Personally, I prefer to do it all in C# code. Why? Because I think is:

  1. Easier to maintain
  2. Performance is better since it won’t have to render the XAML part.
  3. Full control of the UI Elements
  4. Part of the UI will be defined when using the control

For example: A Dynamic Segmented Tab Control

Screen-Shot-2019-11-26-at-3.56.09-PM.png?resize=440%2C262&ssl=1

If you analyze the UI above, each tab is quite simple, just a Label and a BoxView wrapped into a dynamic collection. For this scenario, I would do it all in C# code since it’s easier to replicate and it will give me the flexibility of specifying the UI content for the elements when using the control.

Check the source for the control here.

Tip 3: Use a Default Value Creator when is necessary

If you have a Bindable Property that needs to execute a function to set a default value, you can do it by using DefaultValueCreator.

For example:

private static object GetDefaultMoreCommand(BindableObject bindable) => new Command(() => ((ExpandParagraphControl)bindable).IsExpanded = !((ExpandParagraphControl)bindable).IsExpanded);

public static readonly BindableProperty MoreCommandProperty = BindableProperty.Create(nameof(MoreCommand), typeof(ICommand), typeof(ExpandParagraphControl), defaultBindingMode: BindingMode.OneWay, defaultValueCreator: GetDefaultMoreCommand);

public ICommand MoreCommand { get => (ICommand)GetValue(MoreCommandProperty); set => SetValue(MoreCommandProperty, value); }

Tip 4: Use a PropertyChanged method for the specific property

When handling property changes of a property, you could override the OnPropertyChanged method of the control and check for that property. The problem with this approach is that it will listen to the property changes for all the properties defined in the control.

protected override void OnPropertyChanged([CallerMemberName] string propertyName = null) { base.OnPropertyChanged(propertyName);

if (propertyName == TextProperty.PropertyName) {

} }

A better way is to define a Property Changed method for that specific property so that it only listens to the changes of that property.

public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(ExpandParagraphControl), propertyChanged: OnTextPropertyChanged);

public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }

private static void OnTextPropertyChanged(BindableObject bindable, object oldvalue, object newvalue) { var control = (ExpandParagraphControl)bindable; //Do your logic here }

Tip 5: DON’T FORGET TO UNSUBSCRIBE

Handling events is quite common when creating a new control, but when we subscribe to an event is important to unsubscribe. If we don’t do that it will cause memory leaks in our application.

For example:

public class ExtendedListView : ListView { public ExtendedListView(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy) { ItemAppearing += OnItemAppearing; }

private void OnItemAppearing(object sender, ItemVisibilityEventArgs e) { if (LoadMoreCommand != null) { if (e.Item == ItemsSource.Cast<object>().Last()) { LoadMoreCommand?.Execute(null); } } } }

As you can see every time this ListView is constructed, it will subscribe to the OnItemAppearing event.

A better version of this code would be:

public class ExtendedListView : ListView, IDisposable { public ExtendedListView(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy) { ItemAppearing += OnItemAppearing; }

private void OnItemAppearing(object sender, ItemVisibilityEventArgs e) { if (LoadMoreCommand != null) { if (e.Item == ItemsSource.Cast<object>().Last()) { LoadMoreCommand?.Execute(null); } } }

public void Dispose() { ItemAppearing -= OnItemAppearing; } }

That’s all for now, stay tuned for the second part of this article with more tips.

Happy coding!

Like this:

Loading...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK