Spacing Question on the * operator for XAML with Grids - wpf

So, I just wanted to understand why this was happening in my WPF app as it seems to be adding a "space" or faint line without me wanting it...
I have the following XAML
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication3.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid x:Name="LayoutRoot" ShowGridLines="False" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" CornerRadius="10,10,0,0" Height="10" Background="Black"/>
<Border Grid.Row="1" Background="Black">
</Border>
<Border Grid.Row="2" CornerRadius="0,0,10,10" Height="10" Background="Black"/>
</Grid>
<StackPanel Grid.Row="1">
<Button>Some Button</Button>
</StackPanel>
</Grid>
Which renders the following window...
The problem is if you look closely at the last row connector you will see a faint gray line...
If however I replace the <RowDefinition Height="*"/> on the inner grid with a fix pixel size (i.e. <RowDefinition Height="300"/>) the line goes away. Why exactly when I am using the * value does it seem to be adding this "grey line" / "space"?

I think the problem is Anti-Aliasing
Your effect
SnapsToDevicePixels="True"
UseLayoutRounding="False"
RenderOptions.EdgeMode="Aliased"

It looks like layout rounding problem to me. If you are using WPF 4, try setting UseLayoutRounding="true" on your outer grid. Else, take a look at SnapToDevicePixels.
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.uselayoutrounding.aspx
http://www.wpftutorial.net/DrawOnPhysicalDevicePixels.html

Related

WPF Image in grid with label and caption

I've been struggling with placing an image with a label above and a caption below in a grid.
What I would like to get is the top label aligned in the middle right above the image, and the bottom label right beneath the image like this:
But what I actually get is this:
I've used the following code in my view:
<Window x:Class="ImageWithText.MainWindow"
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"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Content="This is a label"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Grid.Row="0"/>
<Image x:Name="MainImage"
Stretch="Uniform"
Grid.Row="1">
<Image.Source>
<BitmapImage UriSource="test.jpg"/>
</Image.Source>
</Image>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Top"
Grid.Row="2">
<Run Text="Some text "/>
<Run Text="Some more text"/>
</TextBlock>
</Grid>
</Grid>
</Window>
I've also tried using a DockPanel:
<Window x:Class="ImageWithText.MainWindow"
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"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel>
<Label Content="This is a label" HorizontalAlignment="Center" DockPanel.Dock="Top"/>
<Image x:Name="MainImage"
Stretch="Uniform"
DockPanel.Dock="Top">
<Image.Source>
<BitmapImage UriSource="test.jpg"/>
</Image.Source>
</Image>
<TextBlock Margin="5"
HorizontalAlignment="Center"
DockPanel.Dock="Top">
<Run Text="Some text "/>
<Run Text="Some more text"/>
</TextBlock>
</DockPanel>
</Grid>
</Window>
But then the caption is not visible if the window is not large enough.
I've tried both options for LastChildFill, but it made no difference. Does anyone know how to get this done?
Your inner grid is being stretched to fill the entirety of the outer grid. As the middle row in the inner grid is the only row with variable sizing it is then being expanded vertically but, as the image defaults to "Stretch" = "Uniform", it is only filling a certain amount of the middle row and being vertically aligned in the middle of it's row.
This should sort it:
<Grid Margin="5">
<Grid x:Name="LayoutGrid" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Content="This is a label"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Grid.Row="0"/>
<Image x:Name="MainImage"
Stretch="Uniform"
Grid.Row="1">
<Image.Source>
<BitmapImage UriSource="test.jpg"/>
</Image.Source>
</Image>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Top"
Grid.Row="2">
<Run Text="Some text "/>
<Run Text="Some more text"/>
</TextBlock>
</Grid>
</Grid>
A good way of debugging this kind of issue is to set background colour of various elements to see the areas they're occupying.
Edited to reflect comment
You need to invert the grid row definition to:
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
This is because your middle grid is being stretched to whatever the area is left so zou get the imperssion that both labels are on the far parts of the image.

Resizing problem with multiple gridsplitters and different sizes

