728x90
반응형
728x170
▶ ColorItem.cs
using System.ComponentModel;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 항목
/// </summary>
public class ColorItem : INotifyPropertyChanged
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 속성 변경시 이벤트 - PropertyChanged
/// <summary>
/// 속성 변경시 이벤트
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 색상 소스
/// </summary>
private ColorSource colorSource = ColorSource.UserDefined;
/// <summary>
/// 명칭
/// </summary>
private string name;
/// <summary>
/// 브러시
/// </summary>
private SolidColorBrush brush;
/// <summary>
/// 알파
/// </summary>
private byte alpha;
/// <summary>
/// 적색
/// </summary>
private byte red;
/// <summary>
/// 녹색
/// </summary>
private byte green;
/// <summary>
/// 청색
/// </summary>
private byte blue;
/// <summary>
/// 휘도
/// </summary>
private double luminance;
/// <summary>
/// 색조
/// </summary>
private double hue;
/// <summary>
/// 채도
/// </summary>
private double saturation;
/// <summary>
/// 명도
/// </summary>
private double value;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 색상 소스 - ColorSource
/// <summary>
/// 색상 소스
/// </summary>
public ColorSource ColorSource
{
get
{
return this.colorSource;
}
}
#endregion
#region 명칭 - Name
/// <summary>
/// 명칭
/// </summary>
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
FirePropertyChangedEvent("Name");
}
}
#endregion
#region 브러시 - Brush
/// <summary>
/// 브러시
/// </summary>
public SolidColorBrush Brush
{
get
{
return this.brush;
}
}
#endregion
#region 알파 - Alpha
/// <summary>
/// 알파
/// </summary>
public byte Alpha
{
get
{
return this.alpha;
}
set
{
this.alpha = value;
FirePropertyChangedEvent("Alpha");
UpdateBrush();
}
}
#endregion
#region 적색 - Red
/// <summary>
/// 적색
/// </summary>
public byte Red
{
get
{
return this.red;
}
set
{
this.red = value;
FirePropertyChangedEvent("Red");
SetHSV();
}
}
#endregion
#region 녹색 - Green
/// <summary>
/// 녹색
/// </summary>
public byte Green
{
get
{
return this.green;
}
set
{
this.green = value;
FirePropertyChangedEvent("Green");
SetHSV();
}
}
#endregion
#region 청색 - Blue
/// <summary>
/// 청색
/// </summary>
public byte Blue
{
get
{
return this.blue;
}
set
{
this.blue = value;
FirePropertyChangedEvent("Blue");
SetHSV();
}
}
#endregion
#region 휘도 - Luminance
/// <summary>
/// 휘도
/// </summary>
public double Luminance
{
get
{
return this.luminance;
}
set
{
this.luminance = value;
}
}
#endregion
#region 색조 - Hue
/// <summary>
/// 색조
/// </summary>
public double Hue
{
get
{
return this.hue;
}
set
{
if(value > 360.0)
{
value = 360.0;
}
if(value < 0.0)
{
value = 0.0;
}
this.hue = value;
FirePropertyChangedEvent("Hue");
SetRGB();
}
}
#endregion
#region 채도 - Saturation
/// <summary>
/// 채도
/// </summary>
public double Saturation
{
get
{
return this.saturation;
}
set
{
if(value > 1.0)
{
value = 1.0;
}
if(value < 0.0)
{
value = 0.0;
}
this.saturation = value;
FirePropertyChangedEvent("Saturation");
SetRGB();
}
}
#endregion
#region 명도 - Value
/// <summary>
/// 명도
/// </summary>
public double Value
{
get
{
return this.value;
}
set
{
if(value > 1.0)
{
value = 1.0;
}
if(value < 0.0)
{
value = 0.0;
}
this.value = value;
FirePropertyChangedEvent("Value");
SetRGB();
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorItem(name, brush)
/// <summary>
/// 생성자
/// </summary>
/// <param name="name">명칭</param>
/// <param name="brush">브러시</param>
public ColorItem(string name, SolidColorBrush brush)
{
this.colorSource = ColorSource.BuiltIn;
this.name = name;
this.brush = brush;
Color color = brush.Color;
this.alpha = color.A;
this.red = color.R;
this.green = color.G;
this.blue = color.B;
SetHSV();
}
#endregion
#region 생성자 - ColorItem(colorItem)
/// <summary>
/// 생성자
/// </summary>
/// <param name="colorItem">색상 항목</param>
public ColorItem(ColorItem colorItem)
{
this.colorSource = ColorSource.UserDefined;
this.name = "New Color";
this.brush = new SolidColorBrush(colorItem.brush.Color);
this.alpha = colorItem.alpha;
this.red = colorItem.red;
this.green = colorItem.green;
this.blue = colorItem.blue;
this.luminance = colorItem.luminance;
this.hue = colorItem.hue;
this.saturation = colorItem.saturation;
this.value = colorItem.value;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 속성 변경시 이벤트 발생시키기 - FirePropertyChangedEvent(proertyName)
/// <summary>
/// 속성 변경시 이벤트 발생시키기
/// </summary>
/// <param name="proertyName">속성명</param>
protected void FirePropertyChangedEvent(string proertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(proertyName));
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 브러시 업데이트하기 - UpdateBrush()
/// <summary>
/// 브러시 업데이트하기
/// </summary>
private void UpdateBrush()
{
Color color = this.brush.Color;
if(this.alpha != color.A || this.red != color.R || this.green != color.G || this.blue != color.B)
{
color = Color.FromArgb(this.alpha, this.red, this.green, this.blue);
this.brush = new SolidColorBrush(color);
FirePropertyChangedEvent("Brush");
}
double luminance = (0.30 * this.red + 0.59 * this.green + 0.11 * this.blue) / 255.0;
if(this.luminance != luminance)
{
this.luminance = luminance;
FirePropertyChangedEvent("Luminance");
}
}
#endregion
#region HSV 설정하기 - SetHSV()
/// <summary>
/// HSV 설정하기
/// </summary>
private void SetHSV()
{
int maximumInteger = this.red;
int minimumInteger = this.red;
if(this.green > maximumInteger)
{
maximumInteger = this.green;
}
else if(this.green < minimumInteger)
{
minimumInteger = this.green;
}
if(this.blue > maximumInteger)
{
maximumInteger = this.blue;
}
else if(this.blue < minimumInteger)
{
minimumInteger = this.blue;
}
double maximum = maximumInteger / 255.0, min = minimumInteger / 255.0;
double value = maximum;
double saturation = (maximum > 0) ? (maximum - min) / maximum : 0.0;
double hue = this.hue;
if(maximumInteger > minimumInteger)
{
double f = 1.0 / ((maximum - min) * 255.0);
hue = (maximumInteger == this.red ) ? 0.0 + f * (this.green - this.blue) :
(maximumInteger == this.green) ? 2.0 + f * (this.blue - this.red ) :
4.0 + f * (this.red - this.green);
hue = hue * 60.0;
if(hue < 0.0)
{
hue += 360.0;
}
}
if(hue != this.hue)
{
this.hue = hue;
FirePropertyChangedEvent("Hue");
}
if(saturation != this.saturation)
{
this.saturation = saturation;
FirePropertyChangedEvent("Saturation");
}
if(value != this.value)
{
this.value = value;
FirePropertyChangedEvent("Value");
}
UpdateBrush();
}
#endregion
#region RGB 설정하기 - SetRGB()
/// <summary>
/// RGB 설정하기
/// </summary>
private void SetRGB()
{
double red = 0.0;
double green = 0.0;
double blue = 0.0;
if(this.saturation == 0.0)
{
red = green = blue = this.value;
}
else
{
double h = this.hue;
while(h >= 360.0)
{
h -= 360.0;
}
h = h / 60.0;
int i = (int)h;
double f = h - i;
double r = this.value * (1.0 - this.saturation);
double s = this.value * (1.0 - this.saturation * f);
double t = this.value * (1.0 - this.saturation * (1.0 - f));
switch(i)
{
case 0 :
{
red = this.value;
green = t;
blue = r;
break;
}
case 1 :
{
red = s;
green = this.value;
blue = r;
break;
}
case 2 :
{
red = r;
green = this.value;
blue = t;
break;
}
case 3 :
{
red = r;
green = s;
blue = this.value;
break;
}
case 4 :
{
red = t;
green = r;
blue = this.value;
break;
}
case 5 :
{
red = this.value;
green = r;
blue = s;
break;
}
}
}
byte redByte = (byte)(red * 255.0);
byte greenByte = (byte)(green * 255.0);
byte blueByte = (byte)(blue * 255.0);
if(redByte != this.red)
{
this.red = redByte;
FirePropertyChangedEvent("Red");
}
if(greenByte != this.green)
{
this.green = greenByte;
FirePropertyChangedEvent("Green");
}
if(blueByte != this.blue)
{
this.blue = blueByte;
FirePropertyChangedEvent("Blue");
}
UpdateBrush();
}
#endregion
}
}
728x90
▶ ColorItemList.cs
using System;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 항목 리스트
/// </summary>
public class ColorItemList : ObservableCollection<ColorItem>
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorItemList()
/// <summary>
/// 생성자
/// </summary>
public ColorItemList() : base()
{
Type type = typeof(Brushes);
foreach(PropertyInfo info in type.GetProperties(BindingFlags.Public | BindingFlags.Static))
{
if(info.PropertyType == typeof(SolidColorBrush))
{
Add(new ColorItem(info.Name, (SolidColorBrush)info.GetValue(null, null)));
}
}
}
#endregion
}
}
300x250
▶ 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="색상 값 사용하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Window.Resources>
<local:ColorItemList x:Key="ColorItemListKey" />
<local:ByteToDoubleConverter x:Key="ByteToDoubleConverterKey" />
<local:DoubleToStringConverter x:Key="DoubleToStringConverterKey" />
<local:ColorSourceToBooleanConverter x:Key="ColorSourceToBooleanConverterKey" />
<local:LuminanceToBrushConverter x:Key="LuminanceToBrushConverterKey" />
<DataTemplate x:Key="ColorItemDataTemplateKey">
<Border
Width="150"
Height="30"
Background="{Binding Path=Brush}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{Binding Path=Luminance, Converter={StaticResource LuminanceToBrushConverterKey}}"
Text="{Binding Path=Name}" />
</Border>
</DataTemplate>
<Style x:Key="ListBoxItemStyleKey" TargetType="{x:Type ListBoxItem}">
<Setter Property="Width" Value="Auto" />
</Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Width" Value="90" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style TargetType="{x:Type Slider}">
<Setter Property="Width" Value="100" />
</Style>
</Window.Resources>
<DockPanel
Margin="10"
DataContext="{Binding Source={StaticResource ColorItemListKey}}">
<DockPanel DockPanel.Dock="Top"
Background="White">
<DockPanel Width="Auto">
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>명칭</Label>
<TextBox
Width="120"
Height="20"
Text="{Binding Path=Name}"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>16진수 값</Label>
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding Path=Brush.Color}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>색상 소스</Label>
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding Path=ColorSource}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label Width="85">휘도</Label>
<Slider
Width="50"
Minimum="0.0"
Maximum="1.0"
IsEnabled="False"
Value="{Binding Path=Luminance}" />
<Label
HorizontalAlignment="Left"
Width="35"
Content="{Binding Path=Luminance, Converter={StaticResource DoubleToStringConverterKey}}" />
</StackPanel>
</DockPanel>
<DockPanel DockPanel.Dock="Left"
Width="Auto">
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>알파</Label>
<Slider Name="slider"
Width="50"
Minimum="0"
Maximum="255"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Alpha, Converter={StaticResource ByteToDoubleConverterKey}}" />
<Label
Width="35"
Content="{Binding Path=Alpha}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>적색</Label>
<Slider
Width="50"
Minimum="0"
Maximum="255"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Red, Converter={StaticResource ByteToDoubleConverterKey}}" />
<Label
Width="35"
Content="{Binding Path=Red}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>녹색</Label>
<Slider
Width="50"
Minimum="0"
Maximum="255"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Green, Converter={StaticResource ByteToDoubleConverterKey}}" />
<Label
Width="35"
Content="{Binding Path=Green}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>청색</Label>
<Slider
Width="50"
Minimum="0"
Maximum="255"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Blue, Converter={StaticResource ByteToDoubleConverterKey}}" />
<Label
Width="35"
Content="{Binding Path=Blue}" />
</StackPanel>
</DockPanel>
<DockPanel DockPanel.Dock="Left"
Width="Auto">
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>색조</Label>
<Slider
Width="50"
Minimum="0.0"
Maximum="360.0"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Hue}" />
<Label
Content="{Binding Path=Hue, Converter={StaticResource DoubleToStringConverterKey}}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>채도</Label>
<Slider
Minimum="0.0"
Maximum="1.0"
Width="50"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Saturation}" />
<Label
Width="35"
Content="{Binding Path=Saturation, Converter={StaticResource DoubleToStringConverterKey}}" />
</StackPanel>
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal">
<Label>명도</Label>
<Slider Name="slider2"
Minimum="0.0"
Maximum="1.0"
Width="50"
IsEnabled="{Binding Path=Source, Converter={StaticResource ColorSourceToBooleanConverterKey}}"
Value="{Binding Path=Value}" />
<Label
Width="35"
Content="{Binding Path=Value, Converter={StaticResource DoubleToStringConverterKey}}" />
</StackPanel>
</DockPanel>
<Button DockPanel.Dock="Top"
Width="75"
Height="25"
Click="newColorButton_Click">
신규 색상
</Button>
</DockPanel>
<DockPanel
Margin="10"
Background="FloralWhite">
<StackPanel DockPanel.Dock="Left"
Margin="50"
Orientation="Vertical">
<Label
HorizontalAlignment="Left"
FontWeight="Bold">
정렬 기준
</Label>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">명칭</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">휘도</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">적색</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">녹색</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">청색</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">색조</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">채도</RadioButton>
<RadioButton GroupName="SortBy" Checked="sortRadioButton_Checked">명도</RadioButton>
</StackPanel>
<ListBox Name="colorListBox" DockPanel.Dock="Left"
Width="185"
Height="380"
IsSynchronizedWithCurrentItem="True"
ItemContainerStyle="{StaticResource ListBoxItemStyleKey}"
ItemTemplate = "{StaticResource ColorItemDataTemplateKey}"
ItemsSource="{Binding}" />
<DockPanel DockPanel.Dock="Left">
<Border
Width="100"
Height="100"
Background="{Binding Path=Brush}">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{Binding Path=Luminance, Converter={StaticResource LuminanceToBrushConverterKey}}"
Text="{Binding Path=Name}" />
</Border>
</DockPanel>
</DockPanel>
</DockPanel>
</Window>
▶ MainWindow.xaml.cs
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace TestProject
{
/// <summary>
/// 메인 윈도우
/// </summary>
public partial class MainWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainWindow()
/// <summary>
/// 생성자
/// </summary>
public MainWindow()
{
InitializeComponent();
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 신규 색상 버튼 클릭시 처리하기 - newColorButton_Click(sender, e)
/// <summary>
/// 신규 색상 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void newColorButton_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)sender;
ColorItemList list = (ColorItemList)button.DataContext;
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView((IEnumerable)list);
ColorItem newItem = new ColorItem((ColorItem)view.CurrentItem);
list.Add(newItem);
view.MoveCurrentTo(newItem);
}
#endregion
#region 정렬 라디오 버튼 체크시 처리하기 - sortRadioButton_Checked(sender, e)
/// <summary>
/// 정렬 라디오 버튼 체크시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void sortRadioButton_Checked(object sender, RoutedEventArgs e)
{
RadioButton radioButton = sender as RadioButton;
string sortBy = radioButton.Content.ToString();
string propertyName = string.Empty;
switch(sortBy)
{
case "명칭" : propertyName = "Name"; break;
case "휘도" : propertyName = "Luminance"; break;
case "적색" : propertyName = "Red"; break;
case "녹색" : propertyName = "Green"; break;
case "청색" : propertyName = "Blue"; break;
case "색조" : propertyName = "Hue"; break;
case "채도" : propertyName = "Saturation"; break;
case "명도" : propertyName = "Value"; break;
}
CollectionView view;
if(sortBy != null)
{
view = (CollectionView)CollectionViewSource.GetDefaultView((IEnumerable)radioButton.DataContext);
view.SortDescriptions.Clear();
view.SortDescriptions.Add(new SortDescription(propertyName, ListSortDirection.Descending));
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] ComboBox 엘리먼트 : DropDownOpened/DropDownClosed 이벤트 사용하기 (0) | 2020.08.12 |
---|---|
[C#/WPF] ComboBox 엘리먼트 : 콤보 박스 항목에서 이미지 사용하기 (0) | 2020.08.12 |
[C#/WPF] ComboBox 엘리먼트 : IsEditable 속성 사용하기 (0) | 2020.08.12 |
[C#/WPF] ListBox 클래스 : DisplayMemberPath/SelectedValuePath/SelectedValue 속성 사용하기 (0) | 2020.08.11 |
[C#/WPF] ListBox 클래스 : ScrollIntoView 메소드를 사용해 특정 항목까지 스크롤하기 (0) | 2020.08.11 |
[C#/WPF] 색상 값 사용하기 (0) | 2020.08.11 |
[C#/WPF] IValueConverter 인터페이스 : 바이트↔실수 변환자 사용하기 (0) | 2020.08.11 |
[C#/WPF] IValueConverter 인터페이스 : 실수→문자열 변환자 사용하기 (0) | 2020.08.11 |
[C#/WPF] MultiDataTrigger 엘리먼트 사용하기 (0) | 2020.08.11 |
[C#/WPF] AxisAngleRotation3D 엘리먼트 : 3D 애니메이션 사용하기 (0) | 2020.08.10 |
[C#/WPF] DoubleAnimation 엘리먼트 : EasingFunction 속성에서 CircleEase 객체 사용하기 (0) | 2020.08.10 |
댓글을 달아 주세요