Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change scaling order WPF

I have a WPF application that needs to be sort of responsive. What I want to have is a DataGrid inside a Grid. When the window scales down, I want the Grid to resize first, and then the DataGrid. Here is what I achieved so far:

enter image description here

In the gif on top you can see that the Grid resizes first, and when it reaches it's minimum scaling size, it goes over the bottom DataGrid. Not exactly what I want because I want to scale the layout first, then show a scrollbar in the DataGrid instead of the layout just going over it. So I tried the following:

enter image description here

Right here you can see that it shows the scrollbars like I want. The only thing is that it first resizes the DataGrid, and when it's done resizing the DataGrid, it starts to resize the Grid. I want it to be the other way around, first resize the grid, then resize the DataGrid and show the Scrollbars. So basically I'm searching for a solution that does the following:

  1. Scale the window which scales the Grid.
  2. Scale the grid till it's minimum size
  3. When it has reached the minimum size and it's still getting smaller, show scrollbar in DataGrid.

So that comes down to the first Gif from this question, followed by scrollbars in the DataGrid

Is there any way to do this? It seems like I'm very close since it's a combination of those two things but I don't know how. Here's my code:

<Grid Grid.Row="1" HorizontalAlignment="Right"  Grid.Column="0">
  <Grid ShowGridLines="False">
    <Grid.RowDefinitions>
      <RowDefinition MaxHeight="50"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="20"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="5"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="5"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="5"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="50"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="50"/>
      <RowDefinition Height="auto"/>
      <RowDefinition MaxHeight="5"/>
      <RowDefinition Name="DataGridRow" Height="*" MaxHeight="240" />
    </Grid.RowDefinitions>

    <Label Grid.Row="1" FontSize="24">Test</Label>
    <Label Grid.Row="3" Content="Test"/>
    <ComboBox Grid.Row="5" MaxWidth="500" MinWidth="300" HorizontalAlignment="Left"  />
    <Label Grid.Row="7" Content="Test"/>
    <ComboBox Grid.Row="9" MaxWidth="500" MinWidth="300" HorizontalAlignment="Left"/>
    <Separator Grid.Row="11"/>

    <Label Grid.Row="13" Content="Test" />
    <Grid Grid.Row="15">
      <DataGrid
          RowHeight="40"
           CanUserAddRows="False"
            x:Name="dataGrid"
            AutoGenerateColumns="False"
            CanUserResizeColumns="True"
            HeadersVisibility="None"
            GridLinesVisibility="None"
            ScrollViewer.CanContentScroll="True"
            ScrollViewer.VerticalScrollBarVisibility="Visible"
            ScrollViewer.HorizontalScrollBarVisibility="Auto"
        <DataGrid.Columns>
          <DataGridTextColumn IsReadOnly="True" Width="*" Binding="{Binding Name}">
            <DataGridTextColumn.ElementStyle>
              <Style TargetType="TextBlock">
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="Margin" Value="2,0,0,0"/>
              </Style>
            </DataGridTextColumn.ElementStyle>
          </DataGridTextColumn>
        </DataGrid.Columns>
      </DataGrid>
    </Grid>
  </Grid>
</Grid>
like image 915
Markinson Avatar asked Nov 11 '16 12:11

Markinson


2 Answers

In those cases where solving the layout equation is no longer possible with the default building blocks, you can do the calculations yourself. Letting a converter calculate the available space that's left.

The remaining problem is twofold:

  1. The DataGrid may only shrink when the star sized rows have ActualHeight 0.

    Solution: DataGrid.Style that sets dataGrid.MaxHeight when triggerGrid.ActualHeight = 0 (triggerGrid occupies a star sized row).

  2. When we're giving a MinHeight to DataGridRow it won't shrink when the dataGrid.ActualHeight shrinks (it steals the shrunk height back).

    Solution: RowDefinition.Style that sets its MinHeight to dataGrid.ActualHeight when triggerGrid.ActualHeight = 0 and to the fixed value otherwise.

I've set the Controls' BackGround colors to illustrate when the star sized height (remaining white space) becomes 0.

<Window 

    ...

    Width="200" Height="450">
    <Window.Resources>
        <local:HeightConverter x:Key="HeightConverter" />
        <local:IsEqualToZeroConverter x:Key="IsEqualToZeroConverter" />
    </Window.Resources>
    <!--MainGrid-->
    <Grid x:Name="mainGrid">
        <Grid ShowGridLines="False">
            <Grid.RowDefinitions>
                <RowDefinition MaxHeight="50"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="20"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="5"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="5"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="5"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="50"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="50"/>
                <RowDefinition Height="auto"/>
                <RowDefinition MaxHeight="5"/>
                <RowDefinition x:Name="dataGridRow" Height="Auto">
                    <RowDefinition.Style>
                        <Style TargetType="{x:Type RowDefinition}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ActualHeight, ElementName=triggerGrid, Converter={StaticResource IsEqualToZeroConverter}}" Value="True">
                                    <Setter  Property="MinHeight" Value="{Binding ActualHeight, ElementName=dataGrid}"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding ActualHeight, ElementName=triggerGrid, Converter={StaticResource IsEqualToZeroConverter}}" Value="False">
                                    <Setter  Property="MinHeight" Value="80.0"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </RowDefinition.Style>
                </RowDefinition>
            </Grid.RowDefinitions>
            <Label x:Name="bigLabel" Grid.Row="1" FontSize="24" Background="LightGray">Test</Label>
            <Label x:Name="regularLabel" Grid.Row="3" Content="Test" Background="LightGray"/>
            <ComboBox x:Name="comboBox" Grid.Row="5" MaxWidth="500" MinWidth="300" HorizontalAlignment="Left"  Background="LightGray" />
            <Label Grid.Row="7" Content="Test" Background="LightGray"/>
            <ComboBox Grid.Row="9" MaxWidth="500" MinWidth="300" HorizontalAlignment="Left" Background="LightGray"/>
            <Separator x:Name="separator" Grid.Row="11"/>
            <Label Grid.Row="13" Content="Test"  Background="LightGray"/>
            <!--TriggerGrid-->
            <Grid Grid.Row="14" x:Name="triggerGrid"/>
            <Grid Grid.Row="15">
                <DataGrid
                    x:Name="dataGrid"
                    RowHeight="40"
                    CanUserAddRows="False"
                    AutoGenerateColumns="False"
                    CanUserResizeColumns="True"
                    HeadersVisibility="None"
                    GridLinesVisibility="None"
                    ScrollViewer.CanContentScroll="True"
                    ScrollViewer.VerticalScrollBarVisibility="Visible"
                    ScrollViewer.HorizontalScrollBarVisibility="Auto">
                    <DataGrid.Style>
                        <Style TargetType="{x:Type DataGrid}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ActualHeight, ElementName=triggerGrid}" Value="0">
                                    <Setter Property="MaxHeight">
                                        <Setter.Value>
                                            <MultiBinding Converter="{StaticResource HeightConverter}">
                                                <Binding ElementName="mainGrid" Path="ActualHeight"/>
                                                <Binding ElementName="bigLabel" Path="ActualHeight"/>
                                                <Binding ElementName="regularLabel" Path="ActualHeight"/>
                                                <Binding ElementName="comboBox" Path="ActualHeight"/>
                                                <Binding ElementName="separator" Path="ActualHeight"/>
                                            </MultiBinding>
                                        </Setter.Value>
                                    </Setter>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </DataGrid.Style>
                    <DataGrid.Columns>
                        <DataGridTextColumn IsReadOnly="True" Width="*" Binding="{Binding Name}">
                            <DataGridTextColumn.ElementStyle>
                                <Style TargetType="TextBlock">
                                    <Setter Property="VerticalAlignment" Value="Center" />
                                    <Setter Property="Margin" Value="2,0,0,0"/>
                                </Style>
                            </DataGridTextColumn.ElementStyle>
                        </DataGridTextColumn>
                    </DataGrid.Columns>
                </DataGrid>
            </Grid>
        </Grid>
    </Grid>
</Window>

Converters

public class HeightConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // only 1 check at startup (Debugging)
        if ((double)values[1] == 0.0) return 0.0;

        double mainGridHeight       = (double)values[0];
        double bigLabelHeight       = (double)values[1];
        double regularLabelHeight   = (double)values[2];
        double comboBoxHeight       = (double)values[3];
        double separatorHeight      = (double)values[4];

        double dataGridHeight = mainGridHeight - bigLabelHeight - 2 * (regularLabelHeight + comboBoxHeight) - regularLabelHeight - separatorHeight;

        if (dataGridHeight > 0.0) return dataGridHeight; else return 0.0;
    }

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

public class IsEqualToZeroConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((double)value == 0.0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
like image 109
Funk Avatar answered Nov 15 '22 21:11

Funk


This is not the exact answer. But, it will give an idea to achieve your need.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />            
        <RowDefinition Height="5" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <DockPanel>                        
        <TextBlock DockPanel.Dock="Bottom" Grid.Row="1" FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" MaxHeight="240">DataGrid</TextBlock>
        <Separator DockPanel.Dock="Bottom"/>
        <TextBlock DockPanel.Dock="Bottom" FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Top</TextBlock>
    </DockPanel>
    <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" />
    <TextBlock Grid.Row="2" FontSize="55" HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap">Bottom</TextBlock>
</Grid>

Hope that helps.

like image 34
Gopichandar Avatar answered Nov 15 '22 23:11

Gopichandar