728x90
반응형
728x170
■ Control 클래스를 사용해 사용자 지정 가능한 모양을 가진 컨트롤을 만드는 방법을 보여준다.
▶ THEME\generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject">
<Style TargetType="{x:Type local:NumericUpDownControl}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:NumericUpDownControl}">
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Grid.RowSpan="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Margin="2"
BorderThickness="1"
BorderBrush="Gray">
<TextBlock
Width="60"
Padding="5"
TextAlignment="Right"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value}" />
</Border>
<RepeatButton Grid.Row="0" Grid.Column="1"
Command="{x:Static local:NumericUpDownControl.IncreaseCommand}">
Up
</RepeatButton>
<RepeatButton Grid.Row="1" Grid.Column="1"
Command="{x:Static local:NumericUpDownControl.DecreaseCommand}">
Down
</RepeatButton>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
▶ NumericUpDownControl.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TestProject
{
/// <summary>
/// 숫자 UP/DOWN 컨트롤
/// </summary>
public partial class NumericUpDownControl : Control
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Routed Event
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 값 변경시 이벤트 - ValueChangedEvent
/// <summary>
/// 값 변경시 이벤트
/// </summary>
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent
(
"ValueChanged",
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<decimal>),
typeof(NumericUpDownControl)
);
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 값 변경시 이벤트 - ValueChanged
/// <summary>
/// 값 변경시 이벤트
/// </summary>
public event RoutedPropertyChangedEventHandler<decimal> ValueChanged
{
add
{
AddHandler(ValueChangedEvent, value);
}
remove
{
RemoveHandler(ValueChangedEvent, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Dependent Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 값 속성 - ValueProperty
/// <summary>
/// 값 속성
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register
(
"Value",
typeof(decimal),
typeof(NumericUpDownControl),
new FrameworkPropertyMetadata
(
MinimumValue,
new PropertyChangedCallback(ValuePropertyChangedCallback),
new CoerceValueCallback(ValuePropertyCoerceValueCallback)
)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 증가 명령
/// </summary>
private static RoutedCommand _increaseCommand;
/// <summary>
/// 감소 명령
/// </summary>
private static RoutedCommand _decreaseCommand;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 최소 값
/// </summary>
private const decimal MinimumValue = 0;
/// <summary>
/// 최대 값
/// </summary>
private const decimal MaximumValue = 100;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 증가 명령 - IncreaseCommand
/// <summary>
/// 증가 명령
/// </summary>
public static RoutedCommand IncreaseCommand
{
get
{
return _increaseCommand;
}
}
#endregion
#region 감소 명령 - DecreaseCommand
/// <summary>
/// 감소 명령
/// </summary>
public static RoutedCommand DecreaseCommand
{
get
{
return _decreaseCommand;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 값 - Value
/// <summary>
/// 값
/// </summary>
public decimal Value
{
get
{
return (decimal)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - NumericUpDownControl()
/// <summary>
/// 생성자
/// </summary>
static NumericUpDownControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDownControl), new FrameworkPropertyMetadata(typeof(NumericUpDownControl)));
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - NumericUpDownControl()
/// <summary>
/// 생성자
/// </summary>
public NumericUpDownControl()
{
_increaseCommand = new RoutedCommand("IncreaseCommand", typeof(NumericUpDownControl));
_decreaseCommand = new RoutedCommand("DecreaseCommand", typeof(NumericUpDownControl));
CommandManager.RegisterClassCommandBinding(typeof(NumericUpDownControl), new CommandBinding(_increaseCommand, ProcessIncreaseCommand));
CommandManager.RegisterClassCommandBinding(typeof(NumericUpDownControl), new CommandBinding(_decreaseCommand, ProcessDecreaseCommand));
CommandManager.RegisterClassInputBinding(typeof(NumericUpDownControl), new InputBinding(_increaseCommand, new KeyGesture(Key.Up )));
CommandManager.RegisterClassInputBinding(typeof(NumericUpDownControl), new InputBinding(_decreaseCommand, new KeyGesture(Key.Down)));
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 값 속성 변경시 콜백 처리하기 - ValuePropertyChangedCallback(d, e)
/// <summary>
/// 값 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void ValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
NumericUpDownControl control = (NumericUpDownControl)d;
RoutedPropertyChangedEventArgs<decimal> routedPropertyChangedEventArgs = new RoutedPropertyChangedEventArgs<decimal>
(
(decimal)e.OldValue,
(decimal)e.NewValue,
ValueChangedEvent
);
control.ProcessValueChanged(routedPropertyChangedEventArgs);
}
#endregion
#region 값 속성 값 강제시 처리하기 - ValuePropertyCoerceValueCallback(d, value)
/// <summary>
/// 값 속성 값 강제시 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="value">값</param>
/// <returns>처리 값</returns>
private static object ValuePropertyCoerceValueCallback(DependencyObject d, object value)
{
decimal newValue = (decimal)value;
newValue = Math.Max(MinimumValue, Math.Min(MaximumValue, newValue));
return newValue;
}
#endregion
#region 증가 명령 처리하기 - ProcessIncreaseCommand(sender, e)
/// <summary>
/// 증가 명령 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private static void ProcessIncreaseCommand(object sender, ExecutedRoutedEventArgs e)
{
NumericUpDownControl control = sender as NumericUpDownControl;
if(control != null)
{
control.Increase();
}
}
#endregion
#region 감소 명령 처리하기 - ProcessDecreaseCommand(sender, e)
/// <summary>
/// 감소 명령 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private static void ProcessDecreaseCommand(object sender, ExecutedRoutedEventArgs e)
{
NumericUpDownControl control = sender as NumericUpDownControl;
if(control != null)
{
control.Decrease();
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Protected
#region 값 변경시 처리하기 - ProcessValueChanged(e)
/// <summary>
/// 값 변경시 처리하기
/// </summary>
/// <param name="e">이벤트 인자</param>
protected virtual void ProcessValueChanged(RoutedPropertyChangedEventArgs<decimal> e)
{
RaiseEvent(e);
}
#endregion
#region 증가하기 - Increase()
/// <summary>
/// 증가하기
/// </summary>
protected virtual void Increase()
{
Value++;
}
#endregion
#region 감소하기 - Decrease()
/// <summary>
/// 감소하기
/// </summary>
protected virtual void Decrease()
{
Value--;
}
#endregion
}
}
▶ MainWindow.xaml
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject"
Width="800"
Height="600"
Title="TestProject"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid>
<local:NumericUpDownControl />
</Grid>
</Window>
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] ControlTemplate 엘리먼트 : ContextMenu 엘리먼트 정의하기 (0) | 2023.01.23 |
---|---|
[C#/WPF] ControlTemplate 엘리먼트 : ComboBox 엘리먼트 정의하기 (0) | 2023.01.23 |
[C#/WPF] ControlTemplate 엘리먼트 : CheckBox 엘리먼트 정의하기 (0) | 2023.01.23 |
[C#/WPF] ControlTemplate 엘리먼트 : Calendar 엘리먼트 정의하기 (0) | 2023.01.22 |
[C#/WPF] ControlTemplate 엘리먼트 : 비주얼 상태와 트리거를 사용해 Button 엘리먼트 정의하기 (0) | 2023.01.22 |
[C#/WPF] Application 클래스 : LoadComponent 정적 메소드를 사용해 리소스 딕셔너리 구하기 (0) | 2023.01.21 |
[C#/WPF] ControlTemplate 엘리먼트 : 마우스 위치시 배경색이 변경되는 Button 엘리먼트 정의하기 (0) | 2023.01.20 |
[C#/WPF] HierarchicalDataTemplate 엘리먼트 : DataType 속성을 사용해 트리 만들기 (0) | 2023.01.20 |
[C#/WPF] ToolTipService 엘리먼트 : 툴팁 표시하기 (0) | 2023.01.19 |
[C#/WPF] ToolTip 엘리먼트 : Placement/PlacementRectangle 속성 사용하기 (0) | 2023.01.19 |
댓글을 달아 주세요