Why is ColumnDefinition set to Auto and not Star by default? Xamarin Forms

.NET, Technical stuff, Work, Xamarin, XAML
See comments

UPDATE 24.09.2014: Xamarin just announced a new pre-release version of Xamarin Forms that fixes the behavior described here. Kudos to Xamarin for listening to the community. Publishing breaking changes is never easy, and it is a courageous step.

Official announcement:
Xamarin.Forms 1.3 will be changing the default behavior for a Grid. The default Column/RowDefinitions will be changed from Auto to Star. This is in line with about a million bug reports requesting this, user voice, and should better meet your expectations. If you are depending on the current behavior please add code to your project now to set the Row/Column definitions to Auto.
We will be putting out several pre-releases with this change so you have time to adapt.

Here is a small difference between “Windows XAML” and “Xamarin Forms XAML” that cost me an hour the other day. You know how anal passionate I am about user interfaces and pixel perfection. When I created a Xamarin Forms UI, here is what I wanted (on the left) as opposed to what I got (on the right, rendered in Windows Phone but the same happened in Android and iOS of course).

2014-09-16_10-05-37

This UI on the right is created by the following markup:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Button Text="refresh"
            Grid.Row="2"
            Command="{Binding RefreshCommand}"
            HorizontalOptions="Fill" />
</Grid>

I was of course surprised because if I use similar XAML in a Windows Phone app (instead of a Xamarin Forms app), I get the UI on the left, which is what every XAML developer expects.

So what’s wrong?

The issue here is the default value of unset ColumnDefinition objects. If we refer to the Xamarin Forms API documentation, we see the following text:

If ColumnDefinitions is empty, or if there are more columns than definitions, then columns for which there is no definition are rendered as if they were controlled by a ColumnDefinition object that has its ColumnDefinition.Width property set to GridLength.Auto.
[reference]

This is the key issue here: In Windows XAML, the default value for unset ColumnDefinition.Width is set to Star (“*”). This means that the column will take the whole available space, instead of sizing itself to the size of its children.

This is of course very confusing, since the columns are not visible on a Grid. Even if you set the BackgroundColor property of the Grid (in order to visualize the UI better), you will see that the Grid is taking the whole width of the phone. It’s only the single column who does not. The rest of the space, on the right of the button, is left void, it is limbo, there is nothing.

How to fix it?

The way to fix that is to declare a single ColumnDefinition and to set the width explicitly to Star. This is achieved by the markup here:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Button Text="refresh"
            Grid.Row="2"
            Command="{Binding RefreshCommand}"
            HorizontalOptions="Fill" />
</Grid>

This markup will force the only column to take the whole width.

Should Xamarin fix it?

I’d love to hear your opinion, should Xamarin fix this issue?

To me, it is a bug. Not just because it deviates from Windows XAML (this is a different platform, different XAML definition, I can live with that), but most of all because the current scenario just doesn’t make sense. If you think about HTML, if you have a table with a single cell, it is obvious that the cell will take the whole space. Here however, we have a single cell that doesn’t fill the grid. So what’s in the remaining space? It’s as if I have a house with a single room, but the room doesn’t take the whole space. What’s behind these walls? This is disturbing ;)

I wish Xamarin would fix this issue in a future release. Of course this is a breaking change, and no one likes them. But in my opinion the chance that someone actually wants a single column with a Width of Auto is very slim. In most cases, people will have been confused, like me, then maybe stumbled on the solution. If you already implemented the fix above, and Xamarin fixes the issue, nothing will happen to your UI, no change needed. If you really wanted an Auto column width… then yeah you have a problem.

In the mean time, just remember to set your ColumnDefinitions, people!

Happy coding
Laurent

Previous entry | Next blog entry

Responses to “Why is ColumnDefinition set to Auto and not Star by default? Xamarin Forms”

  1. Rui Marinho Says:

    Hi Laurent, i feel your pain, i found this issue to be very annoying since we are so used to have grid stretch the available space by default, now i have to always create at least 1 column and set to * to behave like i want.

    I hope our feedback could help get this changed/fixed.

  2. Michael Brown Says:

    Laurent,
    Maybe this is a design opinion being expressed by the framework. I know one of the first things I learned when taking a design class is not to be afraid of left or right alignment. Or whitespace.

    That is, centering your elements are typically frowned upon. So in essence, Xamarin is trying to lead you to (what some feel is) a better visual design.

  3. lbugnion Says:

    Hey Mike,

    I don’t think that left-aligned is something bad, but it is not a good way to implement it. The HorizontalOptions is set to “Start” by default, so all elements will be left aligned by default, but I still think that the only column should take the whole width of the Grid.

    Cheers
    Laurent

  4. Thomas LEBRUN Says:

    Hi Laurent,

    I agree too: for me, it’d a bug that needs to be fixed. XAML developers are used to know particular default values. Changing them is not terrible but it’ll be a pain for a lot of developpers to understand what’s wrong….

  5. Pete O'Hanlon Says:

    As it’s based on prior art, I would expect it to follow the conventions. XAML column definitions is a well known and well understood paradigm, so it would make sense for Xamarin Forms to follow what’s already there. Of course, as an old WPF dev, I might be biased.

  6. Derek Says:

    http://forums.xamarin.com/discussion/comment/66362/#Comment_66362

  7. Why is ColumnDefinition set to Auto and not Star by default? Xamarin Forms Says:

    […] windows-phone , wpdev , xamarin , laurent-bugnion Read original post by Laurent Bugnion at GalaSoft BlogHere is a small difference between “Windows XAML” and “Xamarin Forms XAML” […]

  8. Jerrie Pelser Says:

    Oh yeah, this one tripped me up as well. I could not understand why my column did not span the entire grid until I realised I always needed to specify a column definition even if I had only a single column in my grid.

Comments for Why is ColumnDefinition set to Auto and not Star by default? Xamarin Forms