Xamarin.Forms bind Height of Grid to Width of Butt

2020-07-18 09:31发布

问题:

I try to build the following UI Element with Xamarin.Forms. I was able to build this with UWP by binding the Height property of the TopGrid to the ActualWidth property of Button1. However this is not working in Xamarin.Forms, because there is no ActualWidth property. I already tried binding the Height of TopGrid to WidthRequest, but without success.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid x:Name="TopGrid" Grid.Row="0" BindingContext="{x:Reference Name=Button1}"  Height="{Binding Path=WidthRequest}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Button x:Name="Button1" Grid.Column="0" Text="1" />
        <Button x:Name="Button2" Grid.Column="1" Text="2" />
        <Button x:Name="Button3" Grid.Column="2" Text="3" />
        <Button x:Name="Button4" Grid.Column="3" Text="4" />
    </Grid>
</Grid>

Does anybody have experience with Xamarin.Forms and can help me with this problem?

回答1:

First thing first: Xaml names are case-sensitive, so instead of

BindingContext="{x:Reference Name=button1}"

this should be

BindingContext="{x:Reference Name=Button1}"

Beside this, your Xaml was almost ok. Let's look at

Height="{Binding Path=WidthRequest}"

You're trying to bind to the view's height, but the HeightProperty is a read-only BindableProperty, so you can't set it. If you look at the API, there's no public setter for the Height property either. So, instead of binding to the Height, you should bind to the HeightRequest.

HeightRequest="{Binding Path=WidthRequest}"

That's the way of saying that you'd like the Grid to be of that height, and the layout system will do its best to make you happy (but that's a best effort only).

I think you get this by now. The button WidthRequest is the request made by the user, and in this case, it's not set and it's value is left to the default. Instead, you want to use the button's actual Height as source property of your binding. Let's do it:

HeightRequest="{Binding Width}"

and this gives the expected result:

Here's the full corrected Xaml snippet:

<Grid>
  <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
  </Grid.RowDefinitions>
  <Grid x:Name="TopGrid" Grid.Row="0" BindingContext="{x:Reference Name=Button1}"  HeightRequest="{Binding Width}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Button x:Name="Button1" Grid.Column="0" Text="1" BackgroundColor="Pink"/>
    <Button x:Name="Button2" Grid.Column="1" Text="2" BackgroundColor="Pink"/>
    <Button x:Name="Button3" Grid.Column="2" Text="3" BackgroundColor="Pink"/>
    <Button x:Name="Button4" Grid.Column="3" Text="4" BackgroundColor="Pink"/>
  </Grid>
</Grid>


回答2:

If you don't want to set the BindingContext for the whole grid (and every item in it), then you can just specify it directly in the binding as follows, allowing all other controls to retain their original BindingContext:

 <Grid x:Name="TopGrid" Grid.Row="0" HeightRequest="{Binding Width, Source={x:Reference Button1}}">