How to position WPF nested controls absolutely in a window - wpf

I have some controls nested in some panels.
The panels themselves are not arranged with the same x position within a window.
I'd like the controls inside the panels to have a fixed position relative to the window, not the panel (so they all line up vertically, in this case).
To be clear, the Panels themselves have an arbitrary position in the window. One can imagine that the user should be able to effect the Panel positions, but the nested controls would stick to the same X coordinate relative to the window.
I don't think I can use a Canvas, because that's positioning relative to the edges of the canvas.
Any ideas?
Many thanks.

Don't use Panels... instead, use Grids. If you use Grids, then you can take advantage of the Grid.IsSharedSizeScope Attached Property and the ColumnDefinition.SharedSizeGroup Property. Using these, you can line up columns from different Grids, as long as you have a parent Grid with the IsSharedSizeScope property set to true.
Here is an example taken from the first linked page on MSDN:
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Grid ShowGridLines="True" Margin="0,0,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0" Width="200" Height="100"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0" Width="150" Height="100"/>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0"/>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
</StackPanel>

Related

WPF, XMAL percentage spacing gets calculated all wrong

In short
My understanding is, by using the * in xaml you should get "fixed" percentages. However, even when adding two grids to an control with the exact same Row- and Columndefinitions the calculations seem to be different.
tl;dr
What I wish to do
I wanted to create a user control with a canvas or button to open a color picker. Whilst designing that control I stumbled across a problem I cannot explain myself.
The left hand side of the control should be nearly a complete mirrored copy of the right hand side with a small difference: the very outer lines should differ in their appearance slightly. Whilst the left line should be short, the right one should drop to the very bottom of the control in order to encapsulate a textblock.
My approach
In order to achieve this, I have created a "main" grid to host the three elements (Left hand design grid, center control to open the color picker and right hand grid). Ive added the center control encapsulated by a grid, just to stay consistent with my approaches for the left and right hand side.
Moving on, I have added two grids for the mentioned left and right hand side and gave them the exactly same Row- and Columndefinitions. Thinking that would do the trick, I have added a few lines to add the wished designed to the control.
The problem
I've soon noticed, that the two horizontal lines did not match up. The lines had a few pixels in between so I have tried playing around with the layout to find out, what causes that problem.
The 'solution'
It seems like everything seems to behave correctly, except for the most right hand line. Whenever its Grid.RowSpan is set to 4, meaning it will stretch to the bottom of the control, it messes with the spacing of the percentages. Out of some reason I cannot fathom it seems to change the percentages calculated by the Grid.RowDefinitions
Simply setting the Grid.ColumnSpan="4" to Grid.ColumnSpan="3" for the right most line does fix the spacing, changing the Grid.ColumnSpan="4" to Grid.ColumnSpan="3" on the most outer left line would also change the spacing correctly.
A new problem
This attempt does obviously fix the spacing but does introduce a new problem: the design of the user control with either of the two fixes has changed. Either both lines have to be dropped to the very bottom of the control or both lines have to be short.
And I really wish for the two lines to differ slightly. Furthermore, the two vertical lines at the center do not seem to affect the spacing negatively at all, even though they span the discussed rows as well.
Another solution?
I've simply went ahead and changed all lines to be canvases with a black background color. That does fix the issue and everything is presented correctly. But yet I am sitting here, not understanding why that problem has occurred in the first place. I wish to understand what may have caused the changed the calculation of percentages to improve my knowledge on designing UIs with XAML.
However, the controls preview seems to work now, but when "consumed" by another control (meaning I've added that control to another control) it seems like the entire spacing is all wrong again, just as it was when I've used lines.
A new culprit
Upon playing around I've noticed when removing the textbox the spacing would be correct again, even when consumed by another control. Still, my problem here is to understand how that could be an issue even though the percentages should all be the same, leaving no room for the horizontal lines to differ.
Naturally I wondered whether the negative margin could cause the error (that is there in order for the TextBlock to move closer to the line). But with or without margin, the error still consists.
A more general question
I know, general question on best approaches and practices are not very welcomed here, but please let me ask at least about resources on how to design well written Controls with XAML. All I've read the past weeks helped me a great lot, and yet I seem to stumble across many problems on a regularly basis.
I cannot tell you where I've read this on the Microsoft docs site, but it clearly stated that one should try to avoid the use of canvases. Maybe I've misunderstood, however, it does seem to me like using a canvas here seems to be a cheap trick to avoid a simple problem I've had with the lines.
Furthermore, if anyone has any idea on how to change the controls layout in order to achieve the desired output please let me know. Thank you in advance for even taking the time to read through this.
Resources
User-control with lines
Problem: Displaying the horizontal lines slightly off
<UserControl ...
mc:Ignorable="d" d:DesignHeight="50" d:DesignWidth="400"
MinHeight="50">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="54"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- left hand side grid-->
<Grid Grid.Column="0"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Line Grid.Column="0" Grid.ColumnSpan="1"
Grid.Row="1" Grid.RowSpan="3"
X1="0" X2="0"
Y1="0" Y2="1"
Stroke="Black"
StrokeThickness="1"
Stretch="Uniform"
SnapsToDevicePixels="True"/>
<Line Grid.Column="0" Grid.ColumnSpan="3"
Grid.Row="2" Grid.RowSpan="1"
X1="0" X2="1"
Y1="0" Y2="0"
Stroke="Black"
StrokeThickness="1"
Stretch="Uniform"
SnapsToDevicePixels="True"/>
<Line Grid.Column="2" Grid.ColumnSpan="1"
Grid.Row="0" Grid.RowSpan="5"
X1="0" X2="0"
Y1="0" Y2="1"
Stroke="Black"
StrokeThickness="1"
Stretch="Uniform"
SnapsToDevicePixels="True"/>
</Grid>
<!-- middle grid -->
<Grid Grid.Column="1"
Grid.Row="0">
<Canvas Margin="2, 0"
Background="Red"/>
</Grid>
<!-- right hand side grid-->
<Grid Grid.Column="2"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Line Grid.Column="0" Grid.ColumnSpan="1"
Grid.Row="0" Grid.RowSpan="5"
X1="0" X2="0"
Y1="0" Y2="1"
Stroke="Black"
StrokeThickness="1"
Stretch="Uniform"
SnapsToDevicePixels="True"/>
<Line Grid.Column="0" Grid.ColumnSpan="3"
Grid.Row="2" Grid.RowSpan="1"
X1="0" X2="1"
Y1="0" Y2="0"
Stroke="Black"
StrokeThickness="1"
Stretch="Uniform"
SnapsToDevicePixels="True"/>
<Line Grid.Column="2" Grid.ColumnSpan="1"
Grid.Row="1" Grid.RowSpan="4"
X1="0" X2="0"
Y1="0" Y2="1"
Stroke="Black"
StrokeThickness="1"
Stretch="Uniform"
SnapsToDevicePixels="True"/>
<TextBlock Grid.Column="1"
Grid.Row="3" Grid.RowSpan="2"
Text="Prefered Color"
FontSize="20"
FontFamily="Segoe UI Light"
Typography.Capitals="SmallCaps"
Foreground="Black"
HorizontalAlignment="Right"
Margin="4, -3, 4, 0"/>
</Grid>
</Grid>
</UserControl>
User-control as displayed in designer with horizontal lines being off
User-control with Canvases
Problem: Seems to work in the preview but will be miscalculated when added to another control
<UserControl ...
mc:Ignorable="d" d:DesignHeight="50" d:DesignWidth="400"
MinHeight="50">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="54"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- left hand side grid-->
<Grid Grid.Column="0"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Canvas Grid.Column="0" Grid.ColumnSpan="1"
Grid.Row="1" Grid.RowSpan="3"
Background="Black"
SnapsToDevicePixels="True"/>
<Canvas Grid.Column="0" Grid.ColumnSpan="3"
Grid.Row="2" Grid.RowSpan="1"
Background="Black"
SnapsToDevicePixels="True"/>
<Canvas Grid.Column="2" Grid.ColumnSpan="1"
Grid.Row="0" Grid.RowSpan="5"
Background="Black"
SnapsToDevicePixels="True"/>
</Grid>
<!-- middle grid -->
<Grid Grid.Column="1"
Grid.Row="0">
<Canvas Margin="2, 0"
Background="Red"/>
</Grid>
<!-- right hand side grid-->
<Grid Grid.Column="2"
Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Canvas Grid.Column="0" Grid.ColumnSpan="1"
Grid.Row="0" Grid.RowSpan="5"
Background="Black"
SnapsToDevicePixels="True"/>
<Canvas Grid.Column="0" Grid.ColumnSpan="3"
Grid.Row="2" Grid.RowSpan="1"
Background="Black"
SnapsToDevicePixels="True"/>
<Canvas Grid.Column="2" Grid.ColumnSpan="1"
Grid.Row="1" Grid.RowSpan="4"
Background="Black"
SnapsToDevicePixels="True"/>
<TextBlock Grid.Column="1"
Grid.Row="3" Grid.RowSpan="2"
Text="Prefered Color"
FontSize="20"
FontFamily="Segoe UI Light"
Typography.Capitals="SmallCaps"
Foreground="Black"
HorizontalAlignment="Right"
Margin="4, 0, 4, 0"/>
</Grid>
</Grid>
</UserControl>
User-control with canvases instead of lines being displayed correctly in designer
User-control displayed wrong after being added to another control
I will post this as an answer, since it fulfills the neccessary design needs, and mark it as an correct answer for the time beeing. However, this answer does not statisfy my question completly since it does not explain why the previous approach didnt work.
Therefore feel free to add answers and I will choose the answer wich explains the issue as the correct one.
<UserControl ...
mc:Ignorable="d" d:DesignHeight="50" d:DesignWidth="400"
MinHeight="50">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="3"
Grid.Row="0" Grid.RowSpan="5"
Margin="4,0"
Background="Red"
BorderThickness="0"
Command="{Binding ColorClick}">
</Button>
<TextBlock Grid.Column="5"
Grid.Row="4" Grid.RowSpan="2"
Text="Prefered Color"
FontSize="20"
FontFamily="Segoe UI Light"
Typography.Capitals="SmallCaps"
Foreground="Black"
HorizontalAlignment="Right"
Margin="4, 0, 4, 0"/>
<Canvas Grid.Column="0"
Grid.Row="1" Grid.RowSpan="3"
Background="Black"/>
<Canvas Grid.Column="1"
Grid.Row="2" Grid.RowSpan="1"
Background="Black"/>
<Canvas Grid.Column="2"
Grid.Row="0" Grid.RowSpan="5"
Background="Black"/>
<Canvas Grid.Column="4"
Grid.Row="0" Grid.RowSpan="5"
Background="Black"/>
<Canvas Grid.Column="5"
Grid.Row="2" Grid.RowSpan="1"
Background="Black"/>
<Canvas Grid.Column="6"
Grid.Row="1" Grid.RowSpan="5"
Background="Black"/>
</Grid>
</UserControl>

Layout problem with autogenerated DataGrid in WPF/XAML

I've got a problem with WPF/XAML. I can't figure out how to let the left Grid (with a centered image inside and backgroud color) grow its height, depending on the autogenerated height on the datagrid on the right.
They both are presented in a global grid. If I set a fixed height on the corresponding row, the autogenerated datagrid shows a cruel vertical line, depending on the fixed row-height I set before.
layout with row-height on auto
layout with fixed row-height, but with ugly line at the bottom
<!--ElementR0C1-->
<Grid Name="test">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!--Width ElementsC1-->
<ColumnDefinition Width="160"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="500"/>
</Grid.ColumnDefinitions>
<!--START-->
<Label Grid.Row="0" Grid.Column="0" Style="{StaticResource L1}" VerticalAlignment="Top">Process</Label>
<Grid Grid.Row="1" Grid.Column="0" Background="DDDDDD">
<Image Margin="0,30,0,0" Height="64" Width="64" Source="../../Resources/ok.png" Name="imgJobs" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<DataGrid x:Name="grdJobs" Grid.Row="0" Grid.Column="2" Grid.RowSpan="2" Width="500">
-- some stuff here
</DataGrid>
</Grid>

ViewBox and blurring effect issue?

I do not understand if it's a bug that I'm causing some with wrong setting or simply a problem of WPF.
I'm trying to see all content of a GroupBox and I'm using the Viewbox as some label without viewBox for a certain resolution are not visible.
Everything works fine, but it seems there is something wrong with the rendering.
As seen from the image:
by setting this in viewBox:
<Viewbox Stretch = "Fill" Grid.Column = "0" Grid.Row = "0" StretchDirection = "Both">
I can see all content but as you can see the labels are blurred and seem to spread so forced, I do not like.
In the other groupbox I tried to set this:
<Viewbox Stretch="Uniform" Grid.Column="1" Grid.Row="0" StretchDirection="Both">
and I get a nicer effect already at the level of rendering:
the problem is that they remain of the white bands on the right and left (if obviously imposed the minimum resolution reached by the software) and this for me is not nice because I do not use all the UI application.
For those wishing to take a quick look at the complete XAML:
<Viewbox Stretch="Uniform" Grid.Column="1" Grid.Row="0" StretchDirection="Both">
<GroupBox x:Name="Ospite_Analisi" Header="Ospite">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Column="0" Grid.Row="0">
<Label>Inserire scudetto</Label>
</Grid>
<Grid Grid.Column="1" Grid.Row="0">
<StackPanel Orientation="Vertical">
<Label>Nome Squadra</Label>
<Label>Nazione</Label>
<Label>Campionato</Label>
</StackPanel>
</Grid>
<Grid Grid.Column="2" Grid.Row="0" Grid.RowSpan="2">
<Label>Inserire controllo forma</Label>
</Grid>
<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal" HorizontalAlignment="Center">
<Label>Vittorie casa</Label>
<Label>Vittorie fuori</Label>
</StackPanel>
<Grid Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="3">
<DataGrid>
...
</DataGrid>
</Grid>
</Grid>
</GroupBox>
</Viewbox>
What I want to achieve is this:
-Fix Both GroupBox in maximum width (the minimum resolution) in viewBox without losing quality and without making it seem forced rendering. How can I achieve this?

WPF: avoid redrawing of groupbox to fit content

I'm using a page with a grid with 3 rows where every row contains a groupbox. The groupboxes also contain different grids with different content.
I would like to have all of my groupboxes to fit the same width. Initially that's the case. But when the content of the first group box is updated from code behind, the group box gets redrawn for a very short moment (width is smaller), but a second later it again fits to the width.
Initially it is: "not connected" which changes to "connected", so width is smaller.
The Width of my window is set to maximize, I don't want to set fix width and height for the page and the grids. Is there a way I can only update the content, without the box trying to fit to the content?
Example ( 2 rows):
<Grid Grid.IsSharedSizeScope="True" Name="globalGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="globalCol"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="RowA"/>
<RowDefinition SharedSizeGroup="RowA"/>
<RowDefinition SharedSizeGroup="RowA"/>
</Grid.RowDefinitions>
<GroupBox Header="Connection status"
Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Name="Connected"
Style="{StaticResource iconConnectStyle}"
DataContext="{Binding DeviceConnection}"
Grid.Row="0" Grid.Column="0" />
<TextBlock Text="device 1:"
Grid.Row="0" Grid.Column="1"
Style="{StaticResource statusText}"/>
<TextBlock Name="dev1" Grid.Row="0" Grid.Column="2"
Style="{StaticResource statusText}" />
</Grid>
</GroupBox>
<GroupBox Header="processing status"
Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Stretch">
<StackPanel>
<TextBlock x:Name="processState" Style="{StaticResource statusText}"/>
<ProgressBar x:Name="progressState"/>
</StackPanel>
</GroupBox>
</Grid>
I'm now using a UniformGrid, that solved the problem...

How to organize elements inside a Button

i'm new to wpf .
i got a wpf button ,
in it i need to place 2 elements a textblock and a viewbox encapsulating a canvas
the problem is i can't seem to see the canvas at all , unless i give it static values for its size
<Button Margin="10,30,10,10" Padding="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Me" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
<Viewbox Margin="0,0,0,5">
<Canvas Background="red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="1" >
<Ellipse HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Black" StrokeThickness="4" ></Ellipse>
</Canvas>
</Viewbox>
</Grid>
</Button>
iv'e also attempted this using a stack panel with an horizontal orintation
in any case the canvas does not show
any thoughts of what i'm doing wrong ?
thanks.
Attached Grid properties only work when at the Grid-child-level, i.e. the properties set on the canvas do not take effect they should be set on the container, the ViewBox which is a direct child of the Grid.
Viewboxes only work if the content has a concrete size, you probably need neither the ViewBox nor the Canvas. If you want the Ellipse to be a circle set Stretch="Uniform"
The contents of Buttons do not stretch by default you should set HorizontalContentAligment and its vertical counterpart to Stretch.
e.g.
<Button Margin="10,30,10,10" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Me" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
<Ellipse Stretch="Uniform" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Stroke="Black" StrokeThickness="4"></Ellipse>
</Grid>
</Button>

Resources