Viewbox containing a TextBlock seems to have minimum height - wpf

I'm trying to build a UI layout in WPF that can scale with the size of the window. The idea is to have a number of controls on the left, a number of controls on the right, and in the middle, have a line of text. It's OK if the line of text is cropped on the right. The main thing is that the aspect ratio of all of the controls is maintained.
That part is working fine. The problem is that the center line of text seems to have a minimum height; below this height, it will start clipping vertically. I want the text to keep shrinking if I make the window very thin. Even manually setting the FontSize on the TextBlock doesn't work.
Note that the controls on the left and right do not have a minimum width; they can shrink indefinitely.
My XAML is here. I'm using .NET 4.0.
<Window x:Class="TestWpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="75" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Viewbox Grid.Column="0" Stretch="UniformToFill" Margin="2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">A</Button>
<Button Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">B</Button>
<Button Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">C</Button>
<Button Grid.Column="3" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">D</Button>
</Grid>
</Viewbox>
<Viewbox VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="1" Stretch="UniformToFill" Margin="2">
<TextBlock>Here is a bunch of text that may prove to be interesting.</TextBlock>
</Viewbox>
<Viewbox Grid.Column="2" Stretch="UniformToFill" Margin="2">
<Button HorizontalAlignment="Center">X</Button>
</Viewbox>
</Grid>
</Window>

The problem is that you like the Viewbox clipping when it occurs horizontally but don't want any clipping vertically. In other words, you want UniformToFill until the horizontal clipping stops and then you want to switch to Uniform.
To get both of these behaviors you need an alternative to Viewbox. A while ago I wrote a prototype of just such a layout element in this Stack Overflow answer called ViewboxPanel:
Making a Viewbox scale vertically but stretch horizontally
I just tested it, and at least for your sample XAML, I think it does just what you want:
<local:ViewboxPanel VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="1" Margin="2">
<TextBlock>Here is a bunch of text that may prove to be interesting.</TextBlock>
</local:ViewboxPanel>

Related

Strange white box covering controls

