How to have 2 child Button, each one with different VerticalAlignment? - wpf

I have a grid with the top and bottom row having each one kind of the same button (style and so on) with their size growing when I mouse over them.
Except I want my top button to grow from bottom to top, so without altering the rest of the grid position, and respectively, my bottom button to grow from top to bottom.
I tried to change VerticalAlignment="Bottom" for top button, and respectively, VerticalAlignment="Top" for bottom button, but that doesn't change a thing.
After reading this I figured I had to change the parent vertical alignment, so my grid.
But it affect both button at once, and I what distinct behavior for each one !
See this example
EDIT :
So I try first solution of Chris Mack and embedding my first button inside a new dedicated Grid just for formatting the visual I look for (Meh don't like that much, but may be it is the way to go XAML).
So here it is now :
<Grid Grid.Row="1" Background="Yellow">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--this is new : =>-->
<Grid Grid.Column="2" Background="Green" Margin="5,10,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<!--<= : this was new-->
<!--VerticalAlignment="Bottom" is new inside the Button properties-->
<Button Grid.Column="0" Grid.Row="0" Style="{StaticResource ResourceKey=TransparentImgButtonStyle}" VerticalAlignment="Bottom" MinHeight="60" Background="PaleGoldenrod" BorderBrush="Transparent" BorderThickness="1" Name="UpdateBtn" Click="UpdateBtn_Click">
<local:NineSliceImage x:Name="Update9SliceImg" ImgSource="/Assets/UpdateGreenBIG.png" Slice="225,300,225,225" AreasSize="0.02,0,0.02,10"/>
</Button>
</Grid>
So for now (have to test more to be sure) I get what I want, as my 2nd bottom button was already reacting as I wanted, only had to add those extra formatting visual behaviour on my first Button.
But here is my new question :
I don't understand why I had to set VerticalAlignment="Bottom" on my "root" grid to change my childs positioning (and all of them the same, see my original issue) whereas here in my new sub-grid (created only for formatting first button on bottom of it's own sub-grid), setting VerticalAlignment="Bottom" had no effect this time and I had to set VerticalAlignment="Bottom" on the Button itself !
As total opposition of previous remark !!?
EDIT 2 :
Finally I ended up using last suggestion of Chris Mack, simply :
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80"/><!--Top row-->
<RowDefinition Height="252"/><!--Update & save. New : FIXED HEIGHT VALUE-->
<RowDefinition Height="*"/><!--ListBox-->
</Grid.RowDefinitions>
<Grid>
<!--first row, useless in for our case here-->
</Grid>
<Grid Grid.Row="1" Background="Transparent">
<Grid.RowDefinitions>
<!-- 0) UPDATE Button. New : FIXED HEIGHT VALUE-->
<RowDefinition Height="90"/>
<!-- 1) Icon & Name-->
<RowDefinition Height="auto"/>
<!-- 2) Icon & Name-->
<RowDefinition Height="auto"/>
<!-- 3) Save Button-->
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!-- 0) Icon Button-->
<ColumnDefinition Width="auto"/>
<!-- 1) Name TextBox-->
<ColumnDefinition Width="250"/>
<!-- 2) TextBox-->
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--Top button, note I added VerticalAlignment="Bottom"-->
<Button Grid.Row="0" Grid.Column="2" Margin="5,0,10,10" Style="{StaticResource ResourceKey=TransparentImgButtonStyle}" VerticalAlignment="Bottom" MinHeight="60" Background="Transparent" BorderBrush="Transparent" BorderThickness="1" Name="UpdateBtn" Click="UpdateBtn_Click" ToolTip="Update">
</Button>
<!--Other useless stuff-->
<Button Style="{StaticResource ResourceKey=TransparentImgButtonStyle}" Margin="10,10,10,10" MinHeight="60" Grid.Row="3" Grid.ColumnSpan="3" Background="Transparent" BorderBrush="Transparent" BorderThickness="1" Name="SaveBtn" Click="SaveBtn_Click" ToolTip="Save">
</Button>
</Grid>
</Grid>

Grid control rows will automatically size depending on their content (at least when coded as you have coded them). VerticalAlignment won't change anything, because the row is changing size with the Button when the mouse hovers over it, so alignment is irrelevant.
To accomplish the effect you are looking for, place each Button inside of its own Grid (within the appropriate row), and size those Grids to accommodate the Buttons' different states.
I guess another thing you could do would be to have a Margin on the Button while the mouse is not hovered over it, and then to remove the Margin (via a Trigger) when the size changes, so the expanded Button takes up the space once taken up by the Margin, resulting in the same row height.
Another thing you could do would just be to have fixed sizes for your Grid rows and Button, in which case the alignments would be effective.

Related

Grid with RowDefinitions based on content

I am trying to get something like an image with adjustable margins done. The image itself is actually a path and resides in a StackPanel, stretching vertically. The StackPanel's width can be adjusted, and I want to keep the image's ratio and the ratio of path size to margin.
<StackPanel>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefintions>
<Path Grid.Row="1"
Grid.Column="1"
Data="...blabla..."
Fill="#FF0072C6"
Stretch="UniformToFill"/>
</Grid>
</StackPanel>
Now, the problem is, even though the path object gets drawn in the grid, the first and third rows are always of zero height, instead of getting set based on the height of the 2nd row. I know this happens because the Grid resides in a StackPanel, which ignores automatic height settings and doesn't even let the Grid stretch vertically (or horizontally depending on orientation). It does work if I set a fixed height to the grid but that would ruin the aspect ratio of the image when resizing. How can I get this to work?
This is what I have:
This is what I want:
EDIT:
It seems there is confusion concerning my question. So to hopefully clarify, here's the desired result after resizing the StackPanel:
As you can see, the whole grid is supposed to resize like it was an actual image. The Grid should keep its aspect ratio. This is not about the Path inside the Grid.
If i have correctly understood the problem, a simple solution could be fixing sizes and using a viewbox:
<StackPanel>
<!--The other rows-->
<Viewbox>
<Grid Width="100" Height="100">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="50"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="25"/>
</Grid.ColumnDefinitions>
<Path Grid.Row="1" Grid.Column="1" Data="M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z" Fill="Blue" Stretch="Uniform" />
</Grid>
</Viewbox>
</StackPanel>

How to make TextBox fill all available space without later resizing to its content?

I have the following Grid with a TextBox in it:
<UserControl ...>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30px"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1px"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="1" Grid.RowSpan="3" AcceptsReturn="True"
TextWrapping="Wrap" HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Visible" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<!-- content in other cells of the Grid's first column -->
</Grid>
</UserControl>
I want the TextBox to fill all space that is available on the control (width and height-wise) and should the user enter more text than fits into it I want its vertical scrollbar to become active, without resizing the TextBox. What happens instead is that the size of the TextBox changes to accomodate the content and the whole grid grows with it.
How do I achieve what I need?
Edit: Here's an illustration of what happens.
The above screenshot is of the situation when the content fits comfortably into the TextBox. The below screenshot is of the situation when there is not enough room to fit all content - the TextBox is then resized to fit it and this resizes also the grid that it is placed in, making it look broken.
Edit 2: The project that demonstrates this behavior is here.
I have managed to solve this by adding an invisible Border in the same cells of the Grid as the TextBox, then setting TextBox' Width and Height to ActualWidth and ActualHeight of that Border respectively:
<Border x:Name="b" Grid.Column="1" Grid.RowSpan="3"
HorizontalAlignment="Stretch"/>
<TextBox AcceptsReturn="True" TextWrapping="Wrap" Grid.Column="1"
Grid.RowSpan="3" Width="{Binding ActualWidth, ElementName=b}"
Height="{Binding ActualHeight, ElementName=b}"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Visible" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
This then caused the TextBox to stay of fixed Height regardless of its content, but there was another problem with its Width: it grew when the interface was expanded, but didn't shrink afterwards, because of the underlying ScrollViewer. The trick was to set that ScrollViewer's HorizontalScrollBarVisibility to Disabled, instead of Hidden as I had done previously.
I pushed changes of the example project to GitHub, so the solution is now available here.
The TextBox doesn't fill the Grid. You can confirm this yourself by specifying a Background for the Grid:
<UserControl>
<Grid Background="Yellow">
...
This is because the height of the Grid is 30 px + whatever the height of the TextBox is + 1 px. For the contents of the row 2 or 3 to fill the Grid, you need to change the Height of at least one of the RowDefinitions to *:
<UserControl>
<Grid Background="Yellow">
<Grid.RowDefinitions>
<RowDefinition Height="30px"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="1px"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="1" Grid.RowSpan="3" AcceptsReturn="True"
TextWrapping="Wrap" HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Visible" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
</UserControl>

preventing WPF Grid from infinit growth

My question is similar to:
Prevent WPF control from expanding beyond viewable area
with the difference that the accepted solution (specific to the issue with StackPanel) does not really help me much.
I have a Window that currently only contains the following Grid:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="265"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="147*"/>
<RowDefinition Height="173*"/>
</Grid.RowDefinitions>
<Button Content="Button" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Click="Button_Click" Grid.Row="1" Grid.Column="1"/>
<local:BatteryGraphicsView x:Name="batView" HorizontalAlignment="Stretch" ClipToBounds="True" Width="265"/>
</Grid>
I want now that if my GraphicsView extends over the width of its column, that the scrollbars are displayed and the control does not paint it self beyond the bounds of the column.
This happens as soon as I press the button.
The user control basically is a grid that contains WinFormsHosts, when pressing the button there are more columns created for the grid and so the grid grows
(Usercontrol grid xaml)
<ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto" ClipToBounds="True">
<Grid x:Name="Maingrid" ClipToBounds="True">
<Grid.RowDefinitions>
<RowDefinition Height="40*"/>
<RowDefinition Height="20*"/>
<RowDefinition Height="40*"/>
</Grid.RowDefinitions>
<WindowsFormsHost x:Name="host1" />
<WindowsFormsHost x:Name="host2" Grid.Row="2"/>
</Grid>
</ScrollViewer>
While the Scollviewer realises that it needs to display it self, the mainGrid anyway is displayed beyond the bounds of the column.
In multiple related posts I saw that you need to set the "ClipToBounds" property to true, but I set the property for every control and there is still no reaction.
The problem is that your ScrollViewer inside your UserControl doesn't know what the GridColumn & and GridRow sizes are.
There are two things you can do.
1: Specify a MAX Width for your Column & Max Height for you Row
2: Instead of adding your scrollViewer in the UserControl, add it in your grid and give it a height and width.

Resize window parts in runtime

I want to have main window split in three parts like the one on the picture. there's supposed to be a line (red one) or left border of the rectangle number 2, that, when it's dragged with mouse, it resizes both rectangle 1 and 2. it's like the behaviour of playlist in windows media player. any ideas on how to obtain this? Also, it would be great if someone proposes a solution to how this playlist make collapsed if the red line is dragged to the right.
Define a <Grid> with columns and rows like so:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="300"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="600"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="300"/>
</Grid.ColumnDefinitions>
...
and then the gridsplitter (still inside the grid):
<GridSplitter Grid.Row="0" Grid.Column="1" ResizeDirection="Columns" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
Note that the gridsplitter will need it's own column.
It is a GridSplitter, here is how to use one:
<GridSplitter Grid.Row="1"
Height="5"
Width="Auto"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Gray"
ResizeDirection="Rows" />
You need to assign a Row or Column to it from your Grid, and specify its ResizeDirection. This one is horizontal, but you get the idea for a vertical one.
HTH,
Bab.

Help with my WPF Layout

I have a WPF Line of business application. Most of it is hosted in user controls in tabs.
I'm having an issue finding out how to layout this so it would fit any resolution (with scrolling if necessary).
Here's the issue described in code because i really can't figure out how to put this to text, if it's not clear please let me know i'll try to draw something up.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition> <!--What i actually want to say here isn't "take all remaining space" but "take all remaining space without scrolling,
and then scroll based on everything as if this was auto and no longer *-->
<ColumnDefinition Width="Auto"></ColumnDefinition><!--But what happens for now is that since this is auto , it will not scroll at all untill the * column has fully scrolled-->
</Grid.ColumnDefinitions>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label></Label>
<TextBox></TextBox>
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="1">
<StackPanel Orientation="Horizontal">
<button> <!-- I want the button's container to be in an auto column , don't
want it to take size away from the fields unless needed but don't
want it to stay visible at the expense of the fields either -->
</StackPanel>
</StackPanel>
<TelerikGrid:RadGridView Grid.Row="1" Grid.ColumnSpan="2">
<TelerikGrid:RadGridView.Columns>
<TelerikGrid:GridViewDataColumn Width="*"/> <!-- This makes my grid take a bajillon kilometers because it itself is in a Grid's column of * size itself in a scrollviewer -->
</TelerikGrid:RadGridView.Columns>
</TelerikGrid:RadGridView>
</Grid>
Hard to tell given I cannot load your GridView control in a Window.
I recommend nesting a layout manager Grid for your controls inside your Grid to create a separation between your controls and the GridView. You also should consider combining all the controls in one StackPanel or other layout manager.
Regardless, this layout gives you separation between the controls and the GridView regardless of your choice of layout manager with no need to specify a column span.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Place a layout Grid inside your Grid to deal with controls -->
<Grid Grid.Column="0" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Removed your nested stack panel -->
<StackPanel Grid.Column="0" Grid.Row="0" Orientation="Horizontal">
<Label></Label>
<TextBox></TextBox>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal">
<Button />
</StackPanel>
</Grid>
<!-- Add a spilter bar here -->
<!-- No need to span 2 columns anymore... -->
<TelerikGrid:RadGridView Grid.Column="0" Grid.Row="1" >
<TelerikGrid:RadGridView.Columns>
<TelerikGrid:GridViewDataColumn Width="*"/>
</TelerikGrid:RadGridView.Columns>
</TelerikGrid:RadGridView>
<!-- Add a status bar here -->
</Grid>

Resources