Browse Source

Port TickBar from WPF

feature/fluent-slider
Jumar Macato 6 years ago
parent
commit
2fa6f6c0d6
No known key found for this signature in database GPG Key ID: B19884DAC3A5BF3F
  1. 593
      src/Avalonia.Controls/TickBar.cs
  2. 34
      src/Avalonia.Themes.Fluent/Slider.xaml

593
src/Avalonia.Controls/TickBar.cs

@ -0,0 +1,593 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Utilities;
namespace Avalonia.Controls
{
/// <summary>
/// Enum which describes how to position the TickBar.
/// </summary>
public enum TickBarPlacement
{
/// <summary>
/// Position this tick at the left of target element.
/// </summary>
Left,
/// <summary>
/// Position this tick at the top of target element.
/// </summary>
Top,
/// <summary>
/// Position this tick at the right of target element.
/// </summary>
Right,
/// <summary>
/// Position this tick at the bottom of target element.
/// </summary>
Bottom,
// NOTE: if you add or remove any values in this enum, be sure to update TickBar.IsValidTickBarPlacement()
};
/// <summary>
/// TickBar is an element that use for drawing Slider's Ticks.
/// </summary>
public class TickBar : TemplatedControl
{
static TickBar()
{
AffectsRender<TickBar>(ReservedSpaceProperty, MaximumProperty, MinimumProperty, OrientationProperty, TickFrequencyProperty);
}
public TickBar() : base()
{
}
/// <summary>
/// Defines the <see cref="Fill"/> property.
/// </summary>
public static readonly StyledProperty<IBrush> FillProperty =
AvaloniaProperty.Register<TickBar, IBrush>(nameof(Fill));
/// <summary>
/// Brush used to fill the TickBar's Ticks.
/// </summary>
public IBrush Fill
{
get { return GetValue(FillProperty); }
set { SetValue(FillProperty, value); }
}
/// <summary>
/// Defines the <see cref="Minimum"/> property.
/// </summary>
public static readonly StyledProperty<double> MinimumProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(Minimum), 0d);
/// <summary>
/// Logical position where the Minimum Tick will be drawn
/// </summary>
public double Minimum
{
get { return GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
/// <summary>
/// Defines the <see cref="Maximum"/> property.
/// </summary>
public static readonly StyledProperty<double> MaximumProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(Maximum), 0d);
/// <summary>
/// Logical position where the Maximum Tick will be drawn
/// </summary>
public double Maximum
{
get { return GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
/*
/// <summary>
/// Defines the <see cref="SelectionStart"/> property.
/// </summary>
public static readonly StyledProperty<double> SelectionStartProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(SelectionStart), 0d);
/// <summary>
/// Logical position where the SelectionStart Tick will be drawn
/// </summary>
public double SelectionStart
{
get { return GetValue(SelectionStartProperty); }
set { SetValue(SelectionStartProperty, value); }
}
/// <summary>
/// Defines the <see cref="SelectionEnd"/> property.
/// </summary>
public static readonly StyledProperty<double> SelectionEndProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(SelectionEnd), 0d);
/// <summary>
/// Logical position where the SelectionEnd Tick will be drawn
/// </summary>
public double SelectionEnd
{
get { return GetValue(SelectionEndProperty); }
set { SetValue(SelectionEndProperty, value); }
}
/// <summary>
/// Defines the <see cref="IsSelectionRangeEnabled"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsSelectionRangeEnabledProperty =
AvaloniaProperty.Register<TickBar, bool>(nameof(IsSelectionRangeEnabled));
/// <summary>
/// IsSelectionRangeEnabled specifies whether to draw SelectionStart Tick and SelectionEnd Tick or not.
/// </summary>
public bool IsSelectionRangeEnabled
{
get { return GetValue(IsSelectionRangeEnabledProperty); }
set { SetValue(IsSelectionRangeEnabledProperty, value); }
}
*/
/// <summary>
/// Defines the <see cref="TickFrequency"/> property.
/// </summary>
public static readonly StyledProperty<double> TickFrequencyProperty =
AvaloniaProperty.Register<TickBar, double>(nameof(TickFrequency), 0d);
/// <summary>
/// TickFrequency property defines how the tick will be drawn.
/// </summary>
public double TickFrequency
{
get { return GetValue(TickFrequencyProperty); }
set { SetValue(TickFrequencyProperty, value); }
}
/// <summary>
/// Defines the <see cref="Orientation"/> property.
/// </summary>
public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<TickBar, Orientation>(nameof(Orientation));
/// <summary>
/// TickBar parent's orientation.
/// </summary>
public Orientation Orientation
{
get { return GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Defines the <see cref="Ticks"/> property.
/// </summary>
public static readonly StyledProperty<List<double>> TicksProperty =
AvaloniaProperty.Register<TickBar, List<double>>(nameof(Ticks));
/// <summary>
/// The Ticks property contains collection of value of type Double which
/// are the logical positions use to draw the ticks.
/// The property value is a <see cref="DoubleCollection" />.
/// </summary>
public List<double> Ticks
{
get { return GetValue(TicksProperty); }
set { SetValue(TicksProperty, value); }
}
/// <summary>
/// Defines the <see cref="IsDirectionReversed"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsDirectionReversedProperty =
AvaloniaProperty.Register<TickBar, bool>(nameof(IsDirectionReversed), false);
/// <summary>
/// The IsDirectionReversed property defines the direction of value incrementation.
/// By default, if Tick's orientation is Horizontal, ticks will be drawn from left to right.
/// (And, bottom to top for Vertical orientation).
/// If IsDirectionReversed is 'true' the direction of the drawing will be in opposite direction.
/// </summary>
public bool IsDirectionReversed
{
get { return GetValue(IsDirectionReversedProperty); }
set { SetValue(IsDirectionReversedProperty, value); }
}
/// <summary>
/// Defines the <see cref="Placement"/> property.
/// </summary>
public static readonly StyledProperty<TickBarPlacement> PlacementProperty =
AvaloniaProperty.Register<TickBar, TickBarPlacement>(nameof(Placement), 0d);
/// <summary>
/// Placement property specified how the Tick will be placed.
/// This property affects the way ticks are drawn.
/// This property has type of <see cref="TickBarPlacement" />.
/// </summary>
public TickBarPlacement Placement
{
get { return GetValue(PlacementProperty); }
set { SetValue(PlacementProperty, value); }
}
private static bool IsValidTickBarPlacement(object o)
{
TickBarPlacement placement = (TickBarPlacement)o;
return placement == TickBarPlacement.Left ||
placement == TickBarPlacement.Top ||
placement == TickBarPlacement.Right ||
placement == TickBarPlacement.Bottom;
}
/// <summary>
/// Defines the <see cref="ReservedSpace"/> property.
/// </summary>
public static readonly StyledProperty<Rect> ReservedSpaceProperty =
AvaloniaProperty.Register<TickBar, Rect>(nameof(ReservedSpace));
/// <summary>
/// TickBar will use ReservedSpaceProperty for left and right spacing (for horizontal orientation) or
/// tob and bottom spacing (for vertical orienation).
/// The space on both sides of TickBar is half of specified ReservedSpace.
/// This property has type of <see cref="Rect" />.
/// </summary>
public Rect ReservedSpace
{
get { return GetValue(ReservedSpaceProperty); }
set { SetValue(ReservedSpaceProperty, value); }
}
/// <summary>
/// Draw ticks.
/// Ticks can be draw in 8 diffrent ways depends on Placment property and IsDirectionReversed property.
///
/// This function also draw selection-tick(s) if IsSelectionRangeEnabled is 'true' and
/// SelectionStart and SelectionEnd are valid.
///
/// The primary ticks (for Mininum and Maximum value) height will be 100% of TickBar's render size (use Width or Height
/// depends on Placement property).
///
/// The secondary ticks (all other ticks, including selection-tics) height will be 75% of TickBar's render size.
///
/// Brush that use to fill ticks is specified by Shape.Fill property.
///
/// Pen that use to draw ticks is specified by Shape.Pen property.
/// </summary>
public override void Render(DrawingContext dc)
{
var size = new Size(Bounds.Width, Bounds.Height);
var range = Maximum - Minimum;
var tickLen = 0.0d; // Height for Primary Tick (for Mininum and Maximum value)
var tickLen2 = 0.0d; // Height for Secondary Tick
var logicalToPhysical = 1.0;
var progression = 1.0d;
var startPoint = new Point();
var endPoint = new Point();
var rSpace = Orientation == Orientation.Horizontal ? ReservedSpace.Width : ReservedSpace.Height;
// Take Thumb size in to account
double halfReservedSpace = rSpace * 0.5;
switch (Placement)
{
case TickBarPlacement.Top:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
{
return;
}
size = new Size(size.Width - rSpace, size.Height);
tickLen = -size.Height;
startPoint = new Point(halfReservedSpace, size.Height);
endPoint = new Point(halfReservedSpace + size.Width, size.Height);
logicalToPhysical = size.Width / range;
progression = 1;
break;
case TickBarPlacement.Bottom:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
{
return;
}
size = new Size(size.Width - rSpace, size.Height);
tickLen = size.Height;
startPoint = new Point(halfReservedSpace, 0d);
endPoint = new Point(halfReservedSpace + size.Width, 0d);
logicalToPhysical = size.Width / range;
progression = 1;
break;
case TickBarPlacement.Left:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
{
return;
}
size = new Size(size.Width, size.Height - rSpace);
tickLen = -size.Width;
startPoint = new Point(size.Width, size.Height + halfReservedSpace);
endPoint = new Point(size.Width, halfReservedSpace);
logicalToPhysical = size.Height / range * -1;
progression = -1;
break;
case TickBarPlacement.Right:
if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
{
return;
}
size = new Size(size.Width, size.Height - rSpace);
tickLen = size.Width;
startPoint = new Point(0d, size.Height + halfReservedSpace);
endPoint = new Point(0d, halfReservedSpace);
logicalToPhysical = size.Height / range * -1;
progression = -1;
break;
};
tickLen2 = tickLen * 0.75;
// Invert direciton of the ticks
if (IsDirectionReversed)
{
progression *= -progression;
logicalToPhysical *= -1;
// swap startPoint & endPoint
var pt = startPoint;
startPoint = endPoint;
endPoint = pt;
}
var pen = new Pen(Fill, 1.0d);
bool snapsToDevicePixels = UseLayoutRounding;
// var xLines = snapsToDevicePixels ? new List<double>() : null;
// var yLines = snapsToDevicePixels ? new List<double>() : null;
// Is it Vertical?
if ((Placement == TickBarPlacement.Left) || (Placement == TickBarPlacement.Right))
{
// Reduce tick interval if it is more than would be visible on the screen
double interval = TickFrequency;
if (interval > 0.0)
{
double minInterval = (Maximum - Minimum) / size.Height;
if (interval < minInterval)
{
interval = minInterval;
}
}
// Draw Min & Max tick
dc.DrawLine(pen, startPoint, new Point(startPoint.X + tickLen, startPoint.Y));
dc.DrawLine(pen, new Point(startPoint.X, endPoint.Y),
new Point(startPoint.X + tickLen, endPoint.Y));
// if (snapsToDevicePixels)
// {
// xLines.Add(startPoint.X);
// yLines.Add(startPoint.Y - 0.5);
// xLines.Add(startPoint.X + tickLen);
// yLines.Add(endPoint.Y - 0.5);
// xLines.Add(startPoint.X + tickLen2);
// }
// This property is rarely set so let's try to avoid the GetValue
// caching of the mutable default value
var ticks = Ticks ?? null;
// Draw ticks using specified Ticks collection
if (ticks?.Count > 0)
{
for (int i = 0; i < ticks.Count; i++)
{
if (MathUtilities.LessThanOrClose(ticks[i],Minimum) || MathUtilities.GreaterThanOrClose(ticks[i],Maximum))
{
continue;
}
double adjustedTick = ticks[i] - Minimum;
double y = adjustedTick * logicalToPhysical + startPoint.Y;
dc.DrawLine(pen,
new Point(startPoint.X, y),
new Point(startPoint.X + tickLen2, y));
// if (snapsToDevicePixels)
// {
// yLines.Add(y - 0.5);
// }
}
}
// Draw ticks using specified TickFrequency
else if (interval > 0.0)
{
for (double i = interval; i < range; i += interval)
{
double y = i * logicalToPhysical + startPoint.Y;
dc.DrawLine(pen,
new Point(startPoint.X, y),
new Point(startPoint.X + tickLen2, y));
// if (snapsToDevicePixels)
// {
// yLines.Add(y - 0.5);
// }
}
}
// Draw Selection Ticks
// if (IsSelectionRangeEnabled)
// {
// double y0 = (SelectionStart - Minimum) * logicalToPhysical + startPoint.Y;
// Point pt0 = new Point(startPoint.X, y0);
// Point pt1 = new Point(startPoint.X + tickLen2, y0);
// Point pt2 = new Point(startPoint.X + tickLen2, y0 + Math.Abs(tickLen2) * progression);
// PathSegment[] segments = new PathSegment[] {
// new LineSegment(pt2, true),
// new LineSegment(pt0, true),
// };
// PathGeometry geo = new PathGeometry(new PathFigure[] { new PathFigure(pt1, segments, true) });
// dc.DrawGeometry(Fill, pen, geo);
// y0 = (SelectionEnd - Minimum) * logicalToPhysical + startPoint.Y;
// pt0 = new Point(startPoint.X, y0);
// pt1 = new Point(startPoint.X + tickLen2, y0);
// pt2 = new Point(startPoint.X + tickLen2, y0 - Math.Abs(tickLen2) * progression);
// segments = new PathSegment[] {
// new LineSegment(pt2, true),
// new LineSegment(pt0, true),
// };
// geo = new PathGeometry(new PathFigure[] { new PathFigure(pt1, segments, true) });
// dc.DrawGeometry(Fill, pen, geo);
// }
}
else // Placement == Top || Placement == Bottom
{
// Reduce tick interval if it is more than would be visible on the screen
double interval = TickFrequency;
if (interval > 0.0)
{
double minInterval = (Maximum - Minimum) / size.Width;
if (interval < minInterval)
{
interval = minInterval;
}
}
// Draw Min & Max tick
dc.DrawLine(pen, startPoint, new Point(startPoint.X, startPoint.Y + tickLen));
dc.DrawLine(pen, new Point(endPoint.X, startPoint.Y),
new Point(endPoint.X, startPoint.Y + tickLen));
// if (snapsToDevicePixels)
// {
// xLines.Add(startPoint.X - 0.5);
// yLines.Add(startPoint.Y);
// xLines.Add(startPoint.X - 0.5);
// yLines.Add(endPoint.Y + tickLen);
// yLines.Add(endPoint.Y + tickLen2);
// }
// This property is rarely set so let's try to avoid the GetValue
// caching of the mutable default value
var ticks = Ticks ?? null;
// Draw ticks using specified Ticks collection
if (ticks?.Count > 0)
{
for (int i = 0; i < ticks.Count; i++)
{
if (MathUtilities.LessThanOrClose(ticks[i],Minimum) || MathUtilities.GreaterThanOrClose(ticks[i],Maximum))
{
continue;
}
double adjustedTick = ticks[i] - Minimum;
double x = adjustedTick * logicalToPhysical + startPoint.X;
dc.DrawLine(pen,
new Point(x, startPoint.Y),
new Point(x, startPoint.Y + tickLen2));
// if (snapsToDevicePixels)
// {
// xLines.Add(x - 0.5);
// }
}
}
// Draw ticks using specified TickFrequency
else if (interval > 0.0)
{
for (double i = interval; i < range; i += interval)
{
double x = i * logicalToPhysical + startPoint.X;
dc.DrawLine(pen,
new Point(x, startPoint.Y),
new Point(x, startPoint.Y + tickLen2));
// if (snapsToDevicePixels)
// {
// xLines.Add(x - 0.5);
// }
}
}
// Draw Selection Ticks
// if (IsSelectionRangeEnabled)
// {
// double x0 = (SelectionStart - Minimum) * logicalToPhysical + startPoint.X;
// Point pt0 = new Point(x0, startPoint.Y);
// Point pt1 = new Point(x0, startPoint.Y + tickLen2);
// Point pt2 = new Point(x0 + Math.Abs(tickLen2) * progression, startPoint.Y + tickLen2);
// PathSegment[] segments = new PathSegment[] {
// new LineSegment(pt2, true),
// new LineSegment(pt0, true),
// };
// PathGeometry geo = new PathGeometry(new PathFigure[] { new PathFigure(pt1, segments, true) });
// dc.DrawGeometry(Fill, pen, geo);
// x0 = (SelectionEnd - Minimum) * logicalToPhysical + startPoint.X;
// pt0 = new Point(x0, startPoint.Y);
// pt1 = new Point(x0, startPoint.Y + tickLen2);
// pt2 = new Point(x0 - Math.Abs(tickLen2) * progression, startPoint.Y + tickLen2);
// segments = new PathSegment[] {
// new LineSegment(pt2, true),
// new LineSegment(pt0, true),
// };
// geo = new PathGeometry(new PathFigure[] { new PathFigure(pt1, segments, true) });
// dc.DrawGeometry(Fill, pen, geo);
// }
}
// if (snapsToDevicePixels)
// {
// xLines.Add(Bounds.Width);
// yLines.Add(Bounds.Height);
// VisualXSnappingGuidelines = xLines;
// VisualYSnappingGuidelines = yLines;
// }
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
if (TemplatedParent is Slider parent)
{
this[~TickFrequencyProperty] = parent[~Slider.TickFrequencyProperty];
this[~OrientationProperty] = parent[~Slider.OrientationProperty];
this[~MinimumProperty] = parent[~Slider.MinimumProperty];
this[~MaximumProperty] = parent[~Slider.MaximumProperty];
// if (parent._track != null)
// {
ReservedSpace = new Rect(0, 0, 20, 20); // HACK parent._track.Thumb[~BoundsProperty];
// }
}
}
}
}

34
src/Avalonia.Themes.Fluent/Slider.xaml

@ -48,9 +48,9 @@
<ControlTemplate>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}" Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid x:Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
<ContentPresenter Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}" Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid Name="SliderContainer" Grid.Row="1">
<Grid Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
<Grid.RowDefinitions>
<RowDefinition Height="{DynamicResource SliderPreContentMargin}" />
@ -58,11 +58,11 @@
<RowDefinition Height="{DynamicResource SliderPostContentMargin}" />
</Grid.RowDefinitions>
<!--
<TickBar x:Name="TopTickBar" Visibility="Collapsed" Fill="{DynamicResource SliderTickBarFill}" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
<TickBar x:Name="HorizontalInlineTickBar" Visibility="Collapsed" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" />
<TickBar x:Name="BottomTickBar" Visibility="Collapsed" Fill="{DynamicResource SliderTickBarFill}" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
-->
<TickBar Name="TopTickBar" Placement="Top" Fill="{DynamicResource SliderTickBarFill}" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
<TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" />
<TickBar Name="BottomTickBar" Placement="Bottom" Fill="{DynamicResource SliderTickBarFill}" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
<Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
<Track.DecreaseButton>
@ -109,22 +109,22 @@
<ControlTemplate>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}" Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid x:Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
<ContentPresenter Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}" Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid Name="SliderContainer" Grid.Row="1">
<Grid Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{DynamicResource SliderPreContentMargin}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{DynamicResource SliderPostContentMargin}" />
</Grid.ColumnDefinitions>
<TickBar Name="LeftTickBar" Placement="Left" Fill="{DynamicResource SliderTickBarFill}" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
<TickBar Name="VerticalInlineTickBar" Placement="Left" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" />
<!--
<TickBar x:Name="LeftTickBar" Visibility="Collapsed" Fill="{ThemeResource SliderTickBarFill}" Width="{ThemeResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
<TickBar x:Name="VerticalInlineTickBar" Visibility="Collapsed" Fill="{ThemeResource SliderInlineTickBarFill}" Width="{ThemeResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" />
<TickBar x:Name="RightTickBar" Visibility="Collapsed" Fill="{ThemeResource SliderTickBarFill}" Width="{ThemeResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
-->
<TickBar Name="RightTickBar" Placement="Right" Fill="{DynamicResource SliderTickBarFill}" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
<Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}">

Loading…
Cancel
Save