Is it possible to make the elements within a WPF toolbar have a HorizontalAlignment of Right?
<ToolBar Height="38" VerticalAlignment="Top" Grid.Row="1">
<Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
<Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
<ComboBox Width="120" HorizontalAlignment="Right"/>
</ToolBar>
I've tried adding the elements inside into a Grid and assigning the ColumnDefinition
s to Left/Right as we开发者_如何学JAVAll. I have also tried a StackPanel
. No matter what I try I can't seem to get the ComboBox to be "anchored" on the right side of the Toolbar.
UPDATE:
<DockPanel LastChildFill="True">
Doesn't work, It will not fill the ToolBar element like it would a normal element.
Further investigation showed that in order to do this I need to set the width of a Grid
within the ToolBar
, or as Chris Nicol said, a DockPanel
within the ToolBar
dynamically to that of the width of the Toolbar
using RelativeSource
.
However, that did not feel like a clean solution. It is quite complicated to get the Toolbar
to update correctly on resizing. So instead I found somewhat of a hack that looks, and operates cleaner by adding an external Grid.
<Grid>
<ToolBar Height="38" VerticalAlignment="Top" Grid.Row="1">
<Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
<Button HorizontalAlignment="Left" Width="50" VerticalAlignment="Stretch"/>
</ToolBar>
<ComboBox Margin="0,0,15,0" Width="120" HorizontalAlignment="Right" Grid.Row="1"/>
</Grid>
Since all of my elements are on a Grid, I can place my ComboBox
on top of the ToolBar
by assigning it's Grid.Row
to the same row as the toolbar. After setting my Margins
to pull the ComboBox
over slightly as not to interfere with looks, it operates as needed with no bugs. Since the only other way I found to do this was setting a DockPanel/Grid's Width property dynamically, I actually feel like this is the cleaner more efficient way to do it.
I realize this is an old topic, but it still pops up when asking the question. This is how I handle this question:
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="MenuRow" Height="25"/>
<RowDefinition x:Name="ToolbarRow" Height="25"/>
<RowDefinition x:Name="CatalogRow" Height="*"/>
<RowDefinition x:Name="RecipeRow" Height="0.4*"/>
</Grid.RowDefinitions>
<ToolBar Grid.Row="1">
<Button x:Name="tbFileOpen" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/Load.png"/></Button>
<Button x:Name="tbFileSave" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/Save.png"/></Button>
<Button x:Name="tbFileClear" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/New document.png"/></Button>
</ToolBar>
<ToolBar Grid.Row="1" HorizontalAlignment="Right">
<Button x:Name="tbFileExit" Margin="0,0,0,0" Click="MenuItem_Click"><Image Source="Icons/Main/File/Exit.png"/></Button>
</ToolBar>
</Grid>
Effectively: I create two toolbar objects and have them on the same Grid.row. The first one has default (left) alignment, the second one is right aligned. It seems to do the trick for me.
For anyone else looking for a solution, the following worked for me:
<ToolBar HorizontalAlignment="Stretch" ToolBarTray.IsLocked="True">
<ToolBar.Resources>
<Style TargetType="{x:Type DockPanel}">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</ToolBar.Resources>
I'm using .NET 4.6 and VS2015, but I believe this would work in previous versions too.
Have you tried using a DockPanel that fills the toolbar, then you can dock the ComboBox to the right.
Remember that with a dockpanel the sequence you put the items in is very important.
HTH
<ToolBar Width="100" VerticalAlignment="Top" >
<ToolBar.Resources>
<Style TargetType="{x:Type ToolBarPanel}">
<Setter Property="Orientation" Value="Vertical"/>
</Style>
</ToolBar.Resources>
<DockPanel>
<ToolBarPanel Orientation="Horizontal" >
<Button>A</Button>
<Button>B</Button>
</ToolBarPanel>
<Button DockPanel.Dock="Right" HorizontalAlignment="Right">C</Button>
</DockPanel>
</ToolBar>
My solution to this was to create a label control with a "spring" like ability, so that it would fill the empty void with between the buttons on the toolbar, thus "right aligning" the toolbar's combobox (or any other control that needs "right-aligned).
To do this, I created a WidthConverter, that would take the Actual Width of the ToolBar Control, and then subtract the the space needed needed to right align the combobox.:
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Math.Max(System.Convert.ToDouble(value) - System.Convert.ToDouble(parameter), 0.0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then, I added a label control to the toolbar, placed to the left of the combobox you need right aligned. Bind the label's Width to the toolbar's ActualWidth and apply the WidthConverter:
<Label Width="{Binding Converter={StaticResource WidthConverter}, ElementName=toolBar1, Path=ActualWidth, ConverterParameter=50}" />
You will need to adjust the ConverterParameter to your specific needs until you get the desired "right align". A higher number provides more space for the combobox, whereas a lower number provides less space.
Using this solution, the label will automatically resize whenever your toolbar resizes, making it appear that you have right aligned your combobox.
There are two great benefit to this solution compared to adding a grid to the toolbar. The first is that if you need to use buttons on the toolbar, you won't lose the toolbar button styling. The second is that the overflow will work as expected if the toolbar length is reduced through window resizing. Individual buttons will go into the overflow as required. If the buttons are put into a a grid then the grid is put into the overflow taking all buttons with it.
XAML of it in use:
<ToolBarPanel>
<ToolBar Name="toolBar1">
<Button>
<Image Source="save.png"/>
</Button>
<Label Width="{Binding Converter={StaticResource Converters.WidthConverter},
ElementName=toolBar1,
Path=ActualWidth,
ConverterParameter=231}" HorizontalAlignment="Stretch" ToolBar.OverflowMode="Never"/>
<Button>
<Image Source="open.png"/>
</Button>
</ToolBar>
If you desire to always keep the last button on the toolbar, say a help button that you always want visible, add the attribute ToolBar.OverflowMode="Never" to its element.
This is how I did it:
I created a style for the toolbar
<Style x:Key="{x:Type ToolBar}" TargetType="{x:Type ToolBar}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolBar}">
<Grid Background="{StaticResource ToolGridBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Style="{StaticResource LogoImage}"/>
<ToolBarPanel Grid.Column="2" x:Name="PART_ToolBarPanel" IsItemsHost="true" Margin="0,1,2,2" Orientation="Horizontal"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The important part is :
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
And
<ToolBarPanel Grid.Column="2"/>
With this, your buttons will be right aligned
I'm not very satisfied with the "WidthConverter" solution because I got some dynamic elements at end. Further search led me to here, which seems to be working perfect for me. Here is my code sample in case you are interested:
<ToolBar Name="toolBar">
<DockPanel Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ToolBarPanel}}}">
<DockPanel.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"></Style>
</DockPanel.Resources>
<Button x:Name="btnRefresh" ToolTip="Refresh" Click="btnRefresh_Click">
<Image Margin="2 0" Source="/Resources/refresh.ico" Height="16" Width="16"/>
</Button>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Image Margin="2 0" Source="/Resources/Help.ico" Height="16" Width="16"/>
<TextBlock Text="Help" Margin="2 0" VerticalAlignment="Center"/>
</StackPanel>
</DockPanel>
</ToolBar>
精彩评论