Home / News

Blog - News

Using Bindable Properties In Xamarin.Forms

Using Bindable Properties In Xamarin.Forms

Author: Les Brown

I would argue the nicest feature of Xamarin is the ability to create custom controls natively or simply extend existing ones. If you have tried other mobile frameworks, you will notice quickly that you are limited to what they provide and making only composite controls. They real power isn't just that you can create visually stunning UIs but that through bindable properties your component can interact at runtime with the backend code making it as powerful as those provided out of the box.

Before we get into a practical example, let's explain the basic concepts of a bindable property. They provide the following abilities:

  • Can set a default value
  • Can monitor changes in a value
  • Can validate a value
  • Can set a value via a style
  • Enable data binding

The process of creating a bindable property starts with the Create method of the BindableProperty class.

public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(ImageTextButton), default(string), propertyChanged: OnTextChanged);

As you can see, we have defined a TextProperty. The parameters are defined as such:

  • nameof(Text) is the class property it is associated to
  • typeof(string) is the data type of the property
  • typeof(ImageTextButton) is type the property is a member of
  • default(string) is the default value it should be set to initially
  • propertyChanged is the method that should be called when data binding occurs

The remaining hookup code referenced in the above create parameters is:

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

private static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
{
  var control = (ImageTextButton)bindable;

  var value = (string)newValue;

  //You can do anything you want here
}

So, let's give you a simple scenario where using bindable properties would be useful. Let's make a composite control that is a button with Text and an Image. This isn't that hard because we already have controls for labels, images and containers. We just need to position the items correctly and hookup a tap event. The following is the code and what it looks like.

public class PageOne : ContentPage
{
    public PageOne()
    {
        this.Title = "PageOne";

        var tapGesture = new TapGestureRecognizer()
        {
            Command = new Command(async () =>
            {
                await Navigation.PushAsync(new PageTwo());
            })
        };

        var compositeControl = new StackLayout()
        {
            BackgroundColor = Color.LightGray,
            HeightRequest = 45,
            Margin = new Thickness(150, 100, 150, 100),
            Children =
            {
                new StackLayout()
                {
                    Margin = 8,
                    HorizontalOptions = LayoutOptions.Center,
                    Orientation = StackOrientation.Horizontal,
                    Children =
                    {
                        new Image()
                        {
                            Margin=new Thickness(10,5,0,5),
                            Source = ImageSource.FromFile("music.png"),
                            HeightRequest = 22,
                        },

                        new Label()
                        {
                            Margin=new Thickness(0,5,10,5),
                            Text = "Click Here",
                            TextColor = Color.Black,
                            VerticalTextAlignment = TextAlignment.Center,
                        }
                    }
                }
            }
        };

        compositeControl.GestureRecognizers.Add(tapGesture);

        Content = new StackLayout()
        {
            Children =
            {
                compositeControl
            }
        };
    }
}

A screenshot of a cell phone demonstrating a custom control in Xamarin.Forms

This works fine but not really reusable and all the properties are hard-coded. It would be nice to move this into a separate content view with bindable properties. This wouldn't be that difficult and all you would need to do is make properties for the image, label and click command. Simply copy and paste the property creation code above over and over again and remember to change the parameters to the appropriate values. However, there is an easier way!

MFractor has a bindable property wizard that makes creating these properties ridiculously simple and you don't have to remember all the steps and parameters to get everything hooked up. All you have to do is press Alt+Return (Windows) / Option+Return (Mac) to pull-up an action menu. Select Create a bindable property and the following window is presented.

Using MFractors bindable property wizard to create a new Xamarin.Forms bindable property

Enter the necessary fields and click create. Let's look a refactored version of the example and see this in action. For brevities sake, only one property is being displayed. The entire code base is provided on GitHub.

public class ImageTextButton : ContentView
{
    private Image _image;

    private StackLayout _stackLayout;

    public static readonly BindableProperty ImageProperty = BindableProperty.Create(nameof(Image), typeof(ImageSource), typeof(ImageTextButton), default(ImageSource), propertyChanged: OnImageChanged);

    public ImageSource Image
    {
        get { return (ImageSource)GetValue(ImageProperty); }
        set { SetValue(ImageProperty, value); }
    }

    private static void OnImageChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (ImageTextButton)bindable;

        var value = (ImageSource)newValue;

