[C#/WPF] FrameworkElement 클래스 : DefaultStyleKeyProperty 속성을 사용해 컨트롤 테마 스타일 설정하기
C#/WPF 2020. 8. 3. 02:51728x90
반응형
728x170
■ FrameworkElement 클래스의 DefaultStyleKeyProperty 속성을 사용해 컨트롤의 테마 스타일을 설정하는 방법을 보여준다.
▶ 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 x:Key="SliderRepeatButtonStyleKey" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type local:ColorThumb}" TargetType="{x:Type local:ColorThumb}">
<Setter Property="PointerOutlineBrush" Value="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" />
<Setter Property="PointerOutlineThickness" Value="2" />
<Setter Property="Foreground" Value="{x:Null}" />
<Setter Property="ThumbColor" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ColorThumb}">
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<Polygon Name="arrowPolygon"
Stroke="{TemplateBinding PointerOutlineBrush}"
StrokeThickness="{TemplateBinding PointerOutlineThickness}"
Stretch="Fill"
Points="100 20 80 50 100 80">
<Polygon.Fill>
<SolidColorBrush
Color="{Binding ThumbColor, RelativeSource={RelativeSource TemplatedParent}}" />
</Polygon.Fill>
</Polygon>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsDragging" Value="False">
<Setter TargetName="arrowPolygon" Property="BitmapEffect">
<Setter.Value>
<BitmapEffectGroup>
<BevelBitmapEffect BevelWidth="5" Relief="0.5" />
<DropShadowBitmapEffect />
</BitmapEffectGroup>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type local:SpectrumSlider}" TargetType="{x:Type local:SpectrumSlider}">
<Setter Property="Orientation" Value="Vertical" />
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="Minimum" Value="0" />
<Setter Property="Maximum" Value="100" />
<Setter Property="TickFrequency" Value="0.001" />
<Setter Property="IsSnapToTickEnabled" Value="True" />
<Setter Property="IsDirectionReversed" Value="False" />
<Setter Property="Value" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SpectrumSlider}">
<Border
Height="{TemplateBinding Height}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" MinWidth="{TemplateBinding Slider.MinWidth}" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border x:Name="PART_TrackBackground" Grid.Column="1"
Margin="10 0 10 0"
Width="20">
<Rectangle x:Name="PART_SpectrumDisplay"
Stretch="Fill"
VerticalAlignment="Stretch" />
<Border.BitmapEffect>
<BevelBitmapEffect
BevelWidth="3"
EdgeProfile="BulgedUp"
Relief="0.3" />
</Border.BitmapEffect>
</Border>
<Canvas Grid.Column="1"
HorizontalAlignment="Center"
Width="4">
<Rectangle x:Name="PART_SelectionRange" Canvas.Left="1"
Width="2.0"
Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"
Visibility="Hidden" />
</Canvas>
<Track Name="PART_Track" Grid.Column="1">
<Track.DecreaseRepeatButton>
<RepeatButton
Style="{StaticResource SliderRepeatButtonStyleKey}"
Command="Slider.DecreaseLarge" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton
Style="{StaticResource SliderRepeatButtonStyleKey}"
Command="Slider.IncreaseLarge" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<local:ColorThumb x:Name="Thumb"
Height="20"
ThumbColor="{Binding SelectedColor, RelativeSource={RelativeSource TemplatedParent}}" />
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter TargetName="PART_SelectionRange" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="Width" Value="Auto">
<Setter Property="MinWidth" Value="21" />
</Trigger>
<Trigger Property="Height" Value="Auto">
<Setter Property="MinHeight" Value="104" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
▶ SpectrumSlider.cs
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
namespace TestProject
{
/// <summary>
/// 스펙트럼 슬라이더
/// </summary>
public class SpectrumSlider : Slider
{
//////////////////////////////////////////////////////////////////////////////////////////////////// DependencyProperty
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 선택 색상 속성 - SelectedColorProperty
/// <summary>
/// 선택 색상 속성
/// </summary>
private static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register
(
"SelectedColor",
typeof(Color),
typeof(SpectrumSlider),
new PropertyMetadata(Colors.Transparent)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 스펙트럼 표시명
/// </summary>
private static string SPECTRUN_DISPLAY_NAME = "PART_SpectrumDisplay";
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 스펙트럼 표시 사각형
/// </summary>
private Rectangle spectrumDisplayRectangle;
/// <summary>
/// 색상 초기화 여부
/// </summary>
private bool colorInitialized = false;
/// <summary>
/// 선택기 브러시
/// </summary>
private LinearGradientBrush pickerBrush;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 선택 색상 - SelectedColor
/// <summary>
/// 선택 색상
/// </summary>
public Color SelectedColor
{
get
{
return (Color)GetValue(SelectedColorProperty);
}
set
{
SetValue(SelectedColorProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - SpectrumSlider()
/// <summary>
/// 생성자
/// </summary>
static SpectrumSlider()
{
DefaultStyleKeyProperty.OverrideMetadata
(
typeof(SpectrumSlider),
new FrameworkPropertyMetadata(typeof(SpectrumSlider))
);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 템플리트 적용시 처리하기 - OnApplyTemplate()
/// <summary>
/// 템플리트 적용시 처리하기
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.spectrumDisplayRectangle = GetTemplateChild(SPECTRUN_DISPLAY_NAME) as Rectangle;
if(!this.colorInitialized)
{
UpdateColorSpectrum();
OnValueChanged(0, 0);
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 값 변경시 처리하기 - OnValueChanged(previousValue, newValue)
/// <summary>
/// 값 변경시 처리하기
/// </summary>
/// <param name="previousValue">이전 값</param>
/// <param name="newValue">신규 값</param>
protected override void OnValueChanged(double previousValue, double newValue)
{
base.OnValueChanged(previousValue, newValue);
Color? color = ColorHelper.GetColor(360 - newValue, 1, 1);
SetValue(SelectedColorProperty, color);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 스펙트럼 생성하기 - CreateSpectrum()
/// <summary>
/// 스펙트럼 생성하기
/// </summary>
private void CreateSpectrum()
{
this.pickerBrush = new LinearGradientBrush();
this.pickerBrush.ColorInterpolationMode = ColorInterpolationMode.SRgbLinearInterpolation;
this.pickerBrush.StartPoint = new Point(0.5, 0);
this.pickerBrush.EndPoint = new Point(0.5, 1);
List<Color> colorList = ColorHelper.GetHSVColorList();
double stopIncrement = (double)1 / colorList.Count;
int i;
for(i = 0; i < colorList.Count; i++)
{
this.pickerBrush.GradientStops.Add(new GradientStop(colorList[i], i * stopIncrement));
}
this.pickerBrush.GradientStops[i - 1].Offset = 1.0;
this.spectrumDisplayRectangle.Fill = pickerBrush;
}
#endregion
#region 색상 스펙트럼 업데이트하기 - UpdateColorSpectrum()
/// <summary>
/// 색상 스펙트럼 업데이트하기
/// </summary>
private void UpdateColorSpectrum()
{
if(this.spectrumDisplayRectangle != null)
{
this.colorInitialized = true;
CreateSpectrum();
}
else
{
this.colorInitialized = false;
}
}
#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="FrameworkElement 클래스 : DefaultStyleKeyProperty 속성을 사용해 컨트롤 테마 스타일 설정하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<local:SpectrumSlider x:Name="slider"
Width="40"
Height="300"
IsMoveToPointEnabled="True"
IsSnapToTickEnabled="False"
Maximum="360"
Value="0" />
<Label
HorizontalAlignment="Center"
Content="{Binding ElementName=slider, Path=Value}" />
</StackPanel>
</Grid>
</Window>
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] Application 클래스 : MainWindow 속성을 사용해 메인 윈도우 구하기 (0) | 2020.08.03 |
---|---|
[C#/WPF] MouseButtonEventArgs 클래스 : GetPosition 메소드를 사용해 마우스 좌표 구하기 (0) | 2020.08.03 |
[C#/WPF] Shape 엘리먼트 : StrokeDashArray/StrokeDashOffset 속성 사용하기 (0) | 2020.08.03 |
[C#/WPF] RadialGradientBrush 엘리먼트 사용하기 (0) | 2020.08.03 |
[C#/WPF] ContentControl 엘리먼트 : Style 속성 사용하기 (0) | 2020.08.03 |
[C#/WPF] FrameworkElement 엘리먼트 : OverridesDefaultStyle 속성을 사용해 테마 스타일 사용하기 (0) | 2020.08.03 |
[C#/WPF] DrawingBrush 엘리먼트 : GeometryDrawing 객체를 사용해 체크 배경 브러시 만들기 (0) | 2020.08.02 |
[C#/WPF] HSV 색상에서 RGB 색상 구하기 (0) | 2020.08.02 |
[C#/WPF] 색상 선택기 사용하기 (0) | 2020.08.02 |
[C#/WPF] LinearGradientBrush 클래스 : 속성 값 변경하기 (0) | 2020.08.01 |
댓글을 달아 주세요