none
Image Sized to grid height (proportional) RRS feed

  • Question

  • Im trying to create a WPF UserControl that contains an image docked to the left side, and a 2 column table on the right. I want the control to automatically resize so that it is tall enough to contain the contents of the table (a grid panel with 2 columns, 3 rows).

    The control will resize correctly with just the grid, but once I add the image on the left hand side, things stop working.  I have it kind of working - but the issue is that the control seems to always resize the height of the control based on the size of the image, rather than the size of the grid (the picture is currently taller than the grid).

    If my image is 50 wide x 100 tall, and the grid is sized to be 50 tall...I ultimately want the image to be 'stretched' down to 25x50 to match the grid.  If the grid is 75 tall, I want the image to be 37x75, etc. And then have the user control match the height of the grid and image.

    Any thoughts on what my layout should look like to accomplish this?  I've tried all sorts of combinations of width, heights, alignments, etc, but cant seem to get the image to resize correctly so that it matches the height of the grid (based on grid contents - # of rows, font size, etc).

    Not sure if I need to put a grid inside of a grid, or some other layout.  Right now I have a dockpanel with an image docked to the left, and the grid fills the remaining space.

    Any help would be appreciated.

    Friday, December 6, 2013 2:45 PM

Answers

  • Ok now I understand what you looking for. I hope I understand lol

    Take a look at this code. I placed border with different border color to show you that image and grid have the same size.

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Canvas Width="50" Grid.Column="0">
                <Canvas.Background>
                    <RadialGradientBrush>
                        <GradientStop Color="#FF3AD83A" Offset="0"/>
                        <GradientStop Color="#FF4D784D" Offset="1"/>
                    </RadialGradientBrush>
                </Canvas.Background>
            </Canvas>
            <Border Grid.Column="1" BorderBrush="Black" BorderThickness="3" VerticalAlignment="Top">
                <Image Source="..."
                       Stretch="Fill"
                       Height="{Binding Path=ActualHeight, ElementName=owner}"/>
            </Border>
            <Border x:Name="owner" Grid.Column="2" BorderBrush="Blue" BorderThickness="3" VerticalAlignment="Top">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Label Content="Long Label" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Top" FontSize="16" Padding="5,1"/>
                    <Label Content="Even Longer Label" Grid.Column="1" HorizontalAlignment="Right" Margin="0" VerticalAlignment="Center" Padding="5,1"/>
                    <Label Content="Label" HorizontalAlignment="Left" Margin="0" Grid.Row="1" FontSize="16" VerticalAlignment="Center" Grid.ColumnSpan="2" Padding="5,1"/>
                    <Label Content="Label" HorizontalAlignment="Left" Margin="0" Grid.Row="2" VerticalAlignment="Bottom" Padding="5,1"/>
                    <Label Content="Label" HorizontalAlignment="Right" Margin="0" Grid.Row="2" VerticalAlignment="Bottom" Grid.ColumnSpan="2" Padding="5,1"/>
                </Grid>
            </Border>
        </Grid>

    I bound the height of right most grid with all the labels and bound it to image height.

    • Marked as answer by kjwinkel Saturday, December 7, 2013 4:58 PM
    Saturday, December 7, 2013 11:17 AM

All replies

  • I get you but I need your xaml code. Please provide your code.

    Friday, December 6, 2013 2:54 PM
  • Heres where im currently at (which really screws up, unless I set the maxwidth or maxheight on the image)

    <UserControl x:Class="TestProj.TestControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 mc:Ignorable="d"
                 d:DesignHeight="155" d:DesignWidth="413" Padding="10">
        <Grid>
            <Grid HorizontalAlignment="Stretch" Margin="0" Name="grid1" VerticalAlignment="Stretch">
                <DockPanel Name="dockPanel1">
                    <Canvas Name="canvas1" Width="5" HorizontalAlignment="Left">
                        <Canvas.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FF66F866" Offset="0" />
                                <GradientStop Color="#FF007700" Offset="1" />
                            </LinearGradientBrush>
                        </Canvas.Background>
                    </Canvas>
                    <Grid DockPanel.Dock="Left">
                        <Image Name="image1" Source="/TestProj;component/Images/image.png" HorizontalAlignment="Center" Stretch="Fill" />
                    </Grid>
                    <Grid Name="grid2" Margin="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Label Content="First" Name="label1" VerticalAlignment="Top" FontSize="16" Padding="5,1" FontWeight="Bold" Grid.Column="1" />
                        <Label Content="second" HorizontalAlignment="Right" Name="label2" Grid.Column="2" VerticalAlignment="Top" IsEnabled="True" Foreground="#FF909090" FontSize="14" Padding="5,1,1,1" />
                        <Label Content="Third" Grid.ColumnSpan="2" Grid.Row="1" Margin="0" Name="label3" VerticalAlignment="Center" FontSize="14" Padding="5,1" FontWeight="Bold" Grid.Column="1" />
                        <Label Content="Fourth" Grid.Row="2" Name="label4" VerticalAlignment="Bottom" FontSize="14" Foreground="#FF7A7A7A" Padding="5,1" Grid.Column="1" />
                        <Label Content="Fifth" HorizontalAlignment="Right" Name="label5" VerticalAlignment="Bottom" Grid.Column="2" Grid.Row="2" FontSize="14" Foreground="#FF777777" Padding="5,1" />
                    </Grid>
                </DockPanel>
            </Grid>
        </Grid>
    </UserControl>

    Friday, December 6, 2013 3:13 PM
  • Is this what you need?

        <Grid>
            <Grid HorizontalAlignment="Stretch" Margin="0" Name="grid1" VerticalAlignment="Stretch">
                <DockPanel Name="dockPanel1" LastChildFill="False">
                    <Canvas Name="canvas1" HorizontalAlignment="Left" Width="100">
                        <Canvas.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FF66F866" Offset="0" />
                                <GradientStop Color="#FF007700" Offset="1" />
                            </LinearGradientBrush>
                        </Canvas.Background>
                    </Canvas>
                    <Grid DockPanel.Dock="Left">
                        <Image Source="http://31.media.tumblr.com/MlgRLzY1yi5y061jY0VFGiupo1_500.jpg"/>
                    </Grid>
                    <Grid Name="grid2" Margin="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Label Content="First" Name="label1" VerticalAlignment="Top" FontSize="16" Padding="5,1" FontWeight="Bold" Grid.Column="1" />
                        <Label Content="second" HorizontalAlignment="Right" Name="label2" Grid.Column="2" VerticalAlignment="Top" IsEnabled="True" Foreground="#FF909090" FontSize="14" Padding="5,1,1,1" />
                        <Label Content="Third" Grid.ColumnSpan="2" Grid.Row="1" Margin="0" Name="label3" VerticalAlignment="Center" FontSize="14" Padding="5,1" FontWeight="Bold" Grid.Column="1" />
                        <Label Content="Fourth" Grid.Row="2" Name="label4" VerticalAlignment="Bottom" FontSize="14" Foreground="#FF7A7A7A" Padding="5,1" Grid.Column="1" />
                        <Label Content="Fifth" HorizontalAlignment="Right" Name="label5" VerticalAlignment="Bottom" Grid.Column="2" Grid.Row="2" FontSize="14" Foreground="#FF777777" Padding="5,1" />
                    </Grid>
                </DockPanel>
            </Grid>
        </Grid>

    I set the DockPanel to LastChildFill = false. The default is true and so was the Grid since it is the last child always filling the space. Now it doesnt :)

    Friday, December 6, 2013 8:00 PM
  • That doesn't seem to do it

    Here is what Im getting with my latest code:

    But this is what I want:

    Im wondering if Im not going to be able to accomplish what I want without some code - but hoping I could.

    Saturday, December 7, 2013 3:06 AM
  • Now you have a list all of a sudden. Could you post code please.
    Saturday, December 7, 2013 3:17 AM
  • Well, on my main form I have a StackPanel that will contain a bunch of these user controls - so I was just showing you what I was ending up with.

    This is the code I was using for the top picture, I took out the DockPanel, and switched it to a 3-column grid. 

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Canvas Width="5" Grid.Column="0">
                <Canvas.Background>
                    <RadialGradientBrush>
                        <GradientStop Color="#FF3AD83A" Offset="0"/>
                        <GradientStop Color="#FF4D784D" Offset="1"/>
                    </RadialGradientBrush>
                </Canvas.Background>
            </Canvas>
            <Image Grid.Column="1" Source="soccer.png" Margin="0" Stretch="UniformToFill"/>
            <Grid Grid.Column="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Label Content="Long Label" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Top" FontSize="16" Padding="5,1"/>
                <Label Content="Even Longer Label" Grid.Column="1" HorizontalAlignment="Right" Margin="0" VerticalAlignment="Center" Padding="5,1"/>
                <Label Content="Label" HorizontalAlignment="Left" Margin="0" Grid.Row="1" FontSize="16" VerticalAlignment="Center" Grid.ColumnSpan="2" Padding="5,1"/>
                <Label Content="Label" HorizontalAlignment="Left" Margin="0" Grid.Row="2" VerticalAlignment="Bottom" Padding="5,1"/>
                <Label Content="Label" HorizontalAlignment="Right" Margin="0" Grid.Row="2" VerticalAlignment="Bottom" Grid.ColumnSpan="2" Padding="5,1"/>
            </Grid>
        </Grid>
    
    For the bottom picture, I just manually set the height on the image so it matched up with the size of the 'labels' grid - which is what I am trying to make so that if I change the font size of the labels, or the number of rows - the image will automatically resize the height (and width) to match.

    Saturday, December 7, 2013 3:41 AM
  • The WPF layout system is excellent but it takes a bit of user knowledge to tweak things the way you want.

    Here's a few things I've learned over the years:

    • If you want a control type that easily resized and flows with the window use a Grid.
    • You can set up column and row definitions in the grid that are percentages of the grid instead of static numbers.
    • Don't use static numbers for widths and heights if you want resize-ability.
    • Use Horizontal and Vertical widths and heights of "Stretch" to get the flow to match the window size.

    If you do those things the WPF layout system does a superb job of determining the layout rules.  Stick with percentages and "Stretch" unless absolutely unavoidable.  FYI, the WPF system makes three passes on the layout, this means that it does a ton of work to do what it does.  Whenever you specify static values for widths and heights you are actually saying in essence "I'm smarter than the WPF rendering logic".  One of the things you will discover is that not all controls play the same way (Stack panels vs. Grids).  It's tough enough just to figure this stuff out let alone add other constraints.


    JP Cowboy Coders Unite!

    Saturday, December 7, 2013 3:55 AM
  • Ok now I understand what you looking for. I hope I understand lol

    Take a look at this code. I placed border with different border color to show you that image and grid have the same size.

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Canvas Width="50" Grid.Column="0">
                <Canvas.Background>
                    <RadialGradientBrush>
                        <GradientStop Color="#FF3AD83A" Offset="0"/>
                        <GradientStop Color="#FF4D784D" Offset="1"/>
                    </RadialGradientBrush>
                </Canvas.Background>
            </Canvas>
            <Border Grid.Column="1" BorderBrush="Black" BorderThickness="3" VerticalAlignment="Top">
                <Image Source="..."
                       Stretch="Fill"
                       Height="{Binding Path=ActualHeight, ElementName=owner}"/>
            </Border>
            <Border x:Name="owner" Grid.Column="2" BorderBrush="Blue" BorderThickness="3" VerticalAlignment="Top">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Label Content="Long Label" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Top" FontSize="16" Padding="5,1"/>
                    <Label Content="Even Longer Label" Grid.Column="1" HorizontalAlignment="Right" Margin="0" VerticalAlignment="Center" Padding="5,1"/>
                    <Label Content="Label" HorizontalAlignment="Left" Margin="0" Grid.Row="1" FontSize="16" VerticalAlignment="Center" Grid.ColumnSpan="2" Padding="5,1"/>
                    <Label Content="Label" HorizontalAlignment="Left" Margin="0" Grid.Row="2" VerticalAlignment="Bottom" Padding="5,1"/>
                    <Label Content="Label" HorizontalAlignment="Right" Margin="0" Grid.Row="2" VerticalAlignment="Bottom" Grid.ColumnSpan="2" Padding="5,1"/>
                </Grid>
            </Border>
        </Grid>

    I bound the height of right most grid with all the labels and bound it to image height.

    • Marked as answer by kjwinkel Saturday, December 7, 2013 4:58 PM
    Saturday, December 7, 2013 11:17 AM
  • Awesome - Thanks!  Im moving from WinForms to WPF, so a lot of this is new to me (binding properties, etc)

    Your code worked great - only had to move the x:Name="owner" from the border to the grid since that's what the image needed to be sized to.  Thanks for figuring this out for me.

    Saturday, December 7, 2013 3:41 PM
  • You welcome, feel free to mark the answer
    Saturday, December 7, 2013 4:22 PM