Displaying a large image in a ScrollViewer in another ScrollViewer - wpf

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>

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

How can use flow layout inside of a ScrollViewer?

I have a situation with a scroll viewer, and a wrap panel inside of that scroll viewer. The intended behavior is that the content does not scroll left and right, only up and down, and that content wraps (becomes taller) as necessary.
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden" Margin="0">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="330" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="74" />
<RowDefinition Height="75" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- ... other stuff ... -->
<WrapPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" Margin="35,0,0,0">
<Button Style="{StaticResource CreateModelButtonStyle}"
CommandParameter="Design"
Command="{StaticResource WindowProfileUnconditional}">
<StackPanel>
<TextBlock Style="{StaticResource HomePageButtonMarqeeTextStyle}" Text="Blah Blah"/>
<TextBlock Style="{StaticResource HomePageButtonDescriptionTextStyle}" Text="Blah Blah" />
</StackPanel>
</Button>
<!-- A bunch more buttons -->
</WrapPanel>
<!-- ... other stuff ... -->
</Grid>
</ScrollViewer>
The behavior I get instead is that the scroll viewer tells the wrap panel that it can be any width, so the wrap panel behaves like a stack panel and clips instead of wraps.
Is there some way to allow vertical scrolling while completely preventing horizontal scrolling?
Why don't you bind the Width of your WrapPanel (or Grid) to the Width of the ScrollViewer?
<ScrollViewer x:Name="MyScrollViewer" ...>
<WrapPanel Width="{Binding ElementName=MyScrollViewer, Path=Width}" ... />
</ScrollViewer>
Not positive if you need to bind to Width or ActualWidth. If one doesn't work, try the other one.

How to have filled video at top and show label at bottom. (Fill and Anchor)

In Winforms, I use Fill and Dock to achieve this.
I have a "Page" where I would like to play a video file and also show the label at the bottom. I would like the page to be able to stretch and for the video to stretch and to have the label stay at the bottom of the page.
My attempts so far always results in the video covering the label when it is played. How can this be fixed?
(Other controls in the StackPanel have been omitted)
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MediaElementExample" >
<DockPanel LastChildFill="True">
<MediaElement Source="media\numbers.wmv" Name="myMediaElement"
LoadedBehavior="Manual" UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded"
DockPanel.Dock="Top" Margin="50" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="30" DockPanel.Dock="Bottom" Margin="50">
<TextBlock Margin="5" VerticalAlignment="Center">
Video Label
</TextBlock>
</StackPanel>
</DockPanel>
</Page>
Solution (with thanks to Daniel May):
<Grid Height="Auto">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<MediaElement Source="media\numbers.wmv" Name="myMediaElement" LoadedBehavior="Manual" UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened" MediaEnded="Element_MediaEnded" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Height="30" Grid.Row="1">
<Button Content="Button" Height="23" Name="button1" Width="75" Click="button1_Click" />
</StackPanel>
</Grid>
You can achieve this using a Grid.
<Grid Height="300" Width="300">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<MediaElement Source="media\numbers.wmv"
Name="myMediaElement"
LoadedBehavior="Manual"
UnloadedBehavior="Stop"
MediaOpened="Element_MediaOpened"
MediaEnded="Element_MediaEnded" />
<TextBlock Margin="5"
Grid.Row="1"
VerticalAlignment="Center"
Text="Video Label" />
</Grid>
Using the Height attribute on the second RowDefinition, you force that row to size to it's contents. The preceding RowDefinition then fills the rest of the available space (in your case, your MediaElement).

How to get this window layout in WPF?

im trying to create a Window with the following layout:
Layout http://www.x-toolz.com/downloads/layout.jpg
As you can see the window has 3 rows (15*, 70*, 15*) and 3 columns (same).
How can I redesign a rectangle to fit the geometry of the corners?
If it can't be done with rectangles i would need another control that I can place content (Grid, StackPanel) in.
Any Ideas?
Thanks in advance!
MemphiZ
You could do that with a grid with 9 cells. Create 8 usercontrols to hold your outside content. If you want it size adjustable, you are going to have to work a little magic.
Each corner user control would have a 2x2 grid and for the upper left panel I will give a small example.
<UserControl
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:ec="http://schemas.microsoft.com/expression/2010/controls"
mc:Ignorable="d"
x:Class="TopLeft"
x:Name="UserControl"
d:DesignWidth="480" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<Rectangle Stroke="Black" Grid.RowSpan="2" Fill="Black"/>
<Rectangle Fill="Black" Stroke="Black" Grid.ColumnSpan="2"/>
<Path Grid.Column="1" Data="M0.5,0.5 L239.5,0.5 120,120 0.5,239.5 z" Fill="Black" Grid.Row="1" Stretch="Fill" Stroke="Black" />
</Grid>
</UserControl>
In the above example a 2 x 2 grid, with a diagonal path in the bottom right. If your main window is going to resize you will have to decide whether or not your border areas will resize accordingly or be a static frame around the body of the window.
Here is the window:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MegaPanel"
x:Class="MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0.3*"/>
<RowDefinition Height="0.3*"/>
<RowDefinition Height="0.3*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.3*"/>
<ColumnDefinition Width="0.3*"/>
<ColumnDefinition Width="0.3*"/>
</Grid.ColumnDefinitions>
<local:TopLeft Margin="0"/>
</Grid>
</Window>
I failed to put a Content presenter in the UserControl, but you would put that in there to add content to it.
The body area of the window would have to be handled with some care. You can set the Margin to negative values to allow the contents of the body to spill out into the frame areas.
Edit
Example:
<local:TopLeft Margin="0">
<local:TopLeft.Tag>
<ListBox/>
</local:TopLeft.Tag>
</local:TopLeft>
The above change to Top left assigns the ListBox to the Tag property of the TopLeft usercontrol. In the User control, I bound the ContentPresenter to the Tag Property of the UserControl. ListBox is assigned to the tag, ContentPresenter gets the ListBox from the Tag. Of you can regester custom properties in the UserControl codebehind if you want things in several areas.
<ContentPresenter Grid.RowSpan="2" Grid.ColumnSpan="2" Margin="0,0,125,125" Content="{Binding Tag, ElementName=UserControl}"/>
For registering custom DependencyProperties check this post out.
<Window x:Class="WpfApplication2.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">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="15*" />
<RowDefinition Height="15*" />
<RowDefinition Height="40*" />
<RowDefinition Height="15*" />
<RowDefinition Height="15*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15*" />
<ColumnDefinition Width="15*" />
<ColumnDefinition Width="40*" />
<ColumnDefinition Width="15*" />
<ColumnDefinition Width="15*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Background="Blue">
<!-- Top Left Content Goes Here -->
</Grid>
<Grid Grid.Column="2" Grid.Row="0" Background="Aqua">
<!-- Top Middle Content Goes Here-->
</Grid>
<Grid Grid.Column="3" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Background="Gold">
<!-- Top Right Content Goes Here -->
</Grid>
<Grid Grid.Column="0" Grid.Row="2" Background="Magenta">
<!-- Middle LEft Content goes here -->
</Grid>
<Grid Grid.Column="4" Grid.Row="2" Background="Lime">
<!-- Middle Right Content goes here -->
</Grid>
<Grid Grid.Column="0" Grid.Row="3" Grid.RowSpan="2" Grid.ColumnSpan="2" Background="Red">
<!-- Bottom Left Content Goes Here -->
</Grid>
<Grid Grid.Column="2" Grid.Row="4" Background="DarkGoldenrod">
<!-- Bottom Middle Content Goes Here-->
</Grid>
<Grid Grid.Column="3" Grid.Row="3" Grid.RowSpan="2" Grid.ColumnSpan="2" Background="Silver">
<!-- Bottom Right Content Goes Here -->
</Grid>
<!-- This is used to shape the center" -->
<Polygon x:Name="main" Grid.Column="1" Grid.Row="1" Grid.RowSpan="3" Grid.ColumnSpan="3" Fill="White" Points="0,15 15,0 55,0 70,15 70,55 55,70 15,70 0,55" Stretch="Fill" StrokeThickness="0"/>
<Grid Grid.Column="1" Grid.Row="1" Grid.RowSpan="3" Grid.ColumnSpan="3" Background="Pink" >
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=main}" />
</Grid.OpacityMask>
<!-- Centre Content Goes Here-->
</Grid>
</Grid>
</Grid>
</Window>
This produces this layout. The limitation is that WPF does its bounds clipping to rectangles so any content that overflows the regions will be made invisible (i.e. Clipped).
You could partially work around this by applying padding to each grid element to a create a rectangular area that fits inside each region.

How do I customize the WPF StatusBar layout?

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>

Resources