I'm having a weird problem with Gridsplitters that I've been trying to solve all day, but neither the documentation nor Google has really been able to help me with this problem.
The issue is that I have a grid with multiple gridsplitters, where some of the rows have different height units. Three of the rows have concrete height values and one row have 1 star to let it "soak" up all the left over space.
Unfortunately this sets off some weird gridsplitter behavior. Basically, trying to set the height of GridRow 4 and 6 by manipulating the gridsplitter in Row 5, will not affect the height of row 6, the bottom row. Instead, it manipulates row 4 and row 2 and overlaps the gridsplitter in row 3.
Were I to set all the row heights to a specific pixel height, the gridsplitters all work fine, but this lets the Grid grow beyond the edge of the screen, which is not what is intended.
I've made a small sample project to illustrate the problem.
<Window x:Class="GridSplitterTest.MainWindow"
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:GridSplitterTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" >TextBlock01</TextBlock>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Center" Background="Black" ResizeBehavior="PreviousAndNext" ResizeDirection="Rows"></GridSplitter>
<TextBlock Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" >TextBlock02</TextBlock>
<GridSplitter Grid.Row="3" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Center" Background="Black" ResizeBehavior="PreviousAndNext" ResizeDirection="Rows"></GridSplitter>
<TextBlock Grid.Row="4" HorizontalAlignment="Center" VerticalAlignment="Center" >TextBlock03</TextBlock>
<GridSplitter Grid.Row="5" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Center" Background="Black" ResizeBehavior="PreviousAndNext" ResizeDirection="Rows"></GridSplitter>
<TextBlock Grid.Row="6" HorizontalAlignment="Center" VerticalAlignment="Center" >TextBlock04</TextBlock>
</Grid>
Anyone with a good idea of what is wrong and if there's any way to solve this?
I don't think anything is actually wrong here. You have all rows but one set to be fixed size. So adjusting any of the row heights only allows the grid to readjust that one row (row#2) to compensate because the other remaining rows (rows #0 & 6) are also a fixed size.
I think the only way to solve this would be to make all the textblock rows proportional. For example:
<Grid.RowDefinitions>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
</Grid.RowDefinitions>

Keep grid star size as a constant in XAML

<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
I want to define 4/3 ratio somewhere else in XAML, and then use it. Something like this:
<System:Double x:Key="Top_Part">4</System:Double>
<System:Double x:Key="Bottom_Part">3</System:Double>
<Grid.RowDefinitions>
<RowDefinition Height="{StaticResource Top_Part}"/>
<RowDefinition Height="{StaticResource Bottom_Part}"/>
</Grid.RowDefinitions>
Of course, this code is incorrect and doesn't produce desired effect. How can I do this correctly?
The type of the Height property of the RowDefinition is GridLength so you need to create GridLength instances in your resources:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<GridLength x:Key="Top_Part">4*</GridLength>
<GridLength x:Key="Bottom_Part">3*</GridLength >
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="{StaticResource Top_Part}"/>
<RowDefinition Height="{StaticResource Bottom_Part}"/>
</Grid.RowDefinitions>
<Grid Background="Blue" Grid.Row="0"/>
<Grid Background="Red" Grid.Row="1"/>
</Grid>
</Window>

WPF Layout - Fill Height, Auto Scrollbar

The Grid at the bottom contains a ListBox. It stretches vertically, but the scrollbar does not appear when it reaches the bottom.
Layout --
<RibbonWindow ResizeMode="CanResize">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel>
<Ribbon ... />
<ListBox
VerticalAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Auto"
/>
</StackPanel>
</Grid>
</RibbonWindow>
I have heard that StackPanels can cause this behavior, but replacing it with a Grid causes its own set of issues.
EDIT --
This Layout works -
<RibbonWindow ResizeMode="CanResize">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Ribbon Grid.Row="0" />
<ListBox Grid.Row="1"
VerticalAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Auto"
/>
</Grid>
</RibbonWindow>
Turns out I needed the Grid.Row="x" tags, and then I could remove the StackPanel, and everything worked.

Resizing another grid row size in WPF

I am wondering is there any way to solve this by changing XAML code?
Please look at this sample picture:
What I wants to do is when user dragging GridSeparater No.1, I want to resize thr 3rd row of grid.
This is because in this application, the first and third rows are variable size, but second one is fixed size.
Is that possible?
This is possible with ResizeBehaviour="PreviousAndNext" (Link to MSDN). This enables you to specify which rows should be affected relative to the GridSplitter.
<Grid Width="300" Height="200" Background="Yellow" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<GridSplitter Grid.Row="1"
ResizeDirection="Rows"
ResizeBehavior="PreviousAndNext"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Background="Black"
ShowsPreview="True"
Height="5"
/>
</Grid>
You could try setting both MinHeight and MaxHeight to the same value on the center row which would force recalculation of the bottom section when resizing the top. Something like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="50" MaxHeight="50" MinHeight="50"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
... other content
<GridSplitter Height="3" Grid.Row="1" HorizontalAlignment="Stretch"/>
<GridSplitter Height="3" Grid.Row="3" HorizontalAlignment="Stretch"/>
</Grid>

Resources