Уважаемые хабровчане!
Многие кто работал с WPF ощущает необходимость в стандартном компоненте DomainUpDown, который присутствует в WinForms или NumericUpDown из Delphi. В сети существует много примеров и готовых контролов реализующих функционал NumericUpDown, но используя стандартный класс Slider вы можете создать свой собственный NumericUpDown.
По сути принципы работы Slider и NumericUpDown очень похожи, есть минимальное значение и максимальное значение с помощью UI котрола осуществляеться премещение от минимума к максимуму, все разница лишь том какой UI мы будем использовать: ползунок для Slider-а или две кнопки «больше» и «меньше». Задача проста: меняем UI класса Slider и получаем краивую обертку NumericUpDown с сердцем Slider-а.
Создадим простой проект WPF Custom Control Library, далее длянашего контрола пропишем простую обертку:
Многие кто работал с WPF ощущает необходимость в стандартном компоненте DomainUpDown, который присутствует в WinForms или NumericUpDown из Delphi. В сети существует много примеров и готовых контролов реализующих функционал NumericUpDown, но используя стандартный класс Slider вы можете создать свой собственный NumericUpDown.
По сути принципы работы Slider и NumericUpDown очень похожи, есть минимальное значение и максимальное значение с помощью UI котрола осуществляеться премещение от минимума к максимуму, все разница лишь том какой UI мы будем использовать: ползунок для Slider-а или две кнопки «больше» и «меньше». Задача проста: меняем UI класса Slider и получаем краивую обертку NumericUpDown с сердцем Slider-а.
Создадим простой проект WPF Custom Control Library, далее длянашего контрола пропишем простую обертку:
using System.Windows;
using System.Windows.Controls;
namespace MyControls
{
public class UpDownNumeric : Slider
{
static UpDownNumeric()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UpDownNumeric), new FrameworkPropertyMetadata(typeof(UpDownNumeric)));
}
}
}
* This source code was highlighted with Source Code Highlighter.
Теперь спокойно под этот контрол пишем XAML код для реализации UI NumericUpDown.
Сначала добавим пару кистей для нашего контрола:
<LinearGradientBrush x:Key="ButtonBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFF1F3F3" Offset="0"/>
<GradientStop Color="#FFF0F2F2" Offset="0.5"/>
<GradientStop Color="#FFE7EAEE" Offset="0.5"/>
<GradientStop Color="#FFF6F7F8" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HighlightedPressedButtonBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFFDD4A8" Offset="0"/>
<GradientStop Color="#FFFBAE60" Offset="0.4"/>
<GradientStop Color="#FFF9972F" Offset="0.4"/>
<GradientStop Color="#FFFDE499" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="HighlightedMouseOverButtonBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFFFFDDC" Offset="0"/>
<GradientStop Color="#FFFFE797" Offset="0.4"/>
<GradientStop Color="#FFFFD754" Offset="0.4"/>
<GradientStop Color="#FFFFE89F" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
* This source code was highlighted with Source Code Highlighter.
Создадим шаблоны для кнопок Up и Down:
<Style x:Key="UpButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="true"/>
<Setter Property="Height" Value="11"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Name="Border" Background="{StaticResource ButtonBackgroundBrush}" BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1">
<Path
x:Name="Arrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,3 L3,0 6,3 z" Fill="Black"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource HighlightedMouseOverButtonBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource HighlightedPressedButtonBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DownButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="true"/>
<Setter Property="Height" Value="11"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Name="Border" Background="{StaticResource ButtonBackgroundBrush}" BorderBrush="{StaticResource SolidBorderBrush}" BorderThickness="1">
<Path
x:Name="Arrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L3,3 6,0 z" Fill="Black"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource HighlightedMouseOverButtonBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource HighlightedPressedButtonBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
* This source code was highlighted with Source Code Highlighter.
Тут стоит пояснить зачем нужны эти две кнопки. В обычном Slider-е эти кнопки не видны пользователю, они прозрачные и располагаються на Track-е Slider-а, нажимая на слева или справа от ползунка Slider-а пользователь перемещает ползунок влева или вправо, эту функцию выполняют эти кнопки. Если их сделать видимыми и расположить там где нужно нам, то получим нужный нам визуальный функционал!
Теперь составляем стиль слайдера так что бы он был похож на NumericUpDown: нам нужен TextBox для вывода и ввода значения Value нашего контрола и Track для реализации механики, к кнопкам Track-а IncreaseRepeatButton и DecreaseRepeatButton привязываем стили UpButtonStyle и DownButtonStyle; перед кнопками распологаем TextBox и привязываем к свойству Text свойство Value нашего NumericUpDown:
<Style TargetType="{x:Type btc:BlackThemeUpDownNumeric}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Height" Value="20"/>
<Setter Property="MinWidth" Value="50"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Slider}">
<Grid>
<Border BorderThickness="1,1,1,1" CornerRadius="2" BorderBrush="{StaticResource SolidBorderBrush}" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
Focusable="False">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="17"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="PART_EditableTextBox" Grid.Column="0"
Text="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}}"
IsHitTestVisible="True"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Focusable="True"
Background="White"
Visibility="Visible"
Foreground="Black" BorderThickness="0" Margin="-1,-1,-1,-1"/>
<Grid Grid.Column="1" Margin="0,-1,-1,-1">
<Track Name="PART_Track" Orientation="Vertical" Height="0">
<Track.IncreaseRepeatButton>
<RepeatButton
Style="{StaticResource UpButtonStyle}"
Command="Slider.IncreaseLarge" Margin="0,-10,0,0"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Height="0" />
</Track.Thumb>
<Track.DecreaseRepeatButton>
<RepeatButton Margin="0,0,0,-10"
Style="{StaticResource DownButtonStyle}"
Command="Slider.DecreaseLarge" />
</Track.DecreaseRepeatButton>
</Track>
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
* This source code was highlighted with Source Code Highlighter.
У вас должно получиться что то вроде этого:
