Search code examples
avaloniauiavalonia

How to have a responsive canvas with a maximum size?


How can I have a responsive canvas that has at it's maximum: 40% of it's parent width and 30% of it's height?

I tried to wrap it into a ViewBox, which give the responsive aspect but I can't find a way to set the maximum width and height.

The code below is my custom control, the top is the canvas and the rest is for a DataGrid. (PS: I'm happy to use other component, I'm new to Avalonia, so I'm not sure I'm using the right ones :D).

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:vm="clr-namespace:LocalArena.ViewModels"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="LocalArena.Views.MapsView"
             x:DataType="vm:MapsViewModel">
  <StackPanel>
      <Viewbox Stretch="Uniform">
          <Canvas Height="300" Width="320" Background="Yellow" Margin="20">
              <Rectangle Fill="Red" Height="100" Width="100" Margin="10"/>
              <Rectangle Fill="Blue" Height="100" Width="100" Opacity="0.5"
                         Canvas.Left="50" Canvas.Top="20"/>
              <Rectangle Fill="Green" Height="100" Width="100"
                         Canvas.Left="60" Margin="40" Canvas.Top="40"/>
              <Rectangle Fill="Orange" Height="100" Width="100"
                         Canvas.Right="70" Canvas.Bottom="60"/>
          </Canvas>
      </Viewbox>
      <DataGrid Margin="20" ItemsSource="{Binding MapItems}"
          AutoGenerateColumns="True" IsReadOnly="True"
          GridLinesVisibility="All"
          BorderThickness="1" BorderBrush="Gray">
      </DataGrid>
  </StackPanel>
</UserControl>

Solution

  • You are trying to set the size of the canvas relative to it's parent, but wrapping it in a StackPanel. You should consider using a Grid and allowing the Canvas to fill it's cell and set the rows & columns relative to the others.

    Something like this. Keep in mind * represents the biggest row/column in this example, NOT the total of the parent. So 0.3* is 30% of the other row, not the parent. But, this should provide and example, you can do the rest.

    <Grid RowDefinitions="0.3*, *" ColumnDefinitions="*,0.2*,*">
    <Viewbox Stretch="Uniform" Grid.Column="1">
        <Canvas Background="Yellow" Margin="20">
            <Rectangle Fill="Red" Height="100" Width="100" Margin="10"/>
            <Rectangle Fill="Blue" Height="100" Width="100" Opacity="0.5"
                        Canvas.Left="50" Canvas.Top="20"/>
            <Rectangle Fill="Green" Height="100" Width="100"
                        Canvas.Left="60" Margin="40" Canvas.Top="40"/>
            <Rectangle Fill="Orange" Height="100" Width="100"
                        Canvas.Right="70" Canvas.Bottom="60"/>
        </Canvas>
    </Viewbox>
    
    <DataGrid Margin="20" Grid.Row="1" Grid.ColumnSpan="3"
        ItemsSource="{Binding MapItems}"
        AutoGenerateColumns="True" IsReadOnly="True"
        GridLinesVisibility="All"
        BorderThickness="1" BorderBrush="Gray">
    </DataGrid>
    </Grid>