728x90
반응형
728x170
▶ ColorToBrushConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상↔브러시 변환자
/// </summary>
[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorToBrushConverter : IValueConverter
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 변환하기 - Convert(sourceValue, targetType, parameter, cultureInfo)
/// <summary>
/// 변환하기
/// </summary>
/// <param name="sourceValue">소스 값</param>
/// <param name="targetType">타겟 타입</param>
/// <param name="parameter">매개 변수</param>
/// <param name="cultureInfo">컬처 정보</param>
/// <returns>타겟 값</returns>
public object Convert(object sourceValue, Type targetType, object parameter, CultureInfo cultureInfo)
{
Color color = (Color)sourceValue;
return new SolidColorBrush(color);
}
#endregion
#region 역 변환하기 - ConvertBack(targetValue, sourceType, parameter, cultureInfo)
/// <summary>
/// 역 변환하기
/// </summary>
/// <param name="targetValue">타겟 값</param>
/// <param name="sourceType">소스 타입</param>
/// <param name="parameter">매개 변수</param>
/// <param name="cultureInfo">컬처 정보</param>
/// <returns>소스 값</returns>
public object ConvertBack(object targetValue, Type sourceType, object parameter, CultureInfo cultureInfo)
{
SolidColorBrush brush = targetValue as SolidColorBrush;
return brush.Color;
}
#endregion
}
}
728x90
▶ 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 Color? color;
/// <summary>
/// 텍스트
/// </summary>
private string text;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 색상 - Color
/// <summary>
/// 색상
/// </summary>
public Color? Color
{
get
{
return this.color;
}
set
{
if(this.color == value)
{
return;
}
this.color = value;
FirePropertyChanged("Color");
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public string Text
{
get
{
return this.text;
}
set
{
if(this.text == value)
{
return;
}
this.text = value;
FirePropertyChanged("Text");
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 생성자 - ColorItem()
/// <summary>
/// 생성자
/// </summary>
public ColorItem()
{
}
#endregion
#region 생성자 - ColorItem(color, text)
/// <summary>
/// 생성자
/// </summary>
/// <param name="color">색상</param>
/// <param name="text">텍스트</param>
public ColorItem(Color color, string text)
{
this.color = color;
this.text = text;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문자열 구하기 - ToString()
/// <summary>
/// 문자열 구하기
/// </summary>
/// <returns>문자열</returns>
public override string ToString()
{
return this.text;
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 속성 변경시 이벤트 발생시키기 - FirePropertyChanged(propertyName)
/// <summary>
/// 속성 변경시 이벤트 발생시키기
/// </summary>
/// <param name="propertyName">속성명</param>
protected void FirePropertyChanged(string propertyName)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
300x250
▶ ColorList.xaml
<ListBox x:Class="TestProject.ColorList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestProject"
mc:Ignorable="d"
d:DesignWidth="200"
d:DesignHeight="200"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
SelectionMode="Single">
<ListBox.Resources>
<local:ColorToBrushConverter x:Key="ColorToBrushConverterKey" />
<ItemsPanelTemplate x:Key="ItemsPanelTemplateKey1">
<StackPanel />
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="ItemsPanelTemplateKey2">
<UniformGrid Columns="8" />
</ItemsPanelTemplate>
<DataTemplate x:Key="DataTemplateKey1">
<StackPanel Orientation="Horizontal">
<Rectangle
Margin="2"
Width="16"
Height="16"
Stroke="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
Fill="{Binding Path=Color, Converter={StaticResource ColorToBrushConverterKey}}" />
<TextBlock Name="itemTextBlock"
Margin="2 0 0 0"
Width="{Binding RelativeSource={RelativeSource AncestorType=ListBox, Mode=FindAncestor}, Path=ActualWidth}"
VerticalAlignment="Center"
Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DataTemplateKey2">
<Rectangle
Margin="2"
Width="16"
Height="16"
Stroke="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
Fill="{Binding Path=Color, Converter={StaticResource ColorToBrushConverterKey}}"
ToolTip="{Binding Path=Text}" />
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle
Margin="2"
Width="16"
Height="16"
Stroke="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
Fill="{Binding Path=Color, Converter={StaticResource ColorToBrushConverterKey}}" />
<TextBlock Name="itemTextBlock"
Margin="2 0 0 0"
Width="{Binding RelativeSource={RelativeSource AncestorType=ListBox, Mode=FindAncestor}, Path=ActualWidth}"
VerticalAlignment="Center" Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
▶ ColorList.xaml.cs
using System;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 리스트
/// </summary>
public partial class ColorList : ListBox
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 색상 변경시 - ColorChanged
/// <summary>
/// 색상 변경시
/// </summary>
public event EventHandler ColorChanged;
#endregion
#region 항목 마우스 UP시 - ItemMouseUp
/// <summary>
/// 항목 마우스 UP시
/// </summary>
public event EventHandler ItemMouseUp;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 색상 의존 속성
/// </summary>
public static readonly DependencyProperty ColorProperty;
/// <summary>
/// 텍스트 의존 속성
/// </summary>
public static readonly DependencyProperty TextProperty;
/// <summary>
/// 알려진 색상들 채우기 여부 의존 속성
/// </summary>
public static readonly DependencyProperty FillKnownColorsProperty;
/// <summary>
/// 색상 그리드 사용 여부 의존 속성
/// </summary>
public static readonly DependencyProperty UseColorGridProperty;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 값 변경시 이벤트 발생 여부
/// </summary>
private bool canFireValueChanged = true;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 색상 - Color
/// <summary>
/// 색상
/// </summary>
public Color? Color
{
get
{
return (Color?)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
#endregion
#region 알려진 색상들 채우기 여부 - FillKnownColors
/// <summary>
/// 알려진 색상들 채우기 여부
/// </summary>
public bool FillKnownColors
{
get
{
return (bool)GetValue(FillKnownColorsProperty);
}
set
{
SetValue(FillKnownColorsProperty, value);
}
}
#endregion
#region 색상 그리드 사용 여부 - UseColorGrid
/// <summary>
/// 색상 그리드 사용 여부
/// </summary>
public bool UseColorGrid
{
get
{
return (bool)GetValue(UseColorGridProperty);
}
set
{
SetValue(UseColorGridProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - ColorList()
/// <summary>
/// 생성자
/// </summary>
static ColorList()
{
ColorProperty = RegisterDependencyProperty(null, false, false, false, true, colorPropertyChangedCallback,
"Color", typeof(Color?), typeof(ColorList), null);
TextProperty = RegisterDependencyProperty(string.Empty, false, false, false, true, null,
"Text", typeof(string), typeof(ColorList), null);
FillKnownColorsProperty = RegisterDependencyProperty(false, false, false, false, true, fillKnownColorsPropertyChangedCallback,
"FillKnownColors", typeof(bool), typeof(ColorList), null);
UseColorGridProperty = RegisterDependencyProperty(false, false, false, false, true, useColorGridPropertyChangedCallback,
"UseColorGrid", typeof(bool), typeof(ColorList), null);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorList()
/// <summary>
/// 생성자
/// </summary>
public ColorList()
{
InitializeComponent();
SelectionChanged += ListBox_SelectionChanged;
AddHandler(TextBlock.MouseDownEvent, new MouseButtonEventHandler(itemTextBlock_MouseDown));
AddHandler(TextBlock.MouseUpEvent , new MouseButtonEventHandler(itemTextBlock_MouseUp ));
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 의존 속성 등록하기 - RegisterDependencyProperty(defaultValue, affectsRender, affectsMeasure, affectsArrange,
inherits, propertyChangedCallback, propertyName, propertyType, ownerType, validateValueCallback)
/// <summary>
/// 의존 속성 등록하기
/// </summary>
/// <param name="defaultValue">디폴트 값</param>
/// <param name="affectsRender">렌더링 여향 여부</param>
/// <param name="affectsMeasure">크기 측정 영향 여부</param>
/// <param name="affectsArrange">배치 영향 여부</param>
/// <param name="inherits">상속 여부</param>
/// <param name="propertyChangedCallback">속성 변경 콜백</param>
/// <param name="propertyName">속성명</param>
/// <param name="propertyType">속성 타입</param>
/// <param name="ownerType">소유자 타입</param>
/// <param name="validateValueCallback">값 무결성 콜백</param>
/// <returns>의존 속성</returns>
private static DependencyProperty RegisterDependencyProperty(object defaultValue, bool affectsRender, bool affectsMeasure, bool affectsArrange,
bool inherits, PropertyChangedCallback propertyChangedCallback, string propertyName, Type propertyType, Type ownerType,
ValidateValueCallback validateValueCallback)
{
FrameworkPropertyMetadata frameworkPropertyMetadata = new FrameworkPropertyMetadata();
frameworkPropertyMetadata.DefaultValue = defaultValue;
frameworkPropertyMetadata.AffectsRender = affectsRender;
frameworkPropertyMetadata.AffectsMeasure = affectsMeasure;
frameworkPropertyMetadata.AffectsArrange = affectsArrange;
frameworkPropertyMetadata.Inherits = inherits;
frameworkPropertyMetadata.PropertyChangedCallback += propertyChangedCallback;
return DependencyProperty.Register(propertyName, propertyType, ownerType, frameworkPropertyMetadata, validateValueCallback);
}
#endregion
#region 색상 속성 변경시 콜백 처리하기 - colorPropertyChangedCallback(dependencyObject, e)
/// <summary>
/// 색상 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="dependencyObject">의존 객체</param>
/// <param name="e">이벤트인자</param>
private static void colorPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
ColorList colorList = dependencyObject as ColorList;
Color? newValue = (Color?)e.NewValue;
colorList.SetColor(newValue);
string text = colorList.GetText();
colorList.Text = text;
colorList.FireColorChanged();
}
#endregion
#region 알려진 색상들 채우기 여부 속성 변경시 콜백 처리하기 - fillKnownColorsPropertyChangedCallback(dependencyObject, e)
/// <summary>
/// 알려진 색상들 채우기 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="dependencyObject">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void fillKnownColorsPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
ColorList colorList = dependencyObject as ColorList;
bool newValue = (bool)e.NewValue;
colorList.ItemsSource = null;
colorList.Color = null;
if(newValue)
{
colorList.SetKnownColorsCollection();
}
}
#endregion
#region 색상 그리드 사용 여부 속성 변경시 콜백 처리하기 - useColorGridPropertyChangedCallback(dependencyObject, e)
/// <summary>
/// 색상 그리드 사용 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="dependencyObject">의존 객체</param>
/// <param name="e">이벤트인자</param>
private static void useColorGridPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
ColorList colorList = dependencyObject as ColorList;
bool newValue = (bool)e.NewValue;
if(newValue)
{
DataTemplate dataTemplate = colorList.FindResource("DataTemplateKey2") as DataTemplate;
colorList.ItemTemplate = dataTemplate;
ItemsPanelTemplate itemsPanelTemplate = colorList.FindResource("ItemsPanelTemplateKey2") as ItemsPanelTemplate;
colorList.ItemsPanel = itemsPanelTemplate;
}
else
{
DataTemplate dataTemplate = colorList.FindResource("DataTemplateKey1") as DataTemplate;
colorList.ItemTemplate = dataTemplate;
ItemsPanelTemplate itemsPanelTemplate = colorList.FindResource("ItemsPanelTemplateKey1") as ItemsPanelTemplate;
colorList.ItemsPanel = itemsPanelTemplate;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 항목 구하기 - GetItem()
/// <summary>
/// 항목 구하기
/// </summary>
/// <returns>항목</returns>
public ColorItem GetItem()
{
ColorItem item = SelectedItem as ColorItem;
return item;
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Protected
#region 색상 변경시 이벤트 발생시키기 - FireColorChanged()
/// <summary>
/// 색상 변경시 이벤트 발생시키기
/// </summary>
protected void FireColorChanged()
{
if(ColorChanged != null)
{
ColorChanged(this, EventArgs.Empty);
}
}
#endregion
#region 항목 마우스 UP 이벤트 발생시키기 - FireItemMouseUp()
/// <summary>
/// 항목 마우스 UP 이벤트 발생시키기
/// </summary>
public void FireItemMouseUp()
{
if(ItemMouseUp != null)
{
ItemMouseUp(this, EventArgs.Empty);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
////////////////////////////////////////////////////////////////////// Event
#region 리스트 박스 선택 변경시 처리하기 - ListBox_SelectionChanged(sender, e)
/// <summary>
/// 리스트 박스 선택 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(this.canFireValueChanged)
{
ColorItem item = SelectedItem as ColorItem;
if(item == null)
{
Color = Colors.Transparent;
return;
}
Color = item.Color;
}
}
#endregion
#region 항목 텍스트 블럭 마우스 DOWN 처리하기 - itemTextBlock_MouseDown(sender, e)
/// <summary>
/// 항목 텍스트 블럭 마우스 DOWN 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void itemTextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
this.canFireValueChanged = false;
}
#endregion
#region 항목 텍스트 블럭 마우스 UP 처리하기 - itemTextBlock_MouseUp(sender, e)
/// <summary>
/// 항목 텍스트 블럭 마우스 UP 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void itemTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
this.canFireValueChanged = true;
Color = GetColor();
FireColorChanged();
FireItemMouseUp();
}
#endregion
////////////////////////////////////////////////////////////////////// Function
#region 색상 설정하기 - SetColor(color)
/// <summary>
/// 색상 설정하기
/// </summary>
/// <param name="color">색상</param>
private void SetColor(Color? color)
{
try
{
SelectionChanged -= ListBox_SelectionChanged;
if(color.Equals(null))
{
SelectedItem = null;
return;
}
ObservableCollection<ColorItem> collection = ItemsSource as ObservableCollection<ColorItem>;
if(collection == null || collection.Count == 0)
{
return;
}
foreach(ColorItem item in collection)
{
if(color.Equals(item.Color))
{
SelectedItem = item;
return;
}
}
SelectedItem = null;
}
finally
{
SelectionChanged += ListBox_SelectionChanged;
}
}
#endregion
#region 색상 구하기 - GetColor()
/// <summary>
/// 색상 구하기
/// </summary>
/// <returns>색상</returns>
private Color? GetColor()
{
if(SelectedItem == null)
{
return null;
}
ColorItem item = SelectedItem as ColorItem;
if(item != null)
{
return item.Color;
}
else
{
return null;
}
}
#endregion
#region 텍스트 구하기 - GetText()
/// <summary>
/// 텍스트 구하기
/// </summary>
/// <returns>텍스트</returns>
private string GetText()
{
if(SelectedItem == null)
{
return string.Empty;
}
ColorItem item = SelectedItem as ColorItem;
if(item != null)
{
return item.Text;
}
else
{
return string.Empty;
}
}
#endregion
#region 색상명 구하기 - GetColorName(originalName)
/// <summary>
/// 색상명 구하기
/// </summary>
/// <param name="originalName">원본명</param>
/// <returns>색상명</returns>
private string GetColorName(string originalName)
{
string name = originalName[0].ToString();
for(int i = 1; i < originalName.Length; i++)
{
name += (char.IsUpper(originalName[i]) ? " " : string.Empty) + originalName[i].ToString();
}
return name;
}
#endregion
#region 알려진 색상들 컬렉션 설정하기 - SetKnownColorsCollection()
/// <summary>
/// 알려진 색상들 컬렉션 설정하기
/// </summary>
private void SetKnownColorsCollection()
{
ObservableCollection<ColorItem> collection = new ObservableCollection<ColorItem>();
PropertyInfo[] propertyInfoArray = typeof(Colors).GetProperties();
for(int i = 0; i < propertyInfoArray.Length; i++)
{
ColorItem item = new ColorItem();
item.Color = (Color)propertyInfoArray[i].GetValue(null, null);
item.Text = GetColorName(propertyInfoArray[i].Name);
collection.Add(item);
}
ItemsSource = collection;
}
#endregion
}
}
▶ ColorCombo.xaml
<UserControl x:Class="TestProject.ColorCombo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:local="clr-namespace:TestProject"
mc:Ignorable="d"
d:DesignWidth="300"
d:DesignHeight="30">
<UserControl.Resources>
<local:ColorToBrushConverter x:Key="ColorToBrushConverterKey" />
</UserControl.Resources>
<Grid Name="grid"
Margin="0">
<Button Name="button"
Margin="0"
Width="{Binding ElementName=grid, Path=ActualWidth}"
Height= "{Binding ElementName=grid, Path=ActualHeight}"
Content="{Binding ElementName=colorList, Path=SelectedItem}"
Padding="0">
<Button.ContentTemplate>
<DataTemplate>
<Grid Width="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=ActualWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Rectangle Name="itemRectangle" Grid.Column="0"
Margin="2"
Width="16"
Height="16"
Stroke="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"
Fill="{Binding Path=Color, Converter={StaticResource ColorToBrushConverterKey}}" />
<TextBlock Grid.Column="1"
Margin="2 0 0 0"
VerticalAlignment="Center"
TextAlignment="Left" Text="{Binding Text}" />
<Path Grid.Column="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="20"
Fill="Black">
<Path.Data>
<Geometry>M 5 0 L 8.5 4 L 12 0 Z</Geometry>
</Path.Data>
</Path>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Content}" Value="{x:Null}">
<Setter TargetName="itemRectangle" Property="Stroke" Value="Transparent" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Button.ContentTemplate>
</Button>
<Popup Name="popup"
MinWidth="{Binding ElementName=button, Path=ActualWidth}"
Width="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=PopupWidth}"
Height="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=PopupHeight}"
PlacementTarget="{Binding ElementName=button}"
Placement="Bottom"
IsOpen="False"
StaysOpen="False"
AllowsTransparency="True">
<themes:SystemDropShadowChrome Margin="0 0 3 3" Color="#80000000">
<Border HorizontalAlignment="Stretch">
<local:ColorList x:Name="colorList" />
</Border>
</themes:SystemDropShadowChrome>
</Popup>
</Grid>
</UserControl>
▶ ColorCombo.xaml.cs
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 색상 콤보
/// </summary>
public partial class ColorCombo : UserControl
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Event
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 색상 변경시 - ColorChanged
/// <summary>
/// 색상 변경시
/// </summary>
public event EventHandler ColorChanged;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 항목들 소스 의존 속성
/// </summary>
public static readonly DependencyProperty ItemsSourceProperty;
/// <summary>
/// 팝업 너비 의존 속성
/// </summary>
public static readonly DependencyProperty PopupWidthProperty;
/// <summary>
/// 팝업 높이 의존 속성
/// </summary>
public static readonly DependencyProperty PopupHeightProperty;
/// <summary>
/// 색상 의존 속성
/// </summary>
public static readonly DependencyProperty ColorProperty;
/// <summary>
/// 텍스트 의존 속성
/// </summary>
public static readonly DependencyProperty TextProperty;
/// <summary>
/// 알려진 색상들 채우기 여부 의존 속성
/// </summary>
public static readonly DependencyProperty FillKnownColorsProperty;
/// <summary>
/// 색상 그리드 사용 여부 의존 속성
/// </summary>
public static readonly DependencyProperty UseColorGridProperty;
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 마우스 버튼 상위 여부
/// </summary>
private bool isMouseOverButton = false;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 버튼 - Button
/// <summary>
/// 버튼
/// </summary>
public Button Button
{
get
{
return this.button;
}
}
#endregion
#region 색상 리스트 - ColorList
/// <summary>
/// 색상 리스트
/// </summary>
public ColorList ColorList
{
get
{
return this.colorList;
}
}
#endregion
#region 항목들 소스 - ItemsSource
/// <summary>
/// 항목들 소스
/// </summary>
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
#endregion
#region 팝업 너비 - PopupWidth
/// <summary>
/// 팝업 너비
/// </summary>
public double PopupWidth
{
get
{
return (double)GetValue(PopupWidthProperty);
}
set
{
SetValue(PopupWidthProperty, value);
}
}
#endregion
#region 팝업 높이 - PopupHeight
/// <summary>
/// 팝업 높이
/// </summary>
public double PopupHeight
{
get
{
return (double)GetValue(PopupHeightProperty);
}
set
{
SetValue(PopupHeightProperty, value);
}
}
#endregion
#region 색상 - Color
/// <summary>
/// 색상
/// </summary>
public Color? Color
{
get
{
return (Color?)GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
#endregion
#region 텍스트 - Text
/// <summary>
/// 텍스트
/// </summary>
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
#endregion
#region 알려진 색상들 채우기 여부 - FillKnownColors
/// <summary>
/// 알려진 색상들 채우기 여부
/// </summary>
public bool FillKnownColors
{
get
{
return (bool)GetValue(FillKnownColorsProperty);
}
set
{
SetValue(FillKnownColorsProperty, value);
}
}
#endregion
#region 색상 그리드 사용 여부 - UseColorGrid
/// <summary>
/// 색상 그리드 사용 여부
/// </summary>
public bool UseColorGrid
{
get
{
return (bool)GetValue(UseColorGridProperty);
}
set
{
SetValue(UseColorGridProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - ColorCombo()
/// <summary>
/// 생성자
/// </summary>
static ColorCombo()
{
ItemsSourceProperty = RegisterDependencyProperty(null, false, false, false, true, null,
"ItemsSource", typeof(IEnumerable), typeof(ColorCombo), null);
PopupWidthProperty = RegisterDependencyProperty(150d, false, false, false, true, null,
"PopupWidth", typeof(double), typeof(ColorCombo), null);
PopupHeightProperty = RegisterDependencyProperty(100d, false, false, false, true, null,
"PopupHeight", typeof(double), typeof(ColorCombo), null);
ColorProperty = RegisterDependencyProperty(null, false, false, false, true, colorPropertyChangedCallback,
"Color", typeof(Color?), typeof(ColorCombo), null);
TextProperty = RegisterDependencyProperty(string.Empty, false, false, false, true, null,
"Text", typeof(string), typeof(ColorCombo), null);
FillKnownColorsProperty = RegisterDependencyProperty(false, false, false, false, true, null,
"FillKnownColors", typeof(bool), typeof(ColorCombo), null);
UseColorGridProperty = RegisterDependencyProperty(false, false, false, false, true, null,
"UseColorGrid", typeof(bool), typeof(ColorCombo), null);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - ColorCombo()
/// <summary>
/// 생성자
/// </summary>
public ColorCombo()
{
InitializeComponent();
SetBinding(this, ItemsSourceProperty, this.colorList, ColorList.ItemsSourceProperty,
BindingMode.TwoWay, UpdateSourceTrigger.PropertyChanged);
SetBinding(this, ColorProperty, this.colorList, ColorList.ColorProperty,
BindingMode.TwoWay, UpdateSourceTrigger.PropertyChanged);
SetBinding(this, TextProperty, this.colorList, ColorList.TextProperty,
BindingMode.TwoWay, UpdateSourceTrigger.PropertyChanged);
SetBinding(this, FillKnownColorsProperty, this.colorList, ColorList.FillKnownColorsProperty,
BindingMode.TwoWay, UpdateSourceTrigger.PropertyChanged);
SetBinding(this, UseColorGridProperty, this.colorList, ColorList.UseColorGridProperty,
BindingMode.TwoWay, UpdateSourceTrigger.PropertyChanged);
this.popup.IsOpen = true;
this.popup.IsOpen = false;
this.button.Click += button_Click;
this.popup.Opened += popup_Opened;
this.popup.Closed += popup_Closed;
this.colorList.ItemMouseUp += colorList_ItemMouseUp;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 의존 속성 등록하기 - RegisterDependencyProperty(defaultValue, affectsRender, affectsMeasure,
affectsArrange, inherits, propertyChangedCallback, propertyName, propertyType, ownerType, validateValueCallback)
/// <summary>
/// 의존 속성 등록하기
/// </summary>
/// <param name="defaultValue">디폴트 값</param>
/// <param name="affectsRender">렌더링 여향 여부</param>
/// <param name="affectsMeasure">크기 측정 영향 여부</param>
/// <param name="affectsArrange">배치 영향 여부</param>
/// <param name="inherits">상속 여부</param>
/// <param name="propertyChangedCallback">속성 변경 콜백</param>
/// <param name="propertyName">속성명</param>
/// <param name="propertyType">속성 타입</param>
/// <param name="ownerType">소유자 타입</param>
/// <param name="validateValueCallback">값 무결성 콜백</param>
/// <returns>의존 속성</returns>
public static DependencyProperty RegisterDependencyProperty(object defaultValue, bool affectsRender, bool affectsMeasure,
bool affectsArrange, bool inherits, PropertyChangedCallback propertyChangedCallback, string propertyName,
Type propertyType, Type ownerType, ValidateValueCallback validateValueCallback)
{
FrameworkPropertyMetadata frameworkPropertyMetadata = new FrameworkPropertyMetadata();
frameworkPropertyMetadata.DefaultValue = defaultValue;
frameworkPropertyMetadata.AffectsRender = affectsRender;
frameworkPropertyMetadata.AffectsMeasure = affectsMeasure;
frameworkPropertyMetadata.AffectsArrange = affectsArrange;
frameworkPropertyMetadata.Inherits = inherits;
frameworkPropertyMetadata.PropertyChangedCallback += propertyChangedCallback;
return DependencyProperty.Register(propertyName, propertyType, ownerType, frameworkPropertyMetadata, validateValueCallback);
}
#endregion
#region 바인딩 설정하기 - SetBinding(targetElement, targetProperty, source, sourceProperty, bindingMode, updateSourceTrigger)
/// <summary>
/// 바인딩 설정하기
/// </summary>
/// <param name="targetElement">타겟 엘리먼트</param>
/// <param name="targetProperty">타겟 의존 속성</param>
/// <param name="source">소스 객체</param>
/// <param name="sourceProperty">소스 의존 속성</param>
/// <param name="bindingMode">바인딩 모드</param>
/// <param name="updateSourceTrigger">소스 업데이트 트리거</param>
public static void SetBinding(FrameworkElement targetElement, DependencyProperty targetProperty, object source,
DependencyProperty sourceProperty, BindingMode bindingMode, UpdateSourceTrigger updateSourceTrigger)
{
Binding binding = new Binding();
binding.Source = source;
binding.Path = new PropertyPath(sourceProperty);
binding.Mode = bindingMode;
binding.UpdateSourceTrigger = updateSourceTrigger;
targetElement.SetBinding(targetProperty, binding);
}
#endregion
#region 색상 속성 변경시 콜백 처리하기 - colorPropertyChangedCallback(dependencyObject, e)
/// <summary>
/// 색상 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="dependencyObject">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void colorPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
ColorCombo colorCombo = dependencyObject as ColorCombo;
colorCombo.FireColorChanged();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 항목 구하기 - GetItem()
/// <summary>
/// 항목 구하기
/// </summary>
/// <returns>항목</returns>
public ColorItem GetItem()
{
return this.colorList.GetItem();
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Protected
#region 색상 변경시 이벤트 발생시키기 - FireColorChanged()
/// <summary>
/// 색상 변경시 이벤트 발생시키기
/// </summary>
protected void FireColorChanged()
{
if(ColorChanged != null)
{
ColorChanged(this, EventArgs.Empty);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 버튼 클릭시 처리하기 - button_Click(sender, e)
/// <summary>
/// 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void button_Click(object sender, RoutedEventArgs e)
{
if(this.isMouseOverButton)
{
this.isMouseOverButton = false;
return;
}
this.popup.IsOpen = !this.popup.IsOpen;
}
#endregion
#region 팝업 열리는 경우 처리하기 - popup_Opened(sender, e)
/// <summary>
/// 팝업 열리는 경우 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void popup_Opened(object sender, EventArgs e)
{
ObservableCollection<ColorItem> collection = ItemsSource as ObservableCollection<ColorItem>;
if(collection == null || collection.Count == 0)
{
PopupHeight = 16;
return;
}
if(!UseColorGrid)
{
ListBoxItem listBoxItem = this.colorList.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
if(listBoxItem != null)
{
if(!listBoxItem.ActualHeight.Equals(Double.NaN))
{
PopupHeight = Math.Min(collection.Count * listBoxItem.ActualHeight, 20 * listBoxItem.ActualHeight) + 10;
}
}
}
ColorItem item = this.colorList.SelectedItem as ColorItem;
if(item == null)
{
return;
}
this.colorList.ScrollIntoView(item);
}
#endregion
#region 팝업이 닫히는 경우 처리하기 - popup_Closed(sender, e)
/// <summary>
/// 팝업이 닫히는 경우 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void popup_Closed(object sender, EventArgs e)
{
Point mousePoint = Mouse.GetPosition(this.button);
if(mousePoint.X >= 0 && mousePoint.X <= this.button.ActualWidth &&
mousePoint.Y >= 0 && mousePoint.Y <= this.button.ActualHeight)
{
this.isMouseOverButton = true;
}
else
{
this.isMouseOverButton = false;
}
}
#endregion
#region 색상 리스트 항목 마우스 UP 처리하기 - colorList_ItemMouseUp(sender, e)
/// <summary>
/// 색상 리스트 항목 마우스 UP 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorList_ItemMouseUp(object sender, EventArgs e)
{
this.popup.IsOpen = 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:src="clr-namespace:TestProject"
Width="800"
Height="600"
Title="UserControl 클래스 : 색상 콤보 박스 사용하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<src:ColorCombo x:Name="colorCombo" Grid.Column="0"
VerticalAlignment="Top"
Margin="0 50 0 0"
Width="200"
Height="30"
PopupWidth="250" />
<StackPanel Grid.Column="2" Background="#ffe5e5e5">
<StackPanel HorizontalAlignment="Left">
<Button Margin="10" Width="150" Height="30" Content="데이터 설정" Click="dataButton_Click" />
<Button Margin="10" Width="150" Height="30" Content="색상 초기화" Click="colorButton_Click" />
<Button Margin="10" Width="150" Height="30" Content="색상 그리드 사용" Click="useColorGridButton_Click" />
</StackPanel>
<TextBlock Name="colorComboTextBlock" Margin="10"/>
</StackPanel>
</Grid>
</Window>
▶ MainWindow.xaml.cs
using System;
using System.Windows;
namespace TestProject
{
/// <summary>
/// 메인 윈도우
/// </summary>
public partial class MainWindow : Window
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainWindow()
/// <summary>
/// 생성자
/// </summary>
public MainWindow()
{
InitializeComponent();
this.colorCombo.ColorChanged += colorCombo_ColorChanged;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 색상 콤보 색상 변경시 처리하기 - colorCombo_ColorChanged(sender, e)
/// <summary>
/// 색상 콤보 색상 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorCombo_ColorChanged(object sender, EventArgs e)
{
this.colorComboTextBlock.Text = this.colorCombo.Color.ToString();
}
#endregion
#region 데이터 설정 버튼 클릭시 처리하기 - dataButton_Click(sender, e)
/// <summary>
/// 데이터 설정 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void dataButton_Click(object sender, RoutedEventArgs e)
{
this.colorCombo.FillKnownColors = true;
}
#endregion
#region 색상 초기화 버튼 클릭시 처리하기 - colorButton_Click(sender, e)
/// <summary>
/// 색상 초기화 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void colorButton_Click(object sender, RoutedEventArgs e)
{
this.colorCombo.Color = null;
}
#endregion
#region 색상 그리드 사용 버튼 클릭시 처리하기 - useColorGridButton_Click(sender, e)
/// <summary>
/// 색상 그리드 사용 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void useColorGridButton_Click(object sender, RoutedEventArgs e)
{
this.colorCombo.UseColorGrid = !this.colorCombo.UseColorGrid;
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] Viewport3D 클래스 사용하기 (0) | 2019.04.12 |
---|---|
[C#/WPF] VisualStateManager 엘리먼트 사용하기 (0) | 2019.04.12 |
[C#/WPF] XpsDocument 클래스 : XPS 문서 사용하기 (0) | 2019.04.12 |
[C#/WPF] 문자 맵 사용하기 (0) | 2019.04.12 |
[C#/WPF] 폰트 대화 상자 사용하기 (0) | 2019.04.11 |
[C#/WPF] ListBox 클래스 : 색상 리스트 사용하기 (0) | 2019.04.11 |
[C#/WPF] ControlTemplate 클래스 : 시계 만들기 (0) | 2019.04.11 |
[C#/WPF] TreeView 클래스 : 클래스 계층도 트리뷰 사용하기 (0) | 2019.04.11 |
[C#/WPF] ListBox 클래스 : 브러시 리스트 박스 사용하기 (0) | 2019.04.10 |
[C#/WPF] 원 위에 문자 그리기 (0) | 2019.01.15 |
댓글을 달아 주세요