How to expand a Slider to fill the available space when the slider is within a StackPanel
Inserting a Slider
in a Grid
would expand it to fill the available space, but I would prefer not use a grid for the following reason:
I've a TextBlock
and a Slider
in a UserControl
, the slider is spring loaded and does jog / shuttle; the current value has to be displayed because the user can't rely on the neutral cursor's position, so the textblock. Implementing the **Orientation**
property of this custom slider requires both components to be rotated and also their relative position to be adjusted (left/right or top/bottom), which wouldn't be easy with a grid (unless I miss something obvious) while it is with a StackPanel
.
Response to Aviad's comment
Aviad, thanks, I apologize for the pain ;-) The question was in the title: How to expand a Slider to fill the available space when the slider is within a StackPanel ?
This user control:
<UserControl x:Class="XXX.Preview.SelectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsof开发者_C百科t.com/winfx/2006/xaml"
Height="auto" Width="auto">
<GroupBox Header="Selected">
<StackPanel Orientation="Horizontal">
<TextBlock/>
<Slider/>
</StackPanel>
</GroupBox>
</UserControl>
won't expand when included in a grid even in a row with a "*" width. The slider will have no length at all.
A solution is to replace the stack panel by a grid in the code below, but I don't want to use a grid, because I need to use the Orientation property of the stack panel to show both controls stacked vertically when the enclosing user control is set in the Orientation "Vertical".
Very simple with binding! Note that the StackPanel as HorizontalAlignment="Stretch" and a name referred to by the binding
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Top" Orientation="Horizontal" Name="ParentPanel">
<Slider Minimum="1" Maximum="999999" Interval="3" Width="{Binding Path=ActualWidth, ElementName=ParentPanel}"></Slider>
</StackPanel>
Credits to @somedust
Follow this link to a similar question and learn how to have more control over the binding by using converters.
You can embed the Slider inside a Grid column that has a ColumnDefinition like Witdh="*" (i.e. will distribute available space). For example, below you can find how to get TextBlock | Slider | TextBlock layout with the slider stretched to fill the available space in the middle column:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="CutOff Fraction:"/>
<Slider Grid.Column="1"
x:Name="SliderCutOffFraction"
IsEnabled="{Binding ElementName=ChkLanczosFilter, Path=IsChecked}"
HorizontalAlignment="Stretch"
Margin="2"
Minimum="0.5"
Maximum="5"
SmallChange="0.25"
LargeChange="0.5"
TickPlacement="BottomRight"
TickFrequency="0.5"
Value="1"
ValueChanged="SliderCutOffFraction_OnValueChanged"/>
<TextBlock Grid.Column="2" Width="20"
DockPanel.Dock="Right"
Text="{Binding ElementName=SliderCutOffFraction, Path=Value}"
TextAlignment="Center"/>
</Grid>
This thing can be better done by using DockPanel instead of StackPanel. You can try that.
Check this: http://msdn.microsoft.com/en-us/library/bb628664.aspx
and http://www.wpftutorial.net/DockPanel.html
The short answer is "you can't." StackPanel is limited this way by its ArrangeOverride and MeasureOverride code. It simply does not have the ability to expand to fill available space in the stacking direction.
You could subclass StackPanel, of course, and implement it differently, but StackPanel is so simple that if you're going to do that you may as well just subclass Panel, or you could subclass DockPanel (which has the expansion ability), and set DockPanel.Dock on all its children based on its StackPanel.Orientation property:
public class StackPanelExpanding : DockPanel
{
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
public static DependencyProperty OrientationProperty =
StackPanel.OrientationProperty.AddOwner(typeof(StackPanelExpanding));
protected override MeasureOverride(...)
{
var dock = Orientation==Orientation.Vertical ? Dock.Top : Dock.Left;
foreach(var element in Children)
SetDock(element, dock);
base.MeasureOverride(...);
}
}
You still didn't make it clear why you can't just use a DockPanel and use trigger in your template to synchronize the Orientation and DockPanel.Dock. Frankly in most cases I would be more inclined to go that way than to create a custom panel.
精彩评论