0

I have a main view with a secondary child view ChildViewModel inside it:

<Window {...}>
  <Window.Resources> {...} </Window.Resources>

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

    <Grid Grid.Row="0"> {...} </Grid>

    <StackPanel Grid.Row="1"> {...} </StackPanel>

    <ContentControl Grid.Row="2"
                    Content="{Binding ChildViewModel}"/>

  </Grid>
</Window>

The ChildViewModel contains another grid of elements, with a Stack Panel of two buttons at the bottom. I would like these two buttons to be stuck to the bottom of the whole window.

I have tried this method, however it doesn't quite work as either the whole content control is at the bottom (with a large white gap at the top), or the buttons are at the bottom of the content control, but the content control itself is not at the bottom.

The following image should explain visually what I mean. The buttons are the two small rectangles that I would like at the bottom.

EDIT: Code of the Content Control:

  <UserControl {..}>
  <UserControl.DataContext>
    <viewModels:ChildViewModel />
  </UserControl.DataContext>

  <Grid FocusVisualStyle="{x:Null}">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid.Resources>
      {..}
    </Grid.Resources>

    <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}"> 
    {..}
    </ScrollViewer>

    <customViews:SwirlyThingy Grid.Row="1" {..}/>

    <TextBlock Grid.Row="2" {..}/>

    <TextBlock Grid.Row="3" {..}/>

    <TextBlock Grid.Row="4" {..}}"/>

    <!--The buttons I'd like at the bottom-->
    <StackPanel Grid.Row=5"
                VerticalAlignment="Bottom"
                Orientation="Horizontal"
                misc:MarginSetter.Margin="6">
      <Button Command="{Binding PrepareForMigrationCommand}"
              IsEnabled="{Binding CanMigrate,
                                   UpdateSourceTrigger=PropertyChanged}">
        <Button.Style>
          <Style BasedOn="{StaticResource MajorControlButton}" TargetType="Button">
            <Setter Property="Content" Value="Migrate" />
            <Style.Triggers>
              <DataTrigger Binding="{Binding PrepareForMigrationCommand.Execution.IsNotCompleted}"
                           Value="True">
                <Setter Property="Content" Value="Migrating..." />
              </DataTrigger>
            </Style.Triggers>
          </Style>
        </Button.Style>
      </Button>
      <Button Command="{Binding PrepareForMultiMigrationCommand}"
              Visibility="{Binding IsMultiMigration,
                                    UpdateSourceTrigger=PropertyChanged,
                                    Converter={StaticResource BooleanToVisibilityConverter}}">
        <Button.Style>
          <Style BasedOn="{StaticResource MajorControlButton}" TargetType="Button">
            <Setter Property="Content" Value="Run All" />
          </Style>
        </Button.Style>
      </Button>

    </StackPanel>
  </Grid>
</UserControl>

image of how I'd like the format to be

monadoboi
  • 1,651
  • 3
  • 16
  • 26
  • 1
    "What I want" is not exactly *sticking*. Can you show content of data template for `ChildViewModel` (as wanted white space has to be added there)? Another thing it's not clear what define the height for white spaces, you have two of such in "What I want", how they are distributing available space? If you just want to pull down the border of otherwise centered control, then you need to refer to original height somehow. Easy way to achieve it is to have another grid (typically behind everything) on the same level in the visual tree. Then you can bind other controls to its actual size. – Sinatr Mar 25 '20 at 12:43
  • I will add the code for the content control now. As for the size of the white space, it should be variable as elements are added/removed depending on what the user does. The content control itself changes in size and can take up the full space of the window. I suppose pulling down the border is what I'd like. The size of the window itself is fixed so that might make it easier. Creating a grid that changes in size might be the solution. – monadoboi Mar 25 '20 at 12:56
  • The problem is two measure passes: one to get size of content control as on first picture and another to actually center it and pull down the border. If you are ok with having it twice in visual tree (I doubt it, first one can be overlapped and disabled, but still), then double xaml above, remove from second last row and bind the height of first empty row to an actual height of any star row from the first. Then add star row inside content control and it should work. – Sinatr Mar 25 '20 at 14:57

1 Answers1

2

You want to take up all available space for the last item. In order to do this you would star size your last row of your top level grid.

<Grid.RowDefinitions>
  <RowDefinition Height="Auto" />
  <RowDefinition Height="Auto" />
  <RowDefinition Height="*" />    <!-- Star size this one -->
</Grid.RowDefinitions>

In your control you could simply have two rows, one for all of your content which would be contained in a stackpanel (instead of multiple rows). And one row for your buttons. Your button panel would be aligned to the bottom.

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

    <Grid Grid.Row="0">
        <Rectangle Height="20" Fill="Red"/>
    </Grid>

    <StackPanel Grid.Row="1">
        <Rectangle Height="20" Fill="Orange"/>
        <Rectangle Height="20" Fill="Yellow"/>
        <Rectangle Height="20" Fill="Green"/>
    </StackPanel>

    <Grid Grid.Row="2"> <!-- simulating your custom control -->
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0">
            <!-- A bunch of content here
        </StackPanel>

        <StackPanel Grid.Row="1"
                    Orientation="Horizontal"
                    VerticalAlignment="Bottom">
            <Button Content="Click Me!"/>
            <Button Content="No, Me!"/>
        </StackPanel>
    </Grid>
</Grid>
Shawn Kendrot
  • 12,425
  • 1
  • 25
  • 41
  • Can you post a picture or better a gif of what you did? Btw, `` is simply `` – Sinatr Mar 25 '20 at 14:51
  • I just realised there was a mistake in my code, and the `RowDefinitions` in the child were all Auto (edited now). I don't quite understand what's going on in the row definitions in your code. Could you please explain :) EDIT: It does seem to work however (with some slight changes)! I didn't need to have them all as `*` but just a few on the middle rows. – monadoboi Mar 25 '20 at 15:07
  • I updated my answer to address your new row sizing. If all of the rows inside your control are auto sized, then just use a stack panel. Generally a little easier. However, you would still want to make the last row be star sized (take up all available space). – Shawn Kendrot Mar 25 '20 at 15:18