        control.ApplyImage(value);
    }

    private void ApplyImage(ImageSource value)
    {
        _image.Source = value;
    }

    public ImageTextButton()
    {
        _image = new Image()
        {
            Margin = new Thickness(10, 5, 0, 5),
            Source = this.Image,
            HeightRequest = 22,
        };

        _stackLayout = new StackLayout()
        {
            BackgroundColor = this.BackgroundColor,
            HeightRequest = this.HeightRequest,
            Margin = this.Margin,
            Children =
            {
                new StackLayout()
                {
                    Margin = 8,
                    HorizontalOptions = LayoutOptions.Center,
                    Orientation = StackOrientation.Horizontal,
                    Children =
                    {
                        _image,
                    }
                }
            }
        };
        Content = _stackLayout;
    }
}

// The updated version of the PageOne class now simply declares the new ImageTextButton control and binds the properties.

public class PageOne : ContentPage
{

    private ImageTextButton _imageTextButton;

    public PageOne()
    {
        this.Title = "PageOne";

        this.BindingContext = new AppViewModel();

        _imageTextButton = new ImageTextButton()
        {
            BackgroundColor = Color.LightGray,
            HeightRequest = 45,
            Margin = 150
        };

        _imageTextButton.SetBinding(ImageTextButton.TextProperty,
        nameof(AppViewModel.ButtonTitle));

        _imageTextButton.SetBinding(ImageTextButton.ImageProperty,
        nameof(AppViewModel.ImgSource));

        _imageTextButton.SetBinding(ImageTextButton.ClickCommandProperty,
        nameof(AppViewModel.NavCommand));

        Content = new StackLayout()
        {
            Children =
            {
                _imageTextButton
            }
        };
    }
}

We now have a reusable control that can data bind it properties and be updated at runtime all because of the features of Xamarin's Bindable Properties. Using MFractor, this process only took a minute or two. If you would like to see the before and after code implementation of the example described go to my bindable properties GitHub project.

About The Author

Les Brown profile picture

Les is the mobile practice lead at Valore Partners as well as a certified Xamarin Mobile Developer and Microsoft MVP. He has been instrumental in developing and writing the mobile curriculum for the University of Phoenix as an adjunct faculty member and sponsors a monthly Meetup for mobile developers open to the community. Holding a Masters in Education, Les has been instrumental in hosting community events and creating training material in developing cross-platform mobile applications. Furthermore, he is an accomplished Angular and Docker developer working on numerous client applications in building responsive web sites.

LinkedIn:

https://www.linkedin.com/in/les-brown-93885424/

GitHub:

http://www.github.com/azdevelopnet

Accessibility in Xamarin.Forms

Accessibility in Xamarin.Forms

Author: Les Brown

In the last American census, it was estimated that 18.7% of the population has some type of disability and of those, according to the Pew Internet Project, 54% utilize internet connected services and devices. In other words, the consumers of our web and mobile applications who have disabilities, in some cases, outnumber the total users in countries like South Korea, Mexico and Spain (Accessibility, Interactive).

In Xamarin.Forms (XF) we can create compelling and interactive mobile applications as well as accommodate the needs of our users that have certain disabilities. Before delving into the accessibility features of XF and the code needed to activate a feature, lets address design guidelines that are equally if not more important.

  1. Layout elements on the screen with navigation in mind: Make sure navigating between controls using alternative inputs methods matches the logical flow using a touch screen.

  2. Support appropriate fonts and color contrasts: Avoid hard-coded dimensions so that layouts can resize to accommodate larger fonts. Also pick colors that are still readable in high-contrast mode.

  3. Provided multiple user cues: Provide visual indicators and not just sound or color changes for completion events. When colors are used, pick a palette that is easy to distinguish changes for those with color blindness.

  4. Provided captioning for various types of media: All video and audio media should have captioning and readable scripts.

The second part of design process includes utilizing features of the OS.

  1. Select visual elements to be seen by accessibility features of the OS. Also exclude those elements not needed for a particular workflow.

    • XAML

<Entry AutomationProperties.IsInAccessibleTree="true" />

  • Code

var entry = new Entry();

AutomationProperties.SetIsInAccessibleTree(entry, true);

  1. User Interface is self-describing: Make sure all elements have descriptive text and hints compatible with screen reading APIs. All Images should have alternate text.

    • XAML

      • Name

<ActivityIndicator AutomationProperties.IsInAccessibleTree="true" AutomationProperties.Name="Progress indicator" />

  • Help Text

<Button Text="Toggle ActivityIndicator"

AutomationProperties.IsInAccessibleTree="true"

AutomationProperties.HelpText="Tap to toggle the activity indicator" />

  • Code

    • Name

var activityIndicator = new ActivityIndicator();

AutomationProperties.SetIsInAccessibleTree(activityIndicator, true);

AutomationProperties.SetName(activityIndicator, "Progress indicator");

  • Help Text

var button = new Button { Text = "Toggle ActivityIndicator" };

AutomationProperties.SetIsInAccessibleTree(button, true);

AutomationProperties.SetHelpText(button, "Tap to toggle the activity indicator");

  1. Accessibility for Navigation:

    • On Navigation pages, for Android, set the AutomationProperties.Name & AutomationProperties.HelpText in order to enable the back button to be screen readable. (Does not work for iOS)

    • On MasterDetail pages, for iOS, follow the above example to enable screen reading of the toggle button. For Android, set the page's IconImageSource's AutomationId to a descriptive text.

    • On ToolbarItems, for both platforms, use the AutomationProperties.Name & AutomationProperties.HelpText to set screen readable text.

  2. Layout Order: The tab order of visual elements is in the order in which they are placed on the screen. However, this may not be the order most logical for accessibility. Also, some controls should be skipped in tabbing. In the following example, entry fields are placed in in columns and rows resulting in the following:

However, the order should be vertical and then horizontal. Setting a controls tab index can change this to the following:

We can also skip / exclude controls from tabbing by setting the property IsTabStop to false.

Now that you have enabled and set the name, help text and tab order for various controls, it is time to test these features.

iOS Testing Procedure:

Apple has a lot of helpful tools to assist developers with integrating accessibility into the applications they build. Before we get started with VoiceOver, it's important to become familiar with the Accessibility Inspector. The Accessibility Inspector is a tool that shows all of the properties and values, methods (actions that can occur from elements on the screen), and position of the object that's currently being selected on the screen.

To start the Accessibility Inspector follow the simple steps below:

  1. Bring up Xcode.

  2. Navigate to the Open Developer Tool and start the Accessibility Inspector.

  3. Bring up the simulator running with the application you would like to inspect.

The Accessibility Inspector can connect to a lot of different processes. While navigating with the inspector you can click by clicking on things twice. If you want to activate a tab with the Accessibility Inspector click on it once. The following tutorial will guide you through the testing steps and features of this tool.

As mentioned above, the inspector tool uses VoiceOver to give auditory prompts to the user. The following Apple documentation explains this feature and how to activate it on a real device in order to perform manual testing.

Android Testing Procedure

Google's accessibility team has created a tool called Accessibility Scanner. This app is free to download and is the easiest way to quickly find issues with your application's accessibility.

Once the scanner is running, open up the application you'd like to test, and tap the floating blue circle. This will scan the current screen and display an orange box around potential accessibility issues. Tapping on the orange box displays a summary about that specific issue, and even a link to detailed documentation about how to fix it.

The following links provide documentation and tutorials on Android's accessibility scanner.

In addition to the scanner tool, it is important to manually test your application using the built-in features of the Android device. The following tutorial and documentation will help you perform manual testing.

The code snippets provided in this article are informative, but a real example is far more helpful. Here is example of accessibility enabled using Xamarin.Forms.

https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-accessibility/

Citations

Accessibility, Interactive. "Accessibility Statistics." Accessibility Statistics | Interactive Accessibility, www.interactiveaccessibility.com/accessibility-statistics.

About The Author

Les Brown profile picture

Les is the mobile practice lead at Valore Partners as well as a certified Xamarin Mobile Developer and Microsoft MVP. He has been instrumental in developing and writing the mobile curriculum for the University of Phoenix as an adjunct faculty member and sponsors a monthly Meetup for mobile developers open to the community. Holding a Masters in Education, Les has been instrumental in hosting community events and creating training material in developing cross-platform mobile applications. Furthermore, he is an accomplished Angular and Docker developer working on numerous client applications in building responsive web sites.

LinkedIn:

https://www.linkedin.com/in/les-brown-93885424/

GitHub:

http://www.github.com/azdevelopnet