The code below does a row-column demonstration of 3 rows where the last row had 3 columns. in each, the second element is a grid splitter.
if splitter's alignment is set to "center", it works as expected to resize others. but if it is set to left/right for horizontal (or top/bottom for vertical) it just shrinks other two while extending its cell (no less than its size)
Can someone explain why does the GridSplitter behave like this? the code is simple WPF code and can be copy-pasted to C# or VB WPF application's main xaml.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="25"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Background="Lime">
<Label Content="Label" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</DockPanel>
<GridSplitter Grid.Row="1" Height="5" Background="#FF7F7F7F" VerticalAlignment="Center" HorizontalAlignment="Stretch" ResizeDirection="Rows"/>
<DockPanel Grid.Row="2">
<Grid DockPanel.Dock="Top" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Background="Red">
<Label Content="Label" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DockPanel>
<GridSplitter Grid.Column="1" Width="5" Background="#FF7F7F7F" VerticalAlignment="Stretch" HorizontalAlignment="Center" ResizeDirection="Columns"/>
<DockPanel Grid.Column="2" Background="Blue">
<Label Content="Label" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</DockPanel>
</Grid>
</DockPanel>
</Grid>
GridSplitter has a property called ResizeBehavior which defines the action the question described. If not set manually the default behavior is BasedOnAlignment, meaning it is based on the HorizontalAlignment and VerticalAlignment values you are setting.
If they are set as in the code, ResizeBehavior is defaulted to PreviousAndNext. This will cause it to redistribute space on either side of the GridSplitter.
GridSplitter parts in the code are equivalent to these manual settings of ResizeBehavior.
...
<GridSplitter ResizeBehavior="PreviousAndNext" Grid.Row="1" Height="5" Background="#FF7F7F7F" VerticalAlignment="Top" HorizontalAlignment="Stretch" ResizeDirection="Rows"/>
...
<GridSplitter ResizeBehavior="PreviousAndNext" Grid.Column="1" Width="5" Background="#FF7F7F7F" VerticalAlignment="Stretch" HorizontalAlignment="Left" ResizeDirection="Columns"/>
...
Update with more explanation about default ResizeBehavior of BasedOnAlignment:
At the end of this answer below is a link to an image of a table excerpted from the book WPF 4.5 Unleashed By Adam Nathan (I do not yet have enough reputation to place this image directly here and so am only allowed to create it as a link).
The table shows what the GridSplitter will look like (shown as the colored rectangles/squares) depending upon the HorizontalAlignment and VerticalAlignment settings it is given. If neither of those settings have a stretch, then the GridSplitter will end up as a small dot and so it is only the cases where one of the alignments is set to stretch that we are interested in (as you did in your code).
When the rows or columns are proportionally sized (as is in your case with using asterisks), then dragging the GridSplitter changes the coefficients for the two cells indicated in the table accordingly.
As you can see when the one alignment is set to stretch and the other to center, the two cells affected are the ones that are on either side of the GridSplitter. Thus you see the behavior you first report of those cells on either side being sized equally.
But when set to the Left/Right or Top/Bottom values (depending upon if you are working with vertical or horizontal GridSplitters) then, as you can see from the table, the GridSplitter itself becomes one of the two affected cells. So if, for example, it is a vertical GridSplitter and you set the HorizontalAlignment to Left, you will only be able to move the GridSplitter from where it starts in the center towards the left and that will size that left cell smaller and make the GridSplitter itself larger (and in the process take away space from the right cell). You cannot, however, move the GridSplitter to the right and make the right cell smaller.
Table: Cells Directly Affected When Dragging a GridSplitter with Various Alignment Settings
Related
I have an Expander control, and the grid inside will have a ListBox with a Label on top of it saying 'Video Sources'. I am attempting to use Grid Row Definitions to achieve this. My issue however is that the grid rows separate everything evenly. I want the label to be directly on top of the ListBox. Removing the definitons causes the ListBox to fill up the entire grid including covering up the Label (which makes no sense to me as the label is on top).
My current code is below:
<Expander HorizontalAlignment="Left" Height="434" Header="Expander" ExpandDirection="Left" Margin="651,8,0,8">
<Grid Background="#FF252525" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Label Content="Video Sources" Grid.Row="0"/>
<ListBox Grid.Row="1" d:ItemsSource="{d:SampleData}">
</ListBox>
</Grid>
</Expander>
The code produces this result. You can see there are even gaps between each control. I want the video sources label right above the listbox:
It would be nice if you could set the column name like in a ListView, however as far as I am aware that is not possible. I don't think it's worth using a ListView for something that will only have a single column, either
You have to set the rows height ; to auto (ie: minimal value) and * (ie: remaining space).
Also only two rows definition are needed.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="Video Sources" />
<ListBox Grid.Row="1"
ItemsSource="{d:SampleData}"
VerticalAlignement="Top" />
</Grid>
I want to create a button that will display some text together with a status icon inside. The text should be centered and the status icon should go right next to the text. Something like this:
I didn't find a way how to center only the text and then positioning the icon after the centered text. Right now I am using a Grid solution which centers the text and aligns the icon to the right.
<Button VerticalContentAligment="Stretch" HorizontalContentAligment="Stretch">
<Grid>
<TextBlock VerticalAligment="Center" HorizontalAligment="Center"/>
<Image VerticalAligment="Center" HorizontalAligment="Right"/>
</Grid>
</Button>
It's not what I want but it's working for the button's size I have at the moment.
I know that this can be accomplished using some binding magic but it seems too simple for this. It will be great if you can point me to a solution without binding magic but I will grateful even for one with it.
A Grid with 3 columns should work. When the left and right columns have equal width, the middle one is automatically centered.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" VerticalAlignment="Center"/>
<Image Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Grid>
I have the following piece of XAML code in my WPF application,
<StackPanel DockPanel.Dock="Top" >
<TextBlock Style="{StaticResource HeaderTextBlock}">Import Log</TextBlock>
<ScrollViewer Height="400" VerticalScrollBarVisibility="Auto">
<TextBlock Name="ImportFeedBack"></TextBlock>
</ScrollViewer>
</StackPanel>
which dispalys the ImportFeedBack string (in case someone is wondering, I'm using Caliburn.Micro as MVVM framework, so that the content of the TextBlock is bound by naming convention to a property of same name in my ViewModel).
The value can vary heavily in length. I want it to use the whole available space (but it should not resize the application!), and only if that is not enough, add a vertical scroll bar.
If I delete the Height="400" in the ScrollViewer, it resizes the app for big strings, and if I leave it there, it (obviously) just uses 400 height, but ads he scroll bar when needed.
How can I get it to use all the available space, and only if that is not enough, to creata a vertical scroll bar?
Instead of StackPanel use different panel like Grid or DockPanel. In the example below second row will take all available space not allocated by first row and not expand beyond that which is when scroll bar should appear when text is longer.
<Grid DockPanel.Dock="Top" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Style="{StaticResource HeaderTextBlock}">Import Log</TextBlock>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<TextBlock Name="ImportFeedBack"></TextBlock>
</ScrollViewer>
</Grid>
I have a page like this:
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
here are contents
they are forever absolutely in the center of the screen
no matter of the resolution/size
</StackPanel>
</Grid>
Everything is working fine. But now I want to add a back button in the top-left corner.
And I don't want to split the grid into 2 columns and 2 rows like this:
the contents are no longer absolutely centered, even we can split the grid by percent, because the contents are sometimes very wide and sometimes very narrow.
I want to know how can I keep the contents horizontal/vertical aligned "Center", and then set the back button's position relatively to the content.
I would suggest using a grid layout with 3 columns to ensure the content is centered with the columns widths set to *,Auto, *. This will ensure the main content is always centered and not care about the size of the button. You can then use margins to set the seperation as required. This is a techinique I have used in SL, WPF & Metro.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button HorizontalAlignment="Right" VerticalAlignment="Top" Content="Do Something"/>
<ContentControl VerticalAlignment="Top" Content="My custom content"/>
</Grid>
slightly hacky ansewer
You might be able to achieve by positioning your stackpanel in the center, and then set a negative left margin the width of the button to shift everything left by the required amount...
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="-45,0,0,0">
<button with width and padding totalling 45px />
here are contents
they are forever absolutely in the center of the screen
no matter of the resolution/size
</StackPanel>
</Grid>
I want to divide my window (wpf) in three columns: left column must be DockPanel ( I think StackPanel will not work on Canvas), the right column should be another DockPanel holding a listbox and in the middle I need to have a Canvas.
This is what I have done and I am having problem with left column since it is not expandable. I need the left column as holder of custom object so that user could drag/drop them on canvas. Please advise.
<DockPanel LastChildFill="True" Background="LightGray" Margin="5">
<Expander Header="Controls" Background="Gray" Margin="2"
Content="{StaticResource FC}" DockPanel.Dock="Top"
IsExpanded="True" Width="200" />
</DockPanel>
<GridSplitter Focusable="False" Width="2" Background="LightGray"
VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<lib:MyCanvas x:Name="myCanvas" FlowDirection="LeftToRight"
Background="White" AllowDrop="True"
Mouse.MouseMove="MyCanvas _MouseMove">
</lib:MyCanvas >
Also, what control should be used on the right side so that can hold a listbox?
Looking at various question you have asked, it looks like you are looking at building an application similar to Visual studio. I would suggest you to look at following great series of articles on CodeProject similar to your requirement i.e. having ToolBox, various ToolBox items , a designer, drag & drop items on designer etc. -
WPF Diagram Designer - Part 4, Part 3, Part 2, Part 1
You will just have to add a PropertyGrid on the right side and bind your selected ToolBox item in designer with it.
You can embed another grid, or canvas, or other kind of container inside of a grid, you don't have to. But you have a GridSplitter so by definition it needs to be placed inside of a Grid in order to provide its functionality, otherwise it doesn't do anything.
It sounds like you want to do something like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDeifnition Width="*" />
<ColumnDefinition Width="100" /> <!-- whatever size you need here --->
</Grid.ColumnDefinitions>
<DockPanel LastChildFill="True" Background="LightGray" Margin="5" Grid.Column="0">
<Expander Header="Controls" Background="Gray" Margin="2"
Content="{StaticResource FC}" DockPanel.Dock="Top"
IsExpanded="True" Width="200" />
</DockPanel>
<GridSplitter Focusable="False" Width="2" Background="LightGray" Grid.Column="1"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ResizeDirection="Columns"/>
<lib:MyCanvas x:Name="myCanvas" FlowDirection="LeftToRight" Grid.Column="2"
Background="White" AllowDrop="True"
Mouse.MouseMove="MyCanvas _MouseMove">
</lib:MyCanvas >
<ListBox Grid.Column="3" ... />
</Grid>
This layout gives you your 3 columns, the 2nd column is your splitter that lets you resize the first 2 columns (sliding back and forth between them), and your 3rd column is a fixed size.
Create a Grid with 3 columns. For the 1st and 3rd put a DockPanel as child.
I think the general rule is don't put others under canvas, not the other way round.