Ambient Properties in Xamarin.Forms

Ambient Properties in Xamarin.Forms

One of the aspects of XAML that is often misunderstood is that of ambient properties. Probably the best example of this is being able to set the foreground colour on a Page in UWP and for the foreground color to be set on every element on the page. Unfortunately this doesn’t seem to be something that’s available in Xamarin.Forms, which lead me to wonder how hard it would be to implement.

The implementation would be slightly different from UWP which uses the AmbientAttribute. Instead I’ll create an attached property which can be set on any element. The ForeColor will be then set on each child element, unless the TextColor is explcitly set on an element.

For example the following XAML

<StackLayout
    vsm:Ambient.ForeColor=”Blue”>
     <Label Text=”Hello World – Blue!” />
     <Label TextColor=”Red”
             Text=”Hello World – Red!” />
</StackLayout>

would generate the following output

image

Over the next couple of days the Ambient.ForeColor property will be added to BuildIt.Forms, which also includes the VisualStateManager I described in my past two posts (here and here).

Rebuilding the Xamarin.Forms Button with Visual States and Control Templates

Rebuilding the Xamarin.Forms Button with Visual States and Control Templates

In my previous post I provided a demonstrable way that visual states could be used in a Xamarin.Forms application to adjust layout. Whilst I showed how this can be used on a page to show/hide a piece of text, it can also be used to define the different states of a button. Before I get onto using visual states within a button, I’ll first show how a ContentView can be adapted to provide the basic button behaviour, whilst allowing both Content and ControlTemplate to be defined. Ok, perhaps that doesn’t make sense but let’s walk through an example:

<controls:ContentButton Pressed=”ToggleButtonPressed”>
    <StackLayout>
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
    </StackLayout>
</controls:ContentButton>

In this code, I can add any XAML elements as Content within the ContentButton tags. The ContentButton raises a Pressed event, instead of a Click or Clicked event, to which an event handler can be attached. In the next code snippet, I’ve overridden the default ControlTemplate, wrapping the ContentPresenter in a Grid which has a yellow background.

<controls:ContentButton VerticalOptions=”Center”
                        x_Name=”DisabledButton”
                        HorizontalOptions=”Center”>
    <ContentView.ControlTemplate>
        <ControlTemplate>
            <Grid BackgroundColor=”Yellow”>
                <ContentPresenter x_Name=”ContentPresenter”
                                    Content=”{TemplateBinding Content}” />
            </Grid>
        </ControlTemplate>
    </ContentView.ControlTemplate>
    <StackLayout>
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
        <Label Text=”Hello!” />
    </StackLayout>
</controls:ContentButton>

Overriding the ControlTemplate demonstrates an easy way to override the style of the button in a way that can be replicated across all instances of the button in an application.

Let’s take a look at the inner workings of the ContentButton, in particular the default ContentTemplate which is used to define different visual states of the button. In this case there are four visual states: Normal, PointerOver, Pressed and Disabled.

<ContentView.ControlTemplate>
    <ControlTemplate>
        <Grid x_Name=”RootGrid” BackgroundColor=”{TemplateBinding BackgroundColor}”>
            <local:VisualStateManager.VisualStateGroups>
                <x:Array Type=”{x:Type local:VisualStateGroup}”>
                    <local:VisualStateGroup Name=”CommonStates”>
                        <local:VisualState Name=”Normal” />
                        <local:VisualState Name=”PointerOver”>
                            <local:VisualState.Setters>
                                <local:Setter Value=”#33000000″ Target=”Background.BackgroundColor” />
                            </local:VisualState.Setters>
                        </local:VisualState>
                        <local:VisualState Name=”Pressed”>
                            <local:VisualState.Setters>
                                <local:Setter Value=”#66000000″ Target=”RootGrid.BackgroundColor” />
                            </local:VisualState.Setters>
                        </local:VisualState>
                        <local:VisualState Name=”Disabled”>
                            <local:VisualState.Setters>
                                <local:Setter Value=”#33000000″ Target=”Background.BackgroundColor” />
                            </local:VisualState.Setters>
                        </local:VisualState>
                    </local:VisualStateGroup>
                </x:Array>
            </local:VisualStateManager.VisualStateGroups>
           
<BoxView BackgroundColor=”Transparent” x_Name=”Background” />
            <ContentPresenter x_Name=”ContentPresenter” Content=”{TemplateBinding Content}” />
        </Grid>
    </ControlTemplate>
</ContentView.ControlTemplate>

In this code you can see how the visual states (which I introduced in my previous post) are used to adjust the background colour of the BoxView that sits behind the Content of the button.

The sample project that demonstrates the ContentButton can be downloaded here

Styling Pages and Controls in Xamarin Forms using Visual States

Styling Pages and Controls in Xamarin Forms using Visual States

I’ve been a bit proponent of both Xamarin and Xamarin.Forms for a long time but recently I’ve been taking another look at some of the fundamentals. Xamarin.Forms, for all its great intent is still a poor-man’s answer to declaring layout of an application in Xaml. Unlike Xaml platforms that have come before it (WPF, Silverlight, UWP), Forms doesn’t support some of even the basic features that you’d expect. On the chopping board today is the Button control – as one of the fundamental controls for any application, the Button should be able to be completely customised. Unfortunately it’s far from easy to alter the look of the basic button.

If you look at how a simple button renders on different platforms, there is a clear difference between the style of the button. The following image shows how the button control renders across UWP, iOS and Android (UWP has an extra visual state as it supports mouse/pointer over on desktop).

image

Button States Across Three Platforms

The difference in style is by design – the rendering of the button on each platform uses the built in style for each platform. This works well if you’re interesting in building a generic looking application (eg perhaps a simple LOB data capture application). However, if you want to style the button in line with your branding and the design of your application, you’re going to want to make the buttons look and behave the same across all devices. You’d think this would be as simple as defining a common style, or perhaps overriding the default layout of the button. This is in fact doable – for example on UWP you can use an implicit style to override the look of every button across the application.

Having to override the style of the button on each platform defeats the purpose of using Forms in the first place – once you’ve overridden the style, you then need to make platform specific changes every time you want to alter the style of the button control; imagine doing this for every control in your application – pretty soon, you might as well have developed the application using the traditional Xamarin model, rather than Forms. So, let’s look at the limitations of the Button control and see what we can do to address some of its shortcomings in a way that will help us build better applications quicker.

There are two issues that I have with the Button control. The first is that it’s not easy to customise the content within the Button itself. For example if you wanted to have two lines of text, with the first being centred in bold, and the second justified italics with word wrapping enabled to allow it to flow to multiple lines. In UWP this would be easy with the Button control as the Content could be customised to have multiple TextBlock elements, with the style set accordingly.

<Button>
    <StackPanel>
        <TextBlock Text=”Hello World!”
                    TextAlignment=”Center”
                    FontWeight=”Bold” />
        <TextBlock Text=”This is a short message that should word wrap with all the lines being set to justified”
                    FontStyle=”Italic”
                    TextWrapping=”WrapWholeWords”
                    TextAlignment=”Justify” />
    </StackPanel>
</Button>

This would look similar to the following:

image

UWP Button with Custom Content

Attempting to do this with the Forms Button control is not trivial. The second issue is how the different visual states are handled. Again in UWP the different Button visual states are defined in XAML (generic.xaml) where appropriate properties are set based on the active states (eg Normal, Pressed, PointerOver). Forms doesn’t support Visual States, so attempting to define Button states declaratively is going to take more work.

My solution to these issues comes in two steps: firstly, provide a declarative way to define Visual States in XAML, similar to what’s available in UWP; and secondly to provide an alternative to the Button which can not only take custom content but also has a template that can be override to customise behaviour for different button states. If you’ve ever drilled into a control template for a UWP control, chances are that it has some visual states defined. Rather than having some predefined behaviour that’s not accessible or customisable, the various states of UWP controls are defined in XAML in the template for the control. In addition to defining the different states within a control, visual states can be used to define different states of a page too.

In this post we’ll focus on the first step, which is how to define in XAML and then apply visual states. Visual states are defined in visual state groups, and only a single state within a given states group can be active at any time (ie they’re mutually exclusive). However, it is possible that two states, from different groups can be active at any point in time.

So far we know we need visual states, defined within visual state groups. Within each visual state we need to be able to define which properties are going to change when the visual state is made active. UWP allows the property changes to be defined either as a storyboard, potentially with animation, or as a series of setters where the property is updated to the new value immediately. For the purposes of getting the basics working, we’re just going to work with property setters.

Let’s work with a very simple scenario where we have a simple Label which we need to be able to show and hide based on the state of the page:

<Label FontSize=”30″
        x_Name=”HelloLabel”
        Text=”Hello World!” />

In our very contrived example we have a button that will be used to toggle whether the Label is visible.

private bool visible = true;
public void ToggleButtonPressed(object sender, EventArgs e)
{
    visible = !visible;
    VisualStateManager.GoToState(this, visible ? “Show”:”Hide”);
}

This code, by design, is similar to what you might see within a UWP application that uses visual states to control the layout – in this case showing and hiding an element. Currently visual states don’t exist in Xamarin Forms but here’s a first pass on an implementation of visual states:

<vsm:VisualStateManager.VisualStateGroups>
    <x:Array Type=”{x:Type vsm:VisualStateGroup}”>
        <vsm:VisualStateGroup Name=”LabelStates”>
            <vsm:VisualState Name=”Show” />
            <vsm:VisualState Name=”Hide”>
                <vsm:VisualState.Setters>
                    <vsm:Setter Value=”false”
                                Target=”HelloLabel.IsVisible” />
                </vsm:VisualState.Setters>
            </vsm:VisualState>
        </vsm:VisualStateGroup>
    </x:Array>
</vsm:VisualStateManager.VisualStateGroups>

For those familiar with the syntax in UWP this should look familiar – there’s a few kinks to work out (for example the use of the Array tag) but in its initial form it works.

Sample project can be downloaded here

Xamarin Live Player from Build 2017

Xamarin Live Player from Build 2017

Microsoft’s Build conference is over for another year and I’m still working
my way through the various sessions. I did however get a chance to take a look
at the Xamarin Live Player (https://developer.xamarin.com/guides/cross-platform/live/player/)
which is an interesting announcement and one that can help reduce the friction
of getting pre-release applications onto devices. The Live Player is in preview,
which means you’ll need the preview version of Visual Studio, the updated
Xamarin bits and the alpha channel Xamarin bits on your Mac build machine (for
those of you doing development on Windows). I highly recommend following all the
setup instructions – https://developer.xamarin.com/guides/cross-platform/live/install/.

Getting the Live Player setup and running was relatively straight forward,
after I fixed up my Mac build machine because it was
missing certificates/provision profile etc. I was able to install the Live
Player on both my iPhone and a test Android device. After creating a simple
Xamarin Forms project in Visual Studio, the Live Player is available from the
device dropdown.

After clicking run with the Live Player selected, the following dialog is
displayed. Launch the Live Player app on your test device. You can either scan
the QR code, or you can enter the code presented within the app into the
dial.

After scanning the QR code, a connection is established between the Live
Player app running on your device and the instance of Visual Studio. A new entry
should appear in the devices dropdown with your device name followed by the word
Player.

Now that you’ve associated your device, each time you want to run the
application on your device, you can simply select the appropriate player from
the devices dropdown and hit run. The app takes a second or two to deploy and
will appear on your device – this provides a very quick way for you to deploy
and test applications, particularly on an iOS device when doing development on a
Windows machine.

I can definitely see the advantage of using the Live Player but it had a few
limitations (https://developer.xamarin.com/guides/cross-platform/live/limitations/)
so I’m not sure how effective it will be until they resolve some of these.