728x90
반응형
728x170
▶ HSVColor.cs
namespace TestProject
{
/// <summary>
/// HSV 색상
/// </summary>
public struct HSVColor
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 색상
/// </summary>
public double H;
/// <summary>
/// 채도
/// </summary>
public double S;
/// <summary>
/// 명도
/// </summary>
public double V;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - HSVColor(hue, saturation, value)
/// <summary>
/// 생성자
/// </summary>
/// <param name="hue">색상</param>
/// <param name="saturation">채도</param>
/// <param name="value">명도</param>
public HSVColor(double hue, double saturation, double value)
{
H = hue;
S = saturation;
V = value;
}
#endregion
}
}
728x90
▶ ColorHelper.cs
using System;
using System.Collections.Generic;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 헬퍼
/// </summary>
static class ColorHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region HSV 색상 구하기 - GetHSVColor(red, blue, green)
/// <summary>
/// HSV 색상 구하기
/// </summary>
/// <param name="red">빨간색</param>
/// <param name="blue">파란색</param>
/// <param name="green">녹색</param>
/// <returns>HSV 색상</returns>
public static HSVColor GetHSVColor(int red, int blue, int green)
{
System.Drawing.Color otherColor = System.Drawing.Color.FromArgb(255, red, blue, green);
return new HSVColor
(
otherColor.GetHue(),
otherColor.GetSaturation(),
otherColor.GetBrightness()
);
}
#endregion
#region 색상 구하기 - GetColor(hue, saturation, value)
/// <summary>
/// 색상 구하기
/// </summary>
/// <param name="hue">색상</param>
/// <param name="saturation">채도</param>
/// <param name="value">명도</param>
/// <returns>색상</returns>
public static Color GetColor(double hue, double saturation, double value)
{
double red = 0;
double green = 0;
double blue = 0;
if(saturation == 0)
{
red = value;
green = value;
blue = value;
}
else
{
int i;
double f;
double p;
double q;
double t;
if(hue == 360)
{
hue = 0;
}
else
{
hue = hue / 60;
}
i = (int)Math.Truncate(hue);
f = hue - i;
p = value * (1.0 - saturation);
q = value * (1.0 - (saturation * f));
t = value * (1.0 - (saturation * (1.0 - f)));
switch (i)
{
case 0 :
red = value;
green = t;
blue = p;
break;
case 1 :
red = q;
green = value;
blue = p;
break;
case 2 :
red = p;
green = value;
blue = t;
break;
case 3 :
red = p;
green = q;
blue = value;
break;
case 4 :
red = t;
green = p;
blue = value;
break;
default :
red = value;
green = p;
blue = q;
break;
}
}
return Color.FromArgb(255, (byte)(red * 255), (byte)(green * 255), (byte)(blue * 255));
}
#endregion
#region HSV 색상 리스트 구하기 - GetHSVColorList()
/// <summary>
/// HSV 색상 리스트 구하기
/// </summary>
/// <returns>HSV 색상 리스트</returns>
public static List<Color> GetHSVColorList()
{
List<Color> colorList = new List<Color>(8);
for(int i = 0; i < 59; i++)
{
colorList.Add(ColorHelper.GetColor(i * 6, 1, 1));
}
colorList.Add(ColorHelper.GetColor(0, 1, 1));
return colorList;
}
#endregion
}
}
300x250
▶ ColorThumb.cs
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 썸
/// </summary>
public class ColorThumb : Thumb
{
//////////////////////////////////////////////////////////////////////////////////////////////////// DependencyProperty
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 썸 색상 속성 - ThumbColorProperty
/// <summary>
/// 썸 색상 속성
/// </summary>
public static readonly DependencyProperty ThumbColorProperty = DependencyProperty.Register
(
"ThumbColor",
typeof(Color),
typeof(ColorThumb),
new FrameworkPropertyMetadata(Colors.Transparent)
);
#endregion
#region 포인터 윤곽선 두께 속성 - PointerOutlineThicknessProperty
/// <summary>
/// 포인터 윤곽선 두께 속성
/// </summary>
public static readonly DependencyProperty PointerOutlineThicknessProperty = DependencyProperty.Register
(
"PointerOutlineThickness",
typeof(double),
typeof(ColorThumb),
new FrameworkPropertyMetadata(1.0)
);
#endregion
#region 포인터 윤곽선 브러시 속성 - PointerOutlineBrushProperty
/// <summary>
/// 포인터 윤곽선 브러시 속성
/// </summary>
public static readonly DependencyProperty PointerOutlineBrushProperty = DependencyProperty.Register
(
"PointerOutlineBrush",
typeof(Brush),
typeof(ColorThumb),
new FrameworkPropertyMetadata(null)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 썸 색상 - ThumbColor
/// <summary>
/// 썸 색상
/// </summary>
public Color ThumbColor
{
get
{
return (Color)GetValue(ThumbColorProperty);
}
set
{
SetValue(ThumbColorProperty, value);
}
}
#endregion
#region 포인터 윤곽선 두께 - PointerOutlineThickness
/// <summary>
/// 포인터 윤곽선 두께
/// </summary>
public double PointerOutlineThickness
{
get
{
return (double)GetValue(PointerOutlineThicknessProperty);
}
set
{
SetValue(PointerOutlineThicknessProperty, value);
}
}
#endregion
#region 포인터 윤곽선 브러시 - PointerOutlineBrush
/// <summary>
/// 포인터 윤곽선 브러시
/// </summary>
public Brush PointerOutlineBrush
{
get
{
return (Brush)GetValue(PointerOutlineBrushProperty);
}
set
{
SetValue(PointerOutlineBrushProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorThumb()
/// <summary>
/// 생성자
/// </summary>
static ColorThumb()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorThumb), new FrameworkPropertyMetadata(typeof(ColorThumb)));
}
#endregion
}
}
▶ 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
}
}
▶ ColorPicker.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Input;
namespace TestProject
{
/// <summary>
/// 색상 선택기
/// </summary>
public class ColorPicker : Control
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 선택 색상 변경시 이벤트 - SelectedColorChanged
/// <summary>
/// 선택 색상 변경시 이벤트
/// </summary>
public event RoutedPropertyChangedEventHandler<Color> SelectedColorChanged
{
add
{
AddHandler(SelectedColorChangedEvent, value);
}
remove
{
RemoveHandler(SelectedColorChangedEvent, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 선택 색상 변경시 이벤트 - SelectedColorChangedEvent
/// <summary>
/// 선택 색상 변경시 이벤트
/// </summary>
public static readonly RoutedEvent SelectedColorChangedEvent = EventManager.RegisterRoutedEvent
(
"SelectedColorChanged",
RoutingStrategy.Bubble,
typeof(RoutedPropertyChangedEventHandler<Color>),
typeof(ColorPicker)
);
#endregion
#region 선택 색상 속성 - SelectedColorProperty
/// <summary>
/// 선택 색상 속성
/// </summary>
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register
(
"SelectedColor",
typeof(Color),
typeof(ColorPicker),
new PropertyMetadata
(
Colors.Transparent,
new PropertyChangedCallback(SelectedColorPropertyChangedCallback)
)
);
#endregion
#region ScA 속성 - ScAProperty
/// <summary>
/// ScA 속성
/// </summary>
public static readonly DependencyProperty ScAProperty = DependencyProperty.Register
(
"ScA",
typeof(float),
typeof(ColorPicker),
new PropertyMetadata
(
(float)1,
new PropertyChangedCallback(ScAPropertyChangedCallback)
)
);
#endregion
#region ScR 속성 - ScRProperty
/// <summary>
/// ScR 속성
/// </summary>
public static readonly DependencyProperty ScRProperty = DependencyProperty.Register
(
"ScR",
typeof(float),
typeof(ColorPicker),
new PropertyMetadata
(
(float)1,
new PropertyChangedCallback(ScRPropertyChangedCallback)
)
);
#endregion
#region ScG 속성 - ScGProperty
/// <summary>
/// ScG 속성
/// </summary>
public static readonly DependencyProperty ScGProperty = DependencyProperty.Register
(
"ScG",
typeof(float),
typeof(ColorPicker),
new PropertyMetadata
(
(float)1,
new PropertyChangedCallback(ScGPropertyChangedCallback)
)
);
#endregion
#region ScB 속성 - ScBProperty
/// <summary>
/// ScB 속성
/// </summary>
public static readonly DependencyProperty ScBProperty = DependencyProperty.Register
(
"ScB",
typeof(float),
typeof(ColorPicker),
new PropertyMetadata
(
(float)1,
new PropertyChangedCallback(ScBPropertyChangedCallback)
)
);
#endregion
#region A 속성 - AProperty
/// <summary>
/// A 속성
/// </summary>
public static readonly DependencyProperty AProperty = DependencyProperty.Register
(
"A",
typeof(byte),
typeof(ColorPicker),
new PropertyMetadata
(
(byte)255,
new PropertyChangedCallback(APropertyChangedCallback)
)
);
#endregion
#region R 속성 - RProperty
/// <summary>
/// R 속성
/// </summary>
public static readonly DependencyProperty RProperty = DependencyProperty.Register
(
"R",
typeof(byte),
typeof(ColorPicker),
new PropertyMetadata
(
(byte)255,
new PropertyChangedCallback(RPropertyChangedCallback)
)
);
#endregion
#region G 속성 - GProperty
/// <summary>
/// G 속성
/// </summary>
public static readonly DependencyProperty GProperty = DependencyProperty.Register
(
"G",
typeof(byte),
typeof(ColorPicker),
new PropertyMetadata
(
(byte)255,
new PropertyChangedCallback(GPropertyChangedCallback)
)
);
#endregion
#region B 속성 - BProperty
/// <summary>
/// B 속성
/// </summary>
public static readonly DependencyProperty BProperty = DependencyProperty.Register
(
"B",
typeof(byte),
typeof(ColorPicker),
new PropertyMetadata
(
(byte)255,
new PropertyChangedCallback(BPropertyChangedCallback)
)
);
#endregion
#region 16진수 문자열 속성 - HexadecimalStringProperty
/// <summary>
/// 16진수 문자열 속성
/// </summary>
public static readonly DependencyProperty HexadecimalStringProperty = DependencyProperty.Register
(
"HexadecimalString",
typeof(string),
typeof(ColorPicker),
new PropertyMetadata
(
"#FFFFFFFF",
new PropertyChangedCallback(HexadecimalStringPropertyChangedCallback)
)
);
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 색상 슬라이더명
/// </summary>
private static readonly string COLOR_SLIDER_NAME = "PART_ColorSlider";
/// <summary>
/// 색상 상세명
/// </summary>
private static readonly string COLOR_DETAIL_NAME = "PART_ColorDetail";
/// <summary>
/// 색상 마커명
/// </summary>
private static readonly string COLOR_MARKER_NAME = "PART_ColorMarker";
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 스펙트럼 슬라이더
/// </summary>
private SpectrumSlider spectrumSlider;
/// <summary>
/// 색상 상세 프레임워크 엘리먼트
/// </summary>
private FrameworkElement colorDetailFrameworkElement;
/// <summary>
/// 마커 이동 변환
/// </summary>
private TranslateTransform markerTranslateTransform = new TranslateTransform();
/// <summary>
/// 색상 마커 패스
/// </summary>
private Path colorMarkerPath;
/// <summary>
/// 색상 포인트
/// </summary>
private Point? colorPoint;
/// <summary>
/// 색상
/// </summary>
private Color color;
/// <summary>
/// 포인트 찾기 여부
/// </summary>
private bool shouldFindPoint;
/// <summary>
/// 알파 변경 여부
/// </summary>
private bool isAlphaChange;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 선택 색상 - SelectedColor
/// <summary>
/// 선택 색상
/// </summary>
public Color SelectedColor
{
get
{
return (Color)GetValue(SelectedColorProperty);
}
set
{
SetColor((Color)value);
}
}
#endregion
#region ScA - ScA
/// <summary>
/// ScA
/// </summary>
public double ScA
{
get
{
return (double)GetValue(ScAProperty);
}
set
{
SetValue(ScAProperty, value);
}
}
#endregion
#region ScR - ScR
/// <summary>
/// ScR
/// </summary>
public double ScR
{
get
{
return (double)GetValue(ScRProperty);
}
set
{
SetValue(RProperty, value);
}
}
#endregion
#region ScG - ScG
/// <summary>
/// ScG
/// </summary>
public double ScG
{
get
{
return (double)GetValue(ScGProperty);
}
set
{
SetValue(GProperty, value);
}
}
#endregion
#region ScB - ScB
/// <summary>
/// ScB
/// </summary>
public double ScB
{
get
{
return (double)GetValue(BProperty);
}
set
{
SetValue(BProperty, value);
}
}
#endregion
#region A - A
/// <summary>
/// A
/// </summary>
public byte A
{
get
{
return (byte)GetValue(AProperty);
}
set
{
SetValue(AProperty, value);
}
}
#endregion
#region R - R
/// <summary>
/// R
/// </summary>
public byte R
{
get
{
return (byte)GetValue(RProperty);
}
set
{
SetValue(RProperty, value);
}
}
#endregion
#region G - G
/// <summary>
/// G
/// </summary>
public byte G
{
get
{
return (byte)GetValue(GProperty);
}
set
{
SetValue(GProperty, value);
}
}
#endregion
#region B - B
/// <summary>
/// B
/// </summary>
public byte B
{
get
{
return (byte)GetValue(BProperty);
}
set
{
SetValue(BProperty, value);
}
}
#endregion
#region 16진수 문자열 - HexadecimalString
/// <summary>
/// 16진수 문자열
/// </summary>
public string HexadecimalString
{
get
{
return (string)GetValue(HexadecimalStringProperty);
}
set
{
SetValue(HexadecimalStringProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - ColorPicker()
/// <summary>
/// 생성자
/// </summary>
static ColorPicker()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorPicker()
/// <summary>
/// 생성자
/// </summary>
public ColorPicker()
{
this.color = Colors.White;
this.shouldFindPoint = true;
SetValue(AProperty, this.color.A);
SetValue(RProperty, this.color.R);
SetValue(GProperty, this.color.G);
SetValue(BProperty, this.color.B);
SetValue(SelectedColorProperty, this.color);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 선택 색상 속성 변경시 콜백 처리하기 - SelectedColorPropertyChangedCallback(d, e)
/// <summary>
/// 선택 색상 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void SelectedColorPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnSelectedColorChanged((Color)e.OldValue, (Color)e.NewValue);
}
#endregion
#region ScA 속성 변경시 콜백 처리하기 - ScAPropertyChangedCallback(d, e)
/// <summary>
/// ScA 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void ScAPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnScAChanged((float)e.NewValue);
}
#endregion
#region ScB 속성 변경시 콜백 처리하기 - ScRPropertyChangedCallback(d, e)
/// <summary>
/// ScB 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void ScRPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnScRChanged((float)e.NewValue);
}
#endregion
#region ScG 속성 변경시 콜백 처리하기 - ScGPropertyChangedCallback(d, e)
/// <summary>
/// ScG 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void ScGPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnScGChanged((float)e.NewValue);
}
#endregion
#region ScB 속성 변경시 콜백 처리하기 - ScBPropertyChangedCallback(d, e)
/// <summary>
/// ScB 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void ScBPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnScBChanged((float)e.NewValue);
}
#endregion
#region A 속성 변경시 콜백 처리하기 - APropertyChangedCallback(d, e)
/// <summary>
/// A 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void APropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnAChanged((byte)e.NewValue);
}
#endregion
#region R 속성 변경시 콜백 처리하기 - RPropertyChangedCallback(d, e)
/// <summary>
/// R 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void RPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnRChanged((byte)e.NewValue);
}
#endregion
#region G 속성 변경시 콜백 처리하기 - GPropertyChangedCallback(d, e)
/// <summary>
/// G 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void GPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnGChanged((byte)e.NewValue);
}
#endregion
#region B 속성 변경시 콜백 처리하기 - BPropertyChangedCallback(d, e)
/// <summary>
/// B 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void BPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnBChanged((byte)e.NewValue);
}
#endregion
#region 16진수 문자열 속성 변경시 콜백 처리하기 - HexadecimalStringPropertyChangedCallback(d, e)
/// <summary>
/// 16진수 문자열 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void HexadecimalStringPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ColorPicker colorPicker = d as ColorPicker;
colorPicker.OnHexadecimalStringChanged((string)e.NewValue);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 템플리트 적용시 처리하기 - OnApplyTemplate()
/// <summary>
/// 템플리트 적용시 처리하기
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.colorDetailFrameworkElement = GetTemplateChild(COLOR_DETAIL_NAME) as FrameworkElement;
this.colorMarkerPath = GetTemplateChild(COLOR_MARKER_NAME) as Path;
this.spectrumSlider = GetTemplateChild(COLOR_SLIDER_NAME) as SpectrumSlider;
this.spectrumSlider.ValueChanged += spectrumSlider_ValueChanged;
this.colorMarkerPath.RenderTransform = this.markerTranslateTransform;
this.colorMarkerPath.RenderTransformOrigin = new Point(0.5, 0.5);
this.colorDetailFrameworkElement.SizeChanged += colorDetailFrameworkElement_SizeChanged;
this.colorDetailFrameworkElement.MouseLeftButtonDown += colorDetailFrameworkElement_MouseLeftButtonDown;
this.colorDetailFrameworkElement.PreviewMouseMove += colorDetailFrameworkElement_MouseMove;
this.shouldFindPoint = true;
SetColor(SelectedColor);
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Protected
#region 선택 색상 변경시 처리하기 - OnSelectedColorChanged(previousColor, newColor)
/// <summary>
/// 선택 색상 변경시 처리하기
/// </summary>
/// <param name="previousColor">이전 색상</param>
/// <param name="newColor">신규 색상</param>
protected virtual void OnSelectedColorChanged(Color previousColor, Color newColor)
{
try
{
this.color = newColor;
SetValue(HexadecimalStringProperty, this.color.ToString());
}
catch
{
}
RoutedPropertyChangedEventArgs<Color> e = new RoutedPropertyChangedEventArgs<Color>(previousColor, newColor);
e.RoutedEvent = ColorPicker.SelectedColorChangedEvent;
RaiseEvent(e);
}
#endregion
#region ScA 변경시 처리하기 - OnScAChanged(newValue)
/// <summary>
/// ScA 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnScAChanged(float newValue)
{
this.isAlphaChange = true;
if(this.shouldFindPoint)
{
this.color.ScA = newValue;
SetValue(AProperty, this.color.A);
SetValue(SelectedColorProperty, this.color);
SetValue(HexadecimalStringProperty, this.color.ToString());
}
this.isAlphaChange = false;
}
#endregion
#region ScR 변경시 처리하기 - OnScRChanged(newValue)
/// <summary>
/// ScR 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnScRChanged(float newValue)
{
if(this.shouldFindPoint)
{
this.color.ScR = newValue;
SetValue(RProperty, this.color.R);
SetValue(SelectedColorProperty, this.color);
SetValue(HexadecimalStringProperty, this.color.ToString());
}
}
#endregion
#region ScG 변경시 처리하기 - OnScGChanged(newValue)
/// <summary>
/// ScG 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnScGChanged(float newValue)
{
if(this.shouldFindPoint)
{
this.color.ScG = newValue;
SetValue(GProperty, this.color.G);
SetValue(SelectedColorProperty, this.color);
SetValue(HexadecimalStringProperty, this.color.ToString());
}
}
#endregion
#region ScB 변경시 처리하기 - OnScBChanged(newValue)
/// <summary>
/// ScB 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnScBChanged(float newValue)
{
if(this.shouldFindPoint)
{
this.color.ScB = newValue;
SetValue(BProperty, this.color.B);
SetValue(SelectedColorProperty, this.color);
SetValue(HexadecimalStringProperty, this.color.ToString());
}
}
#endregion
#region A 변경시 처리하기 - OnAChanged(newValue)
/// <summary>
/// A 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnAChanged(byte newValue)
{
this.color.A = newValue;
SetValue(ScAProperty, this.color.ScA);
SetValue(SelectedColorProperty, this.color);
}
#endregion
#region B 변경시 처리하기 - OnRChanged(newValue)
/// <summary>
/// B 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnRChanged(byte newValue)
{
this.color.R = newValue;
SetValue(ScRProperty, this.color.ScR);
SetValue(SelectedColorProperty, this.color);
}
#endregion
#region G 변경시 처리하기 - OnGChanged(newValue)
/// <summary>
/// G 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnGChanged(byte newValue)
{
this.color.G = newValue;
SetValue(ScGProperty, this.color.ScG);
SetValue(SelectedColorProperty, this.color);
}
#endregion
#region B 변경시 처리하기 - OnBChanged(newValue)
/// <summary>
/// B 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnBChanged(byte newValue)
{
this.color.B = newValue;
SetValue(ScBProperty, this.color.ScB);
SetValue(SelectedColorProperty, this.color);
}
#endregion
#region 16진수 문자열 변경시 처리하기 - OnHexadecimalStringChanged(newValue)
/// <summary>
/// 16진수 문자열 변경시 처리하기
/// </summary>
/// <param name="newValue">신규 값</param>
protected virtual void OnHexadecimalStringChanged(string newValue)
{
if(this.shouldFindPoint)
{
this.color = (Color)ColorConverter.ConvertFromString(newValue);
}
SetValue(AProperty, this.color.A);
SetValue(RProperty, this.color.R);
SetValue(GProperty, this.color.G);
SetValue(BProperty, this.color.B);
if(this.shouldFindPoint && !this.isAlphaChange)
{
UpdateMarkerPoint(this.color);
}
}
#endregion
#region 템플리트 변경시 처리하기 - OnTemplateChanged(previousTemplate, newTemplate)
/// <summary>
/// 템플리트 변경시 처리하기
/// </summary>
/// <param name="previousTemplate">이전 템플리트</param>
/// <param name="newTemplate">신규 템플리트</param>
protected override void OnTemplateChanged(ControlTemplate previousTemplate, ControlTemplate newTemplate)
{
if(previousTemplate != null)
{
this.spectrumSlider.ValueChanged -= spectrumSlider_ValueChanged;
this.colorDetailFrameworkElement.MouseLeftButtonDown -= colorDetailFrameworkElement_MouseLeftButtonDown;
this.colorDetailFrameworkElement.PreviewMouseMove -= colorDetailFrameworkElement_MouseMove;
this.colorDetailFrameworkElement.SizeChanged -= colorDetailFrameworkElement_SizeChanged;
this.colorDetailFrameworkElement = null;
this.colorMarkerPath = null;
this.spectrumSlider = null;
}
base.OnTemplateChanged(previousTemplate, newTemplate);
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
////////////////////////////////////////////////////////////////////// Event
#region 스펙트럼 슬라이더 값 변경시 처리하기 - spectrumSlider_ValueChanged(sender, e)
/// <summary>
/// 스펙트럼 슬라이더 값 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void spectrumSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<Double> e)
{
if(this.colorPoint != null)
{
DetermineColor((Point)this.colorPoint);
}
}
#endregion
#region 색상 상세 프레임워크 엘리먼트 크기 변경시 처리하기 - colorDetailFrameworkElement_SizeChanged(sender, e)
/// <summary>
/// 색상 상세 프레임워크 엘리먼트 크기 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorDetailFrameworkElement_SizeChanged(object sender, SizeChangedEventArgs e)
{
if(e.PreviousSize != Size.Empty && e.PreviousSize.Width != 0 && e.PreviousSize.Height != 0)
{
double widthDifference = e.NewSize.Width / e.PreviousSize.Width;
double heightDifference = e.NewSize.Height / e.PreviousSize.Height;
this.markerTranslateTransform.X = this.markerTranslateTransform.X * widthDifference;
this.markerTranslateTransform.Y = this.markerTranslateTransform.Y * heightDifference;
}
}
#endregion
#region 색상 상세 프레임워크 엘리먼트 마우스 왼쪽 버튼 DOWN 처리하기 - colorDetailFrameworkElement_MouseLeftButtonDown(sender, e)
/// <summary>
/// 색상 상세 프레임워크 엘리먼트 마우스 왼쪽 버튼 DOWN 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorDetailFrameworkElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point point = e.GetPosition(this.colorDetailFrameworkElement);
UpdateMarkerPoint(point);
}
#endregion
#region 색상 상세 프레임워크 엘리먼트 마우스 이동시 처리하기 - colorDetailFrameworkElement_MouseMove(sender, e)
/// <summary>
/// 색상 상세 프레임워크 엘리먼트 마우스 이동시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorDetailFrameworkElement_MouseMove(object sender, MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Pressed)
{
Point point = e.GetPosition(this.colorDetailFrameworkElement);
UpdateMarkerPoint(point);
Mouse.Synchronize();
}
}
#endregion
////////////////////////////////////////////////////////////////////// Function
#region 색상 결정하기 - DetermineColor(point)
/// <summary>
/// 색상 결정하기
/// </summary>
/// <param name="point">포인트</param>
private void DetermineColor(Point point)
{
HSVColor hsvColor = new HSVColor(360 - this.spectrumSlider.Value, 1, 1);
hsvColor.S = point.X;
hsvColor.V = 1 - point.Y;
this.color = ColorHelper.GetColor(hsvColor.H, hsvColor.S, hsvColor.V);
this.shouldFindPoint = false;
this.color.ScA = (float)GetValue(ScAProperty);
SetValue(HexadecimalStringProperty, this.color.ToString());
this.shouldFindPoint = true;
}
#endregion
#region 마커 포인트 업데이트하기 - UpdateMarkerPoint(point)
/// <summary>
/// 마커 포인트 업데이트하기
/// </summary>
/// <param name="point">포인트</param>
private void UpdateMarkerPoint(Point point)
{
this.markerTranslateTransform.X = point.X;
this.markerTranslateTransform.Y = point.Y;
point.X = point.X / this.colorDetailFrameworkElement.ActualWidth;
point.Y = point.Y / this.colorDetailFrameworkElement.ActualHeight;
this.colorPoint = point;
DetermineColor(point);
}
#endregion
#region 마커 포인트 업데이트하기 - UpdateMarkerPoint(color)
/// <summary>
/// 마커 포인트 업데이트하기
/// </summary>
/// <param name="color">색상</param>
private void UpdateMarkerPoint(Color color)
{
this.colorPoint = null;
HSVColor hsvColor = ColorHelper.GetHSVColor(color.R, color.G, color.B);
if(this.spectrumSlider != null)
{
this.spectrumSlider.Value = 360 - hsvColor.H;
}
Point point = new Point(hsvColor.S, 1 - hsvColor.V);
this.colorPoint = point;
point.X = point.X * this.colorDetailFrameworkElement.ActualWidth;
point.Y = point.Y * this.colorDetailFrameworkElement.ActualHeight;
this.markerTranslateTransform.X = point.X;
this.markerTranslateTransform.Y = point.Y;
}
#endregion
#region 색상 설정하기 - SetColor(color)
/// <summary>
/// 색상 설정하기
/// </summary>
/// <param name="color">색상</param>
private void SetColor(Color color)
{
UpdateMarkerPoint(color);
SetValue(SelectedColorProperty, color);
}
#endregion
}
}
▶ ColorPickerWindow.xaml
<Window x:Class="TestProject.ColorPickerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject"
Width="600"
Height="500"
Title="색상 선택하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom"
Margin="10"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button Name="okButton"
Width="100"
Padding="5"
IsEnabled="False">
확인
</Button>
<Button Name="cancelButton"
Margin="10 0 0 0"
Width="100"
Padding="5">
취소
</Button>
</StackPanel>
<local:ColorPicker x:Name="colorPicker"
Margin="10" />
</DockPanel>
</Window>
▶ ColorPickerWindow.xaml.cs
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 선택기 윈도우
/// </summary>
public partial class ColorPickerWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 색상
/// </summary>
private Color color = new Color();
/// <summary>
/// 시작 색상
/// </summary>
private Color startingColor = new Color();
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 선택 색상 - SelectedColor
/// <summary>
/// 선택 색상
/// </summary>
public Color SelectedColor
{
get
{
return this.color;
}
}
#endregion
#region 시작 색상 - StartingColor
/// <summary>
/// 시작 색상
/// </summary>
public Color StartingColor
{
get
{
return this.startingColor;
}
set
{
this.startingColor = value;
this.okButton.IsEnabled = false;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorPickerWindow()
/// <summary>
/// 생성자
/// </summary>
public ColorPickerWindow()
{
InitializeComponent();
Loaded += Window_Loaded;
this.colorPicker.SelectedColorChanged += colorPicker_SelectedColorChanged;
this.okButton.Click += okButton_Click;
this.cancelButton.Click += cancelButton_Click;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 닫을 경우 처리하기 - OnClosing(e)
/// <summary>
/// 닫을 경우 처리하기
/// </summary>
/// <param name="e">이벤트 인자</param>
protected override void OnClosing(CancelEventArgs e)
{
this.okButton.IsEnabled = false;
base.OnClosing(e);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 윈도우 로드시 처리하기 - Window_Loaded(sender, e)
/// <summary>
/// 윈도우 로드시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.colorPicker.SelectedColor = this.startingColor;
}
#endregion
#region 색상 선택기 선택 색상 변경시 처리하기 - colorPicker_SelectedColorChanged(sender, e)
/// <summary>
/// 색상 선택기 선택 색상 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorPicker_SelectedColorChanged(object sender, RoutedPropertyChangedEventArgs<Color> e)
{
if(e.NewValue != this.color)
{
this.okButton.IsEnabled = true;
}
}
#endregion
#region 확인 버튼 클릭시 처리하기 - okButton_Click(sender, e)
/// <summary>
/// 확인 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void okButton_Click(object sender, RoutedEventArgs e)
{
this.okButton.IsEnabled = false;
this.color = this.colorPicker.SelectedColor;
DialogResult = true;
Hide();
}
#endregion
#region 취소 버튼 클릭시 처리하기 - cancelButton_Click(sender, e)
/// <summary>
/// 취소 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
this.okButton.IsEnabled = false;
DialogResult = 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="색상 선택기 사용하기"
Background="White"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid>
<StackPanel Name="stackPanel"
Margin="10">
<Border BorderBrush="Orange" BorderThickness="2">
<local:ColorPicker x:Name="colorPicker"
Margin="10" />
</Border>
<Button Name="button"
Margin="10"
Width="200"
Padding="5"
Content="색상 선택기 대화 상자" />
</StackPanel>
</Grid>
</Window>
▶ MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 메인 윈도우
/// </summary>
public partial class MainWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainWindow()
/// <summary>
/// 생성자
/// </summary>
public MainWindow()
{
InitializeComponent();
this.button.Click += button_Click;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 버튼 클릭시 처리하기 - button_Click(sender, e)
/// <summary>
/// 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void button_Click(object sender, RoutedEventArgs e)
{
ColorPickerWindow window = new ColorPickerWindow();
window.Owner = this;
window.StartingColor = Colors.Blue;
if(window.ShowDialog().GetValueOrDefault())
{
this.colorPicker.SelectedColor = window.SelectedColor;
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] ContentControl 엘리먼트 : Style 속성 사용하기 (0) | 2020.08.03 |
---|---|
[C#/WPF] FrameworkElement 클래스 : DefaultStyleKeyProperty 속성을 사용해 컨트롤 테마 스타일 설정하기 (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] LinearGradientBrush 클래스 : 속성 값 변경하기 (0) | 2020.08.01 |
[C#/WPF] LinearGradientBrush 클래스 : 애니메이션 사용하기 (0) | 2020.07.31 |
[C#/WPF] Brush 클래스 : RelativeTransform/Transform 속성 사용하기 (0) | 2020.07.31 |
[C#/WPF] Brushes 클래스 : 미리 정의된 브러시 사용하기 (0) | 2020.07.31 |
[C#/WPF] SolidColorBrush 클래스 : Color/Opacity 속성 애니메이션 설정하기 (0) | 2020.07.31 |
댓글을 달아 주세요