206 – Reusable controls

Most reusable controls fall into one of two categories: Custom or composite. A custom control is one where you are doing all the low-level work like rendering. Maybe you need a round gauge with a dial like a speedometer. A composite control is control made up of (composed of, get it?) several other controls. Maybe you use a particular arrangement of a border, label and entry in 10 different places on a page as the form someone fills out. Instead of duplicating the markup 10 times you make a composite control then just place 10 of those on the page. Or maybe you’re tired of the limitations of the built-in header on a navigation page. You could make your own header control then place it on the top of all your pages. In WPF these are UserControl. In Xamarin they are ContentView. Getting used to the naming yet? ContentPage is a page of content, generally views. A grouping of views is the ContentView, which you can then put in other ContentViews or a ContentPage.

Composite controls (ContentViews) are really common, or at least should be, and straightforward to make because you’re not having to do any low-level work. Since they are made from existing controls you know they will render on all the supported platforms. Let’s start with an easy one that everyone needs sooner or later: An input control. You see this everywhere, there is a question or hint, and an entry to type in your value. Maybe it’s for your user name, and another for password. Or for registering on a site for your alias, first name, last name, email address, {…}

If you’re at all like me, you’d rather make something one time and use it many times, than to make it many time – then have maintain every instance individually. So much easier to have it defined in one place, even if it does mean an extra 10 minutes on the front end of the project. There’s that theme again: A little work on the front end saves you tons of work in your day-to-day.

Once done with our new InputControl, you’ll be able to add it to any page and bind to its properties just as easily as any other OEM control

We want this to be a versatile control that you can reuse for all sorts of things. Of course, you can go back and add more and more to it over time to suit your needs; but for now what are the basic properties we probably know we’ll need:

  • Caption – That’s the text that tells us what this is for such as “User Name”, “Password” or “Birthday”
  • Value – That the text the user enters. For the sake of consistency with every other control out there we are not giving it a name like ‘user reply’. Every control has a ‘Value’ and that’s what we all look for and expect when we code.
  • Colors for the caption and the value – both foreground and background


Conceptually that’s all there is to it: A constructor and the properties.

BindableProperty

If you come from WPF this is the Xamarin version of a DependencyProperty. A BindableProperty is basically a normal CLR property with a little bit of plumbing that lets you use it for binding in your XAML views.

A CLR property has a public property with a get and set method, backed by a field, usually set to private.

A BindableProperty also has a public method with get and set, and a backer – only the backer is of type BindableProperty and is created with a method that takes a few parameters such as type, parent type and default value, used to do that plumbing we mentioned.

Your turn

Believe it or not you’ve read everything you need to make all the code-behind for this control. You know the name of the control, the properties we want and have an example. So let’s do it.

Right-click on the Controls folder you made. Choose Add|New Item…

Then select a new Forms Xaml View and name it InputCntrl

Don’t worry about the XAML just yet. We need to make the BindableProperties we intend to bind our UI elements to. We already named them:

And you know the syntax:

I’ll give you the first one to copy/paste. You can type out the rest. (They go in InputCntrl.xaml.cs if you didn’t realize that)

       #region Caption (Bindable string)
        public static readonly BindableProperty CaptionProperty = BindableProperty.Create(
                                                                  "Caption", //Public name to use
                                                                  typeof(string), //this type
                                                                  typeof(InputCntrl), //parent type (tihs control)
                                                                  string.Empty); //default value
        public string Caption
        {
            get { return (string)GetValue(CaptionProperty); }
            set { SetValue(CaptionProperty, value); }
        }
        #endregion Caption (Bindable string)

XAML

Now that you have the properties you can use them in your XAML. Open InputCntrl.xaml

BindingContext is everything when it comes to getting things to bind and work right in any MVVM app – WPF or Xamarin. Controls inherit context from the parent control, unless a different context is explicitly assigned. That’s what we need to do here. We need to tell each UI element (label, entry, button etc.) to explicitly look at this control for its context in order to find those BindingProperties we just made. This is one of the rare occasions when we actually give a XAML element a name: When it is going to be referenced by another XAML element within the XAML itself. To the ContentView, add a tag naming the control ‘this’. That’s right. We’re going to keep to the Microsoft naming and have this item refer to itself as ‘this’. It makes all of us comfortable and the code and markup easy to read and follow.

We can now use ‘this’ as a reference source telling the rest of our XAML where to look for properties to bind to.

I’m sure if you study it a bit you’ll see what’s happening, but for the sake of thoroughness let’s break it down.

  • Style – We defined those earlier so we can keep consistent theme throughout our app.
  • HorizontalOptions & HorizontalTextAlignment – Just to be safe we are overriding these from the style. Remember HorizontalOptions is on the label itself; HorizontalTextAlignment is the position of the text within the label (assuming the label is bigger than it needs to be).
  • Text – Ah… the good stuff. We are binding, referencing ‘this’ as our source. Well, ‘this’ is this control that we just named. On that source of ‘this’ we want to take a path to ‘Caption’ – that’s the BindingProperty we made just a bit ago.
  • TextColor – This looks familiar. We just do the same thing, getting the CaptionForeground property we made from ‘this’ control.
  • BackgroundColor – just like the last two.

Let’s do the same with an Entry. Nothing unfamiliar now:

If we stick those two controls in a Grid of two rows we’re pretty much done with our reusable InputCntrl. I do want to point out that nowhere have we tried to micromanage the size of anything. We aren’t forcing the size of the label… We aren’t hardcoding any numbers anywhere. Our control can size itself as needed. Its seems common sense but lots of people trip over this. For some reason (maybe habit) they just have to try to set the size of everything. That just doesn’t work when you don’t know the size of the phone/tablet/laptop/desktop/watch your app is going to be running on.

Let’s put it to use

If we go back to our MainPage.xaml that we are using for testing we can replace the individual label and entry use for the selected pet’s name with a single control that accepts bindings.
• Comment out the label from the first row, first column.
• Then do the same for the entry in the first row, second column.
• Now add an InputControl in that same space, first row, first column, for a column span of 2
• Bind the value of the InputCntl back to the pet’s name property just the same as we had previously done on the individual Entry.

• Save everything
• Hit [F5] and see it on your device.

Here is a screen capture from an Android tablet. Tap on one of the ListView items. Its details appear on the right for editing… Including in our new reusable control.