У меня есть решение. Это создает индикатор выполнения, который указывает, насколько заполнен «контейнер» с ползунком ползунка, наложенным сверху. Пользователь может перемещать ползунок внутри индикатора выполнения, но только до его текущего значения.
Примером того, как вы можете использовать это, является контроллер записи звука. Индикатор выполнения показывает объем памяти и объем аудио, записанный в данный момент. Большой палец указывает позицию воспроизведения.
Шаг 1:
Определите стиль для ползунка и добавьте индикатор выполнения. Поместите его в тот же визуал (та же ячейка сетки), что и большой палец. Поместите его перед большим пальцем, чтобы он оказался под ним:
<ControlTemplate x:Key="HorizontalProgressSlider" TargetType="{x:Type Slider}">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TickBar x:Name="TopTick" Visibility="Collapsed" Fill="LightGray" Placement="Top" SnapsToDevicePixels="True"
Height="4" Margin="0,0,0,2" />
<ProgressBar x:Name="TrackProgressBar" Grid.Row="1" HorizontalAlignment="Stretch" Height="10" VerticalAlignment="Center"
Margin="8,0,8,0" Foreground="CadetBlue"></ProgressBar>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource SliderRepeatButtonStyle}" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource SliderRepeatButtonStyle}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Style="{StaticResource SliderThumbStyle}" />
</Track.Thumb>
</Track>
<TickBar x:Name="BottomTick" Grid.Row="2" Visibility="Collapsed" Fill="LightGray" Placement="Bottom"
SnapsToDevicePixels="True" Height="4" Margin="0,2,0,0"/>
</Grid>
<ControlTemplate>
Шаг 2:
Создайте вложенные свойства, которые можно туннелировать вниз, чтобы найти ProgressBar:
public class SliderProgressBarAttachedProperty : DependencyObject
{
public static readonly DependencyProperty ProgressValueProperty =
DependencyProperty.RegisterAttached("ProgressValue", typeof(int), typeof(SliderProgressBarAttachedProperty), new PropertyMetadata(OnItemsChanged));
public static int GetProgressValue(DependencyObject obj)
{
return (int)obj.GetValue(ProgressValueProperty);
}
public static void SetProgressValue(DependencyObject obj, int value)
{
obj.SetValue(ProgressValueProperty, value);
}
public static readonly DependencyProperty ProgressMaximumProperty =
DependencyProperty.RegisterAttached("ProgressMaximum", typeof(int), typeof(SliderProgressBarAttachedProperty), new PropertyMetadata(OnItemsChanged));
public static int GetProgressMaximum(DependencyObject obj)
{
return (int)obj.GetValue(ProgressMaximumProperty);
}
public static void SetProgressMaximum(DependencyObject obj, int value)
{
obj.SetValue(ProgressMaximumProperty, value);
}
private static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slider = d as Slider;
var progressValue = GetProgressValue(d);
var progressMaximum = GetProgressMaximum(d);
if (slider == null) return;
var progressBar = slider.Template.FindName("TrackProgressBar",slider) as ProgressBar;
if (progressBar == null) return;
progressBar.Maximum = progressMaximum;
progressBar.Value = progressValue;
}
}
Шаг 3:
Предотвратите перемещение ползунка за пределы значения ProgressBar, реализовав обработчик для ValueChanged:
private void RangeBase_OnValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
var slider = sender as Slider;
if (slider == null) return;
var progressBar = (ProgressBar)slider.Template.FindName("TrackProgressBar", slider);
if (progressBar == null) return;
if (e.NewValue > progressBar.Value)
{
slider.Value = progressBar.Value;
e.Handled = true;
return;
}
}