Aryan M
Aryan M

Reputation: 667

Xamarin Forms: How to set the width of two columns in a grid dynamically using mvvm

I need to make a calculation in my view model to show a percentage range between two columns in a grid.

I'm trying to set a string property to set the values in the view model as below,

// These two below values/ratio would be calculated dynamically,

public string firstColValue = "3*";
public string secondColValue = "7*";

<Frame CornerRadius="8" Grid.Row="0" HorizontalOptions="FillAndExpand" HeightRequest="8">
<Grid HorizontalOptions="FillAndExpand">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="{Binding firstColValue}">
            </ColumnDefinition>
            <ColumnDefinition Width="{Binding secondColValue}">
            </ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="8">
            </RowDefinition>
        </Grid.RowDefinitions>

            <Label Grid.Row="0" Grid.Column="0" HeightRequest="8" HorizontalOptions="FillAndExpand" BackgroundColor="Lime"></Label>
            <Label Grid.Row="0" Grid.Column="1" HeightRequest="8" HorizontalOptions="FillAndExpand" BackgroundColor="Blue"></Label>

    </Grid>
</Frame>

This is throwing me a run time exception. I'm trying to set the width of the two columns dynamically from the view model property.

Please let me know how to achieve this.

Upvotes: 0

Views: 2252

Answers (2)

pinedax
pinedax

Reputation: 9356

This error is because you are Binding a string to the Width which require another object.

To fix this one of the solution would be using a Converter that will convert your type (the one coming from the ViewModel) into the type expected for the Grid Width. More info about Converters here

The Converter you need would look like this:

public class IntToGridLengthConverter : IValueConverter
{
    public IntToGridLengthConverter()
    {
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var intValue = System.Convert.ToInt32(value);
        return new GridLength(intValue, GridUnitType.Star);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Then in the XAML you just need to use it.

Adding a new section to the XAML and calling the Converter

<ContentPage.Resources>
    <ResourceDictionary>
        <local:IntToGridLengthConverter x:Key="gridLengthConverter" />
    </ResourceDictionary>
</ContentPage.Resources>

Then using the Converter in your Bindings

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="{Binding firstColValue, Converter={StaticResource gridLengthConverter}}" />            
    <ColumnDefinition Width="{Binding secondColValue, Converter={StaticResource gridLengthConverter}}"/>            
</Grid.ColumnDefinitions>

As you can see I am using the Key that was set in the previous part.

One small change you need to do in your ViewModel properties is that now they should be of type int (integer). So in your ViewModel you would set only the integer part of the value you wanna set, for example:

firstColValue = 7; 
secondColValue = 3;

The work to convert these values into 7* and 3* respectively will be responsible of the Converter.

Using Converters will prevent you from using Xamarin.Forms elements in your ViewModels as these should be agnostic. Also, this Converter can be reused in any other page you need.

Hope this helps.-

Upvotes: 3

Bruno Caceiro
Bruno Caceiro

Reputation: 7199

Your problem is the object you are trying to bind. You need to use a GridLength

For example

GridLength test =  new GridLength(3, GridUnitType.Star); // which is "3*"

Just update your ViewModel to return a value of type GridLength

Upvotes: 2

Related Questions