In the Designer everything looks alright but in Debbuging a weird white rectangle covers a part of it (If I don't set any Margin in the Button, It looks fine).
Designer
While Debugging
<Window x:Class="MyProgram.MainWindow" ResizeMode="NoResize"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:MyProgram"
mc:Ignorable="d"
Title="MyProgram" Height="450" Width="650">
<Grid>
<Label Content="Things:" HorizontalAlignment="Left" Margin="0,7,0,0" VerticalAlignment="Top" FontSize="22"/>
<Button Height="28" Width="180" Background="Transparent" BorderThickness="0" Margin="454,15,10,378" >
<StackPanel Orientation="Horizontal">
<Image Source="Resources/addpackage2.png" Width="35" />
<TextBlock Text="Add" Margin="3,0,3,0" FontSize="18" />
</StackPanel>
</Button>
</Grid>
I'm doing something wrong?
The margin on your button Margin="454,15,10,378" is constricting the space available for the button. If you make the make the window larger, you will see the whole button.
Edit
There are different ways to organize a layout in XAML, but usually a grid is a good choice.
This is one way you could write it.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Things:" HorizontalAlignment="Left" Margin="7" VerticalAlignment="Top" FontSize="22"/>
<Button Grid.Row="0" Grid.Column="1" Height="28" Width="180" Background="Transparent" BorderThickness="0" >
<StackPanel Orientation="Horizontal">
<Image Source="Resources/addpackage2.png" Width="35" />
<TextBlock Text="Add" Margin="3,0,3,0" FontSize="18" />
</StackPanel>
</Button>
</Grid>
I have added row and column definitions to the grid. In this case two rows and two columns.
The top row is sized automatically according to its content. The second row fills the remaining space.
Similarly, the right hand column is sized automatically according to its content and the left hand column fills the remaining space.
This is just an example. You might want to define a different layout. I presume that the bottom of the screen will not always be white space.
Having defined the rows and columns, you can assign the individual controls to the cells in the grid, by specifying the Grid.Row and Grid.Column properties.
I have placed your label in row 0, column 0 and I have placed the button in row 0 column 1.
Very important, is that I have removed the Margin definition from the button. This kind of positioning controls is, in my opinion, always an error.
I think that the layout is more or less as you wanted.

Stretch WPF Dockpanel contents horizontally

I have a DockPanel and it contains a ScrollViewer [ center aligned ] and a button on left and right .
My xaml is like
<DockPanel LastChildFill="True">
<Button VerticalAlignment="Stretch" HorizontalAlignment="Stretch" DockPanel.Dock="Left">Left</Button>
<Button VerticalAlignment="Stretch" HorizontalAlignment="Stretch" DockPanel.Dock="Right">Right</Button>
<ScrollViewer Name="scrollAreaPageView" HorizontalAlignment="Center" VerticalAlignment="Center"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
</ScrollViewer>
</DockPanel>
And it generates the output as expected , but Left and right butons are not stretched fully to left and right to the ScrollViewer( They are on corners only).
The screen shot of output is
How can i make it stretch fully to left and right of center scrollViewer
A DockPanel may not be ideal in this scenario you may perhaps use Grid here with the desired column definition
sample
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button>Left</Button>
<ScrollViewer Name="scrollAreaPageView"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Column="1">
</ScrollViewer>
<Button Grid.Column="2">Right</Button>
</Grid>
in above example the space available after subtracting the space required b
Alternate approach
I attempted to do it pure xaml, this approach will helo you achieve the desired without code behind. here is the example
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="{Binding ActualWidth,ElementName=scrollAreaPageView}" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button>Left</Button>
<Button Grid.Column="2">Right</Button>
</Grid>
<ScrollViewer HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="50,0"
Name="scrollAreaPageView"
HorizontalScrollBarVisibility="Auto">
</ScrollViewer>
</Grid>
Margin in the scrollAreaPageView element defines minimum width of the buttons. give it a try and see if that helps

How to layout controls in the top right hand corner in XAML/Silverlight?

I am going through the process of designing my first Silverlight application based upon the PivotViewer control from Silverlight 4. I am having problems organizing the bar at the top as per my design:
(source: richard-slater.co.uk)
I have found ways of left aligning the Logo and Title, a way of right aligning the buttons with various combinations of panels however there are two major problems with it.
The XAML looks really really ugly, nesting panels seems to work but doesn't seem like good practice.
I can't seem to find a way of handling resizing the window down without either clipping or overlapping.
I have acheived the best results with the following code:
<StackPanel x:Name="LayoutHeader" Margin="4" Height="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal">
<Image x:Name="LogoImage" Height="50" Width="50" Source="/EVEMonPivot;component/EVEMonLogoBlue.png" Grid.Column="0" Grid.Row="0" />
<TextBlock x:Name="TitleText" Height="50" Text="EVEMon Pivot" FontSize="40" Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" FontWeight="Bold" Padding="10,0,0,0" />
</StackPanel>
<StackPanel x:Name="NavHeader" Margin="4" Height="50" Grid.Column="0" Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="StackExButton" Style="{StaticResource NavButton}" Click="StackExButton_Click">EVE Online StackExchange</Button>
<Button x:Name="BugsButton" Style="{StaticResource NavButton}">Bugs & Suggestions</Button>
</StackPanel>
I intend to move some of the properties into styles, however it still feels messy.
The above code can also result in the following in small windows:
(source: richard-slater.co.uk)
Is there a better way?
If you don't like nesting panels, a Grid might be a better option. With your four elements, have a five column grid like this:
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image x:Name="LogoImage"
Height="50"
Width="50"
Source="/EVEMonPivot;component/EVEMonLogoBlue.png"
Grid.Column="0" />
<TextBlock x:Name="TitleText"
Height="50"
Text="EVEMon Pivot"
FontSize="40"
Grid.Column="1"
Grid.Row="0"
VerticalAlignment="Center"
FontWeight="Bold"
Padding="10,0,0,0" />
<Button x:Name="StackExButton"
Grid.Column="4"
Style="{StaticResource NavButton}"
Click="StackExButton_Click">EVE Online StackExchange</Button>
<Button x:Name="BugsButton"
Grid.Column="5"
Style="{StaticResource NavButton}">Bugs & Suggestions</Button>
</Grid>
This sets four columns to Auto-size, so they adjust to the size of your UI elements, and the centre column is Star-sized so it fills the rest of the space between them.
While you can use a star-sized grid column to enforce a collapsible region between the controls, you're still left to account for what happens when there simply isn't enough room (eg. 600 pixels of display in a 400-pixel wide area.) What I think you need is a ScrollViewer, which is a ContentControl that lets you determine when scroll bars appear.
In the markup below I am doing 2 things: First, I am using the Silverlight toolkit's DockPanel to isolate the left and right sections of the display (a very similar thing can be accomplished with a 3-column Grid with Cols 0 and 2 set to "Auto" and Col 1 set to "*", but the specific use of Left and Right in the DockPanel may make the intent more readable.) Second, the whole thing is being wrapped in a ScrollViewer with the HorizontalScrollBarVisibility set to "Auto" - when the contents is too big to fit, put up a scrollbar.
<UserControl xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" x:Class="SilverlightApplication2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<toolkit:DockPanel >
<StackPanel toolkit:DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top" Height="50" Margin="5">
<TextBlock Text="Some long text" FontSize="30"/>
</StackPanel>
<StackPanel toolkit:DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Right" Height="50" Margin="5">
<Button Content="First Button" Margin="5"/>
<Button Content="Second Button" Margin="5"/>
</StackPanel>
</toolkit:DockPanel>
</ScrollViewer>
<TextBlock Grid.Row="1" Text="Body Content (DataGrid, etc.)" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

Silverlight Image Stretch="Uniform" Fail for Portrait Sized Images

I am using a Silverlight 3.0 Image control, setting it's Stretch property="Uniform". Unless I am mistaken, the expected behavior for Stretch="Uniform" is that it should scale the image, maintaining aspect ratio, letterboxing as needed. This works fine for images with landscape orientations, in that they scale up to fill the space, maintaining aspect ratio without cutting off any of the image. It is a complete fail for images with a more vertical or 'portrait' orientation. Instead of scaling up to fit within the image control, they actually scale past the height constraint such that you only see the middle of the image, with top and bottom cut off. Its as if the control only uses width when scaling, and forgets to check height?
Is this a bug in the Image control, or am I missing or mis-setting a property? To reproduce, find / create an image with a 'portrait' aspect ratio (taller than it is wide) and create an Image with Stretch="Uniform".
**** UPDATE WITH REQUESTED XAML ******
Note that the reason that the size is not explicit is to allow for full screen and scaling.
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="9"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="9"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Border BorderBrush="Black" Grid.Row="0" Grid.ColumnSpan="8" BorderThickness="1, 1, 1, 0">
<Border BorderBrush="{StaticResource blackStatusMapLGB}" BorderThickness="9,9,9, 0">
<Border BorderBrush="Gray" BorderThickness="1, 1, 1, 0">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<MediaElement Height="Auto" Width="Auto" Visibility="Collapsed" AutoPlay="true" Stretch="Fill" MediaFailed="SilverlightMediaPlayer_MediaFailed" Name="previewMediaElement"/>
<Image Name="imagePreview" Stretch="Uniform"/>
</StackPanel>
</Border>
</Border>
</Border>
So, the way a vertical StackPanel works is that measures its children with an infinite Size in the vertical axis, effectively saying to the child: "you can be as tall as you like". It does not constrain the size of the child vertically (though it does constrain it in the horizontal direction).
The way the Stretch=Uniform property works on an Image with no explicit size set is it says: "be as large as you can be within the size constraints while maintaining your aspect ratio".
Now when you combine these two, you have an Image that is constrained only in the Horizontal axis; it takes all of the space available horizontally and sizes vertically to maintain the aspect ratio.
Does this explanation help you understand why you are seeing the behavior that you are seeing?
Imagine you have an image with a 2:1 aspect ratio (twice as tall as it is wide). It has Stretch=Uniform and no explicit Width/Height set. You put it in a StackPanel of size 100x100. The Image will get a size constraint of 100xInfinity. It will first size in the horizontal axis and take all of the space available to it; 100 pixels. It will then see that is has a 2:1 aspect ratio and so will size vertically to 200 pixels. So you end up with an Image of size 100x200 in a StackPanel of 100x100. So the StackPanel is forced to clip its child to the available space.
Most likely this is caused by your image's width being set (by its parent container) instead of its height. It is stretching uniformly, but its height is unconstrained, and it is being clipped.
If this does not help, please provide the XAML for its container.
I just tried this with a tall image and it worked fine. I suspect that the problem is with the Image element's container - it's actually showing the entire image, but the top and bottom are being clipped off.
Here's what I used to test:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Temp_Delete.MainPage"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White">
<Image Source="Tall.png" Stretch="Uniform"></Image>
</Grid>
</UserControl>
UPDATE: All your nested borders are throwing it off since they don't have a defined height. I'd use an ImageBrush on the top level border:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Temp_Delete.MainPage"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="9"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="9"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Border BorderBrush="Black" Grid.Row="0" Grid.ColumnSpan="8" BorderThickness="1, 1, 1, 0">
<Border.Background>
<ImageBrush Stretch="Uniform"/>
</Border.Background>
<Border BorderBrush="Black" BorderThickness="9,9,9, 0">
<Border BorderBrush="Gray" BorderThickness="1, 1, 1, 0">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<MediaElement Height="Auto" Width="Auto" Visibility="Collapsed" AutoPlay="true" Stretch="Fill" MediaFailed="SilverlightMediaPlayer_MediaFailed" Name="previewMediaElement"/>
</StackPanel>
</Border>
</Border>
</Border>
</Grid>
</UserControl>
May take a little tweaking to get all the borders to display correctly, but you can set the padding / margin on the container elements if that's important to you.
Can you verify if your image works in that XAML? Can you post more of your XAML so we can see the context?

Silverlight - Dynamic Layout

I have a Silverlight application that will run out of the browser. I want the layout to resize based on the size of the window. The layout is composed of a Grid. This Grid has a Canvas which hosts a Border, and other controls. The Canvas correctly resizes as the window resizes. However, the Border control seems to be a fixed size. How do I make the Border control stretch to the width of the Canvas and resize if the Window resizes? My code looks like the following:
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Canvas x:Name="myCanvas" Background="Lime">
<Border Canvas.Top="77" Border="Black" BorderThickness="2">
<TextBlock x:Name="myTextBlock" />
</Border>
</Canvas>
</Grid>
Thank you for your help!
Assuming you are wanting the Canvas to be bound to the first Grid.Column, then you can add RowDefinitions and then move the Border to outside the Canvas, then the following code should work.
(Only tested in WPF)
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="77"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Canvas x:Name="myCanvas" Background="Lime" Grid.RowSpan="2">
</Canvas>
<Border Grid.Row="1" Border="Black" BorderThickness="2" VerticalAlignment="Top">
<TextBlock x:Name="myTextBlock" Text="Happy TEXT" />
</Border>
</Grid>
New stuff: <Grid.RowDefinitions>, Grid.RowSpan="2" to Canvas and Grid.Row="1" plus VerticalAlignment="Top" to Border.
Text added for testing.

Resources