첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ UserControl 클래스 : 색상 콤보 박스 사용하기

------------------------------------------------------------------------------------------------------------------------


TestProject.zip


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

    }

}

 

 

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

    }

}

 

 

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

    }

}

 

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요