How do I customize the WPF StatusBar layout? - wpf

Adding more than one child to a WPF StatusBar results in poor layout with little option to customize. For example, this code:
<Window x:Class="StatusBar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem>
<TextBlock>Ready</TextBlock>
</StatusBarItem>
<StatusBarItem>
<TextBlock>Set</TextBlock>
</StatusBarItem>
</StatusBar>
<Label>Main Content</Label>
</DockPanel>
</Window>
Results in:
This is not the ideal layout, since the "Set" is squeezed right up against the "Ready".
How do I gain full control over the layout of the WPF StatusBar control?

By default, the StatusBar uses a DockPanel to position its children. This works fine for one item, but tends to make things messy and inconvenient when working with more than one child.
To gain a high level of control over the positioning of status bar children, you can swap out the DockPanel for a Grid:
<Window x:Class="StatusBar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<StatusBar DockPanel.Dock="Bottom">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem>
<TextBlock>Ready</TextBlock>
</StatusBarItem>
<StatusBarItem Grid.Column="1">
<ProgressBar Value="30" Width="80" Height="18"/>
</StatusBarItem>
<StatusBarItem Grid.Column="2">
<TextBlock>Set</TextBlock>
</StatusBarItem>
<StatusBarItem Grid.Column="3">
<TextBlock>Go!</TextBlock>
</StatusBarItem>
</StatusBar>
<Label>Main Content</Label>
</DockPanel>
</Window>
This results in:
For a more in-depth discussion, please visit my blog post here.

Actually, following Kent's reply I tried this and it works fine:
<StatusBar>
<StatusBarItem DockPanel.Dock="Right">
<TextBlock>Go!</TextBlock>
</StatusBarItem>
<StatusBarItem DockPanel.Dock="Right">
<TextBlock>Set</TextBlock>
</StatusBarItem>
<StatusBarItem DockPanel.Dock="Right">
<ProgressBar Value="30" Width="80" Height="18"/>
</StatusBarItem>
<!-- Fill last child is true by default -->
<StatusBarItem>
<TextBlock>Ready</TextBlock>
</StatusBarItem>
</StatusBar>

Just for the sake of reference for those reading the excellent answers above I'd like to suggest something even more simpler that achieves the same results. (Using neither DockPanel nor StatusBar).
<Window>
.
.
<Grid Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>
<SomeContainer Grid.Row="0" /> <!-- Main Content.. -->
<Grid Grid.Row="1">
<!-- Status bar laid out here (using similar approach)-->
</Grid>
</Window>
Disclaimer : This was long ago at a time when I was starting out with WPF.

You can use a container like StackPanel to move a group of status bar items to the right
<StatusBarItem>
<Button Content="Left Aligned Button"/>
</StatusBarItem>
<StatusBarItem HorizontalAlignment="Right">
<StackPanel Orientation="Horizontal">
<StatusBarItem>
<Button Content="Right Aligned Button 1"/>
</StatusBarItem>
<StatusBarItem >
<Button Content="Right Aligned Button 2"/>
</StatusBarItem>
</StackPanel>
</StatusBarItem>

Related

Avoid WPF statusbar gets totally collapsed when window gets resized vertically to a smaller size

I have below WPF window which contains a dockpanel as main container. Then I place a main grid at the top (which contains some other grids) and a statusbar at the bottom.
<Window>
<DockPanel>
<Grid DockPanel.Dock="Top">
<!-- Grid stuff here -->
</Grid>
<StatusBar DockPanel.Dock="Bottom"
VerticalAlignment="Bottom">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Text="Item1"/>
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock />
</StatusBarItem>
<Separator Grid.Column="3" />
<StatusBarItem Grid.Column="4">
<TextBlock Text="AnotherItem" />
</StatusBarItem>
</DockPanel>
</Window>
I have below problem:
When window is resized vertically to a smaller size, there comes a moment in which statusbar height is reduced and even completely collapsed. So how to avoid this? I want statusbar never gets collapsed and keep all the time its height.
Grids within Grids are so hot right now.
<Window x:Class="GridRoot.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Border BorderBrush="Black" BorderThickness="10" Background="CornflowerBlue">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
Hello!
</TextBlock>
</Border>
</Grid>
<StatusBar Grid.Row="1">
<StatusBarItem>
<TextBlock>
GET OFF ME!
</TextBlock>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
The top row takes up as much space is available, and the bottom row takes up as much space as its content desires. Since the StatusBar control pretty much has a set height, it will always stay visible on the bottom.
Some folks might have issue with putting a Grid inside another Grid, but there's absolutely no reason not to.
The above example, tiny
and embiggened

Displaying a large image in a ScrollViewer in another ScrollViewer

Following on from my previous question here I am now trying to display an Image in a ScrollViewer that is positioned inside another ScrollViewer.
The image is again a large one 2000x2000 pixels.
The main UI is a DockPanel which has a title TextBlock in the Top panel. The filled panel is a ScrollViewer which I refer to as the outside ScrollViewer.
Inside the outside ScrollViewer, I have a Grid named MainContentGrid which has 2 columns - both need to be 50% available width. In column 1 we have some TextBlocks. In column 2 I am trying to display the large image that will exceed the ActualWidth of column 2. This is wrapped in a ScrollViewer which I refer to as the internal ScrollViewer.
When I run the following code, the outside ScrollViewer has the active scroll bars which scrolls the entire MainContentGrid which is not what I want. I am trying to get the internal ScrollViewer have the scrollbars active for the Image.
So what I see initially is:
Then when I scroll down and right, I can see the Crimson Button (with the Browse button) Stack Panel inside the scroll region:
Here is the code:
<Window x:Class="WpfIssues.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:WpfIssues"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DockPanel Background="CadetBlue">
<TextBlock Text="Test Image" FontSize="30" DockPanel.Dock="Top"></TextBlock>
<!-- this is the outside scroller -->
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid x:Name="MainContentGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- this is a left hand panel which may have content bigger than than the
window which i will want to scroll the entire content (including the right hand panel which
hosts the other scroll viewer)
-->
<Grid Grid.Row="0" Grid.Column="0">
<StackPanel Orientation="Vertical">
<TextBlock>Hello there</TextBlock>
<TextBlock>mary doll</TextBlock>
</StackPanel>
</Grid>
<!-- This is the right hand side photo panel -->
<DockPanel x:Name="PhotoPanel" Grid.Row="0" Grid.Column="1">
<Grid DockPanel.Dock="Bottom" Background="Crimson">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Click="Button_Click">Browse...</Button>
</StackPanel>
</Grid>
<!-- This is the internal scroll panel. this should just scroll make image scroll
-->
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Background="Transparent">
<Image x:Name="PhotoImage"
Stretch="Uniform"
Source="Resources/bear grills.png"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</ScrollViewer>
</DockPanel>
</Grid>
</ScrollViewer>
</DockPanel>
</Grid>
</Window>
UPDATE
If I add a Height and Width to the internal ScrollViewer then I get the scrollbars around the image.
Is it possible to make the internal ScrollViewer "fit" to the DockPanel named PhotoPanel?
So if I'm understanding you right in visualizing what you want your actual output to be like. We can ditch your extra ScrollViewer, and your DockPanel, and just keep it as simple as it can get like this. Just del everything you got in there and replace it with this snip and see if it's more in line of what you're shooting for;
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Because we want some accent colors -->
<Rectangle Grid.ColumnSpan="2" Fill="CadetBlue"/>
<Rectangle Grid.RowSpan="2" Fill="CadetBlue"/>
<Rectangle Grid.Row="2" Grid.ColumnSpan="2" Fill="Crimson"/>
<TextBlock Grid.ColumnSpan="2" Text="Test Image" FontSize="30" />
<StackPanel Grid.Row="1">
<TextBlock>Hello there</TextBlock>
<TextBlock>mary doll</TextBlock>
</StackPanel>
<ScrollViewer Grid.Row="1" Grid.Column="1"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"
Background="Transparent">
<Image x:Name="PhotoImage"
Stretch="Uniform"
Source="Resources/bear grills.png"/>
</ScrollViewer>
<StackPanel Grid.Row="2" Grid.Column="1"
Orientation="Horizontal" HorizontalAlignment="Right">
<Button Click="Button_Click">Browse...</Button>
</StackPanel>
</Grid>
I only took a minute before I leave the office for the day so hopefully I didn't forget anything but I'm a big fan of the "K.I.S.S." ideology, and I'm not such a fan for dirty D.O.M.'s and unnecessarily heavy templates used like DockPanel, so hopefully it still aligns with what you're trying to accomplish. If not, I'm on here pretty much every workday anyway for fun. Hope it helps, cheers.
This will work providing a scrollable view if the left hand column is bigger. I don't think its 100% correct and could be improved:
<Window x:Class="WpfIssues.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:WpfIssues"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DockPanel Background="CadetBlue" LastChildFill="True">
<TextBlock Text="Test Image" FontSize="30" DockPanel.Dock="Top"></TextBlock>
<!-- this is the outside scroller -->
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid x:Name="MainContentGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- this is a left hand panel which may have content bigger than than the
window which i will want to scroll the entire content (including the right hand panel which
hosts the other scroll viewer)
-->
<Grid Grid.Column="0">
<StackPanel Orientation="Vertical">
<TextBlock>Hello there</TextBlock>
<TextBlock>Line 1</TextBlock>
<TextBlock>Line 2</TextBlock>
<TextBlock>Line 3</TextBlock>
<TextBlock>Line 4</TextBlock>
<TextBlock>Line 5</TextBlock>
<TextBlock>Line 6</TextBlock>
<TextBlock>Line 7</TextBlock>
<TextBlock>Line 8</TextBlock>
<TextBlock>Line 9</TextBlock>
<TextBlock>Line 10</TextBlock>
<TextBlock>Line 11</TextBlock>
<TextBlock>Line 12</TextBlock>
<TextBlock>Line 13</TextBlock>
<TextBlock>Line 14</TextBlock>
<TextBlock>Line 15</TextBlock>
<TextBlock>Line 16</TextBlock>
<TextBlock>Line 17</TextBlock>
<TextBlock>Line 18</TextBlock>
<TextBlock>Line 19</TextBlock>
<TextBlock>Line 20</TextBlock>
<TextBlock>Line 21</TextBlock>
<TextBlock>Line 22</TextBlock>
<TextBlock>Line 23</TextBlock>
<TextBlock>Line 24</TextBlock>
<TextBlock>Line 25</TextBlock>
<TextBlock>Line 26</TextBlock>
<TextBlock>Line 27</TextBlock>
<TextBlock>Line 28</TextBlock>
<TextBlock>Line 29</TextBlock>
</StackPanel>
</Grid>
<!-- This is the right hand side photo panel -->
<Grid x:Name="PhotoPanel" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- This is the internal scroll panel. this should just scroll make image scroll
-->
<Grid Grid.Row="0" x:Name="ImageGrid">
<ScrollViewer
Width="{Binding ActualWidth, ElementName=ImageGrid, Mode=OneWay}"
Height="{Binding ActualHeight, ElementName=ImageGrid, Mode=OneWay}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<Image x:Name="PhotoImage"
Source="Resources/bear grills.png"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</ScrollViewer>
</Grid>
<Grid Background="Crimson" Grid.Row="1">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Click="Button_Click">Browse...</Button>
</StackPanel>
</Grid>
</Grid>
</Grid>
</ScrollViewer>
</DockPanel>
</Grid>
</Window>

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>

Why does my GridSplitter not work at all?

I'm migrating a WinForms app to WPF. Everything has gone well so far except in relation to my attempts to use GridSplitter which I can never seam to make resize anything at run-time.
To make sure it wasn't just my code I attempted to compile the GridSplitter sample from LearnWPF.com and it doesn't appear to work either. I am expecting to see the standard resize cursor when I mouse over the splitter which doesn't happen, and as far as I can see there is no other visual representation of the splitter in the window either.
What am I missing here?
<Window x:Class="UI.Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test" Height="300" Width="300">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Background="#feca00" Grid.Column="0">
<TextBlock FontSize="35" Foreground="#58290A"
TextWrapping="Wrap">Left Hand Side</TextBlock>
</StackPanel>
<GridSplitter/>
<Border CornerRadius="10" BorderBrush="#58290A"
BorderThickness="5" Grid.Column="1">
<TextBlock FontSize="25" Margin="20" Foreground="#FECA00"
TextWrapping="Wrap">Right Hand Side</TextBlock>
</Border>
</Grid>
In your example, GridSplitter is being placed in the first column. I don't remember my WPF alignment rules off the top of my head, but I think it's probably being placed on the left side of the first column. Not really what you wanted.
It is much easier to make a GridSplitter occupy a row or column, than to try and share a row or column with other controls.
<Window x:Class="UI.Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test" Height="300" Width="300">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Background="#feca00">
<TextBlock FontSize="35" Foreground="#58290A" TextWrapping="Wrap">
Left Hand Side
</TextBlock>
</StackPanel>
<GridSplitter
Width="4"
Grid.Column="1"
Background="Red"
VerticalAlignment="Stretch"
HorizontalAlignment="Center"/>
<Border
Grid.Column="2"
BorderBrush="#58290A"
BorderThickness="5"
CornerRadius="10">
<TextBlock FontSize="25" Foreground="#FECA00" TextWrapping="Wrap">
Right Hand Side
</TextBlock>
</Border>
</Grid>
</Grid>
</Window>
You're missing important concept of Z-Ordering. Controls are placed in the z-order in the order you list them. Basically, your grid splitter is being covered up by the last column. If you place the Grid Splitter over the last column in the z-order, it should work just fine without requiring an extra column:
<Window x:Class="UI.Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test" Height="300" Width="300">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Background="#feca00" Grid.Column="0">
<TextBlock FontSize="35" Foreground="#58290A" TextWrapping="Wrap">Left Hand Side</TextBlock>
</StackPanel>
<Border CornerRadius="10" BorderBrush="#58290A" BorderThickness="5" Grid.Column="1">
<TextBlock FontSize="25" Margin="20" Foreground="#FECA00" TextWrapping="Wrap">Right Hand Side</TextBlock>
</Border>
<GridSplitter Grid.Column="1"/>
</Grid>
</Grid>

Centering a WPF control

I have a window where I add a new UserControl to (with an image), I simply want to center the control in the middle of the screen (both vertically and horizontally). I can only get the vertical one to work. I'm gonna swap content in the DockPanel from my CodeBehind and want to show this startup screen before I start doing my slideshow UI, this means that the content is set from the CodeBehind.
My Window:
<Window x:Class="GreenWebPlayerWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="512" Width="853" WindowStyle="None" WindowState="Maximized" WindowStartupLocation="CenterScreen">
<DockPanel Width="Auto" Height="Auto" Name="TransitionContainer" Background="Black" Margin="0" LastChildFill="True"></DockPanel>
</Window>
My UserControl:
<UserControl x:Class="GreenWebPlayerWPF.FrontPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel Background="Black">
<Image Name="image1" Stretch="None" Source="/GreenWebPlayerWPF;component/gw.png" />
</DockPanel>
</UserControl>
Please note that I'm using maximized/full screen.
Use a Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Replace with your UserControl -->
<Button Content="Foo" Grid.Column="1" Grid.Row="1"/>
</Grid>
You can dock it inside your DockPanel (if you must have a DockPanel there) to stretch. And, of course, while the above is all markup, you can just as easily create such a grid from code.
I keep running into this problem when trying to center elements on the page.
The problem with the StackPanel is that HorizontalAlignment has no effect when the Orientation is Horizontal and VerticalAlignment no effect when Orientation is Vertical. So you keep banging your head trying to set values with no effect. It is not illogical that it works this way but it would be good if this was reported as an error.
The solution I found is to have two imbricated StackPanels one centered horizontally and the other vertically as shown below. Finding the size of the parent is needed to size the intermediate panel otherwise it would be flat and its content hidden - an absolute value would work as well. Although not a panacea itis a bit less verbose than using a grid.
<StackPanel Background="Bisque" Orientation="Vertical" Width="300" Height="300" >
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=StackPanel}, Path=ActualHeight}">
<StackPanel VerticalAlignment="Center" Width="200" Height="60" Background="Blue">
</StackPanel>
</StackPanel>
</StackPanel>
It's quite an old one, but centring a control is now as simple as:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Height="350" Width="600">
<TextBox />
</StackPanel>
</Grid>

Resources