첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ ColorCell.cs

using System;
using System.Windows;
using System.Windows.Media;

namespace TestProject
{
    /// <summary>
    /// 색상 셀
    /// </summary>
    public class ColorCell : FrameworkElement
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// 선택 여부 속성
        /// </summary>
        public static readonly DependencyProperty IsSelectedProperty;

        /// <summary>
        /// 하이라이트 여부 속성
        /// </summary>
        public static readonly DependencyProperty IsHighlightedProperty;

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 셀 크기
        /// </summary>
        private static readonly Size _cellSize = new Size(20, 20);

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 색상 드로잉 비주얼
        /// </summary>
        private DrawingVisual colorDrawingVisual;

        /// <summary>
        /// 브러시
        /// </summary>
        private Brush brush;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 선택 여부 - IsSelected

        /// <summary>
        /// 선택 여부
        /// </summary>
        public bool IsSelected
        {
            set
            {
                SetValue(IsSelectedProperty, value);
            }
            get
            {
                return (bool)GetValue(IsSelectedProperty);
            }
        }

        #endregion
        #region 하이라이트 여부 - IsHighlighted

        /// <summary>
        /// 하이라이트 여부
        /// </summary>
        public bool IsHighlighted
        {
            set
            {
                SetValue(IsHighlightedProperty, value);
            }
            get
            {
                return (bool)GetValue(IsHighlightedProperty);
            }
        }

        #endregion
        #region 브러시 - Brush

        /// <summary>
        /// 브러시
        /// </summary>
        public Brush Brush
        {
            get
            {
                return this.brush;
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 비주얼 자식 수 - VisualChildrenCount

        /// <summary>
        /// 비주얼 자식 수
        /// </summary>
        protected override int VisualChildrenCount
        {
            get
            {
                return 1;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Static

        #region 생성자 - ColorCell()

        /// <summary>
        /// 생성자
        /// </summary>
        static ColorCell()
        {
            IsSelectedProperty = DependencyProperty.Register
            (
                "IsSelected",
                typeof(bool),
                typeof(ColorCell),
                new FrameworkPropertyMetadata
                (
                    false,
                    FrameworkPropertyMetadataOptions.AffectsRender
                )
            );

            IsHighlightedProperty = DependencyProperty.Register
            (
                "IsHighlighted",
                typeof(bool),
                typeof(ColorCell),
                new FrameworkPropertyMetadata
                (
                    false,
                    FrameworkPropertyMetadataOptions.AffectsRender
                )
            );
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - ColorCell(color)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="color">색상</param>
        public ColorCell(Color color)
        {
            this.colorDrawingVisual = new DrawingVisual();

            DrawingContext drawingContext = this.colorDrawingVisual.RenderOpen();

            Rect rect = new Rect(new Point(0, 0), _cellSize);

            rect.Inflate(-4, -4);

            Pen pen = new Pen(SystemColors.ControlTextBrush, 1);

            this.brush = new SolidColorBrush(color);

            drawingContext.DrawRectangle(this.brush, pen, rect);

            drawingContext.Close();

            AddVisualChild(this.colorDrawingVisual);

            AddLogicalChild(this.colorDrawingVisual);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Method
        //////////////////////////////////////////////////////////////////////////////// Protected

        #region 비주얼 자식 구하기 - GetVisualChild(index)

        /// <summary>
        /// 비주얼 자식 구하기
        /// </summary>
        /// <param name="index">인덱스</param>
        /// <returns>비주얼 자식</returns>
        protected override Visual GetVisualChild(int index)
        {
            if(index > 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            return this.colorDrawingVisual;
        }

        #endregion
        #region 측정하기 (오버라이딩) - MeasureOverride(availableSize)

        /// <summary>
        /// 측정하기 (오버라이딩)
        /// </summary>
        /// <param name="availableSize">이용 가능한 크기</param>
        /// <returns>측정 크기</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            return _cellSize;
        }

        #endregion
        #region 렌더링 처리하기 - OnRender(drawingContext)

        /// <summary>
        /// 렌더링 처리하기
        /// </summary>
        /// <param name="drawingContext">DrawingContext</param>
        protected override void OnRender(DrawingContext drawingContext)
        {
            Rect rect = new Rect(new Point(0, 0), RenderSize);

            rect.Inflate(-1, -1);

            Pen pen = new Pen(SystemColors.HighlightBrush, 1);

            if(IsHighlighted)
            {
                drawingContext.DrawRectangle(SystemColors.ControlDarkBrush, pen, rect);
            }
            else if(IsSelected)
            {
                drawingContext.DrawRectangle(SystemColors.ControlLightBrush, pen, rect);
            }
            else
            {
                drawingContext.DrawRectangle(Brushes.Transparent, null, rect);
            }
        }

        #endregion
    }
}

 

728x90

 

▶ ColorGrid.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace TestProject
{
    /// <summary>
    /// 색상 그리드
    /// </summary>
    public class ColorGrid : Control
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 선택 색상 변경시 - SelectedColorChanged

        /// <summary>
        /// 선택 색상 변경시
        /// </summary>
        public event EventHandler SelectedColorChanged;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 행 수
        /// </summary>
        private const int ROW_COUNT = 5;

        /// <summary>
        /// 컬럼 수
        /// </summary>
        private const int COLUMN_COUNT = 8;

        /// <summary>
        /// 색상 문자열 배열
        /// </summary>
        private string[,] colorStringArray = new string[ROW_COUNT, COLUMN_COUNT]
        {
            { "Black"    , "Brown"    , "DarkGreen"  , "MidnightBlue", "Navy"     , "DarkBlue"    , "Indigo"   , "DimGray"   },
            { "DarkRed"  , "OrangeRed", "Olive"      , "Green"       , "Teal"     , "Blue"        , "SlateGray", "Gray"      },
            { "Red"      , "Orange"   , "YellowGreen", "SeaGreen"    , "Aqua"     , "LightBlue"   , "Violet"   , "DarkGray"  },
            { "Pink"     , "Gold"     , "Yellow"     , "Lime"        , "Turquoise", "SkyBlue"     , "Plum"     , "LightGray" },
            { "LightPink", "Tan"      , "LightYellow", "LightGreen"  , "LightCyan", "LightSkyBlue", "Lavender" , "White"     }
        };

        /// <summary>
        /// 색상 셀 배열
        /// </summary>
        private ColorCell[,] colorCellArray = new ColorCell[ROW_COUNT, COLUMN_COUNT];

        /// <summary>
        /// 선택 색상 셀
        /// </summary>
        private ColorCell selectedColorCell;

        /// <summary>
        /// 하이라이트 색상 셀
        /// </summary>
        private ColorCell highlightedColorCell;

        /// <summary>
        /// 테두리
        /// </summary>
        private Border border;

        /// <summary>
        /// 유니폼 그리드
        /// </summary>
        private UniformGrid uniformGrid;

        /// <summary>
        /// 선택 색상
        /// </summary>
        private Color selectedColor = Colors.Black;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 선택 색상 - SelectedColor

        /// <summary>
        /// 선택 색상
        /// </summary>
        public Color SelectedColor
        {
            get
            {
                return this.selectedColor;
            }
        }

        #endregion
        #region 비주얼 자식 수 - VisualChildrenCount

        /// <summary>
        /// 비주얼 자식 수
        /// </summary>
        protected override int VisualChildrenCount
        {
            get
            {
                return 1;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - ColorGrid()

        /// <summary>
        /// 생성자
        /// </summary>
        public ColorGrid()
        {
            this.border = new Border();

            this.border.BorderBrush     = SystemColors.ControlDarkDarkBrush;
            this.border.BorderThickness = new Thickness(1);


            AddVisualChild(this.border);

            AddLogicalChild(this.border);


            this.uniformGrid = new UniformGrid();

            this.uniformGrid.Background = SystemColors.WindowBrush;
            this.uniformGrid.Columns    = COLUMN_COUNT;

            this.border.Child = this.uniformGrid;

            for(int y = 0; y < ROW_COUNT; y++)
            {
                for(int x = 0; x < COLUMN_COUNT; x++)
                {
                    Color color = (Color)typeof(Colors).GetProperty(colorStringArray[y, x]).GetValue(null, null);

                    this.colorCellArray[y, x] = new ColorCell(color);

                    this.uniformGrid.Children.Add(this.colorCellArray[y, x]);

                    if(color == SelectedColor)
                    {
                        this.selectedColorCell = this.colorCellArray[y, x];

                        this.colorCellArray[y, x].IsSelected = true;
                    }

                    ToolTip toolTip = new ToolTip();

                    toolTip.Content = colorStringArray[y, x];

                    this.colorCellArray[y, x].ToolTip = toolTip;
                }
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Protected

        #region 비주얼 자식 구하기 - GetVisualChild(index)

        /// <summary>
        /// 비주얼 자식 구하기
        /// </summary>
        /// <param name="index">인덱스</param>
        /// <returns></returns>
        protected override Visual GetVisualChild(int index)
        {
            if(index > 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            return this.border;
        }

        #endregion
        #region 측정하기 (오버라이딩) - MeasureOverride(availableSize)

        /// <summary>
        /// 측정하기 (오버라이딩)
        /// </summary>
        /// <param name="availableSize">이용 가능한 크기</param>
        /// <returns>측정 크기</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            this.border.Measure(availableSize);

            return this.border.DesiredSize;
        }

        #endregion
        #region 배열하기 (오버라이딩) - ArrangeOverride(finalSize)

        /// <summary>
        /// 배열하기 (오버라이딩)
        /// </summary>
        /// <param name="finalSize">최종 크기</param>
        /// <returns>최종 크기</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            this.border.Arrange(new Rect(new Point(0, 0), finalSize));

            return finalSize;
        }

        #endregion

        #region 마우스 ENTER 처리하기 - OnMouseEnter(e)

        /// <summary>
        /// 마우스 ENTER 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);

            if(this.highlightedColorCell != null)
            {
                this.highlightedColorCell.IsHighlighted = false;

                this.highlightedColorCell = null;
            }
        }

        #endregion
        #region 마우스 이동시 처리하기 - OnMouseMove(e)

        /// <summary>
        /// 마우스 이동시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            ColorCell colorCell = e.Source as ColorCell;

            if(colorCell != null)
            {
                if(this.highlightedColorCell != null)
                {
                    this.highlightedColorCell.IsHighlighted = false;
                }

                this.highlightedColorCell = colorCell;

                this.highlightedColorCell.IsHighlighted = true;
            }
        }

        #endregion
        #region 마우스 DOWN 처리하기 - OnMouseDown(e)

        /// <summary>
        /// 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);

            ColorCell colorCell = e.Source as ColorCell;

            if(colorCell != null)
            {
                if(this.selectedColorCell != null)
                {
                    this.selectedColorCell.IsSelected = false;
                }

                this.selectedColorCell = colorCell;

                this.selectedColorCell.IsSelected = true;
            }

            Focus();
        }

        #endregion
        #region 마우스 UP 처리하기 - OnMouseUp(e)

        /// <summary>
        /// 마우스 UP 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            base.OnMouseUp(e);

            ColorCell colorCell = e.Source as ColorCell;

            if(colorCell != null)
            {
                if(this.selectedColorCell != null)
                {
                    this.selectedColorCell.IsSelected = false;
                }

                this.selectedColorCell = colorCell;

                this.selectedColorCell.IsSelected = true;

                this.selectedColor = (this.selectedColorCell.Brush as SolidColorBrush).Color;

                OnSelectedColorChanged(EventArgs.Empty);
            }
        }

        #endregion
        #region 마우스 LEAVE 처리하기 - OnMouseLeave(e)

        /// <summary>
        /// 마우스 LEAVE 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);

            if(this.highlightedColorCell != null)
            {
                this.highlightedColorCell.IsHighlighted = false;

                this.highlightedColorCell = null;
            }
        }

        #endregion

        #region 키보드 포커스 획득시 처리하기 - OnGotKeyboardFocus(e)

        /// <summary>
        /// 키보드 포커스 획득시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnGotKeyboardFocus(e);

            if(this.highlightedColorCell == null)
            {
                if(this.selectedColorCell != null)
                {
                    this.highlightedColorCell = this.selectedColorCell;
                }
                else
                {
                    this.highlightedColorCell = this.colorCellArray[0, 0];
                }

                this.highlightedColorCell.IsHighlighted = true;
            }
        }

        #endregion
        #region 키 DOWN 처리하기 - OnKeyDown(e)

        /// <summary>
        /// 키 DOWN 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);

            int index = this.uniformGrid.Children.IndexOf(this.highlightedColorCell);
            int y     = index / COLUMN_COUNT;
            int x     = index % COLUMN_COUNT;

            switch(e.Key)
            {
                case Key.Home :

                    y = 0;
                    x = 0;

                    break;

                case Key.End :

                    y = ROW_COUNT    - 1;
                    x = COLUMN_COUNT + 1;

                    break;

                case Key.Down :

                    if((y = (y + 1) % ROW_COUNT) == 0)
                    {
                        x++;
                    }

                    break;

                case Key.Up :

                    if((y = (y + ROW_COUNT - 1) % ROW_COUNT) == ROW_COUNT - 1)
                    {
                        x--;
                    }

                    break;

                case Key.Right :

                    if((x = (x + 1) % COLUMN_COUNT) == 0)
                    {
                        y++;
                    }

                    break;

                case Key.Left :

                    if((x = (x + COLUMN_COUNT - 1) % COLUMN_COUNT) == COLUMN_COUNT - 1)
                    {
                        y--;
                    }

                    break;

                case Key.Enter :
                case Key.Space :

                    if(this.selectedColorCell != null)
                    {
                        this.selectedColorCell.IsSelected = false;
                    }

                    this.selectedColorCell = this.highlightedColorCell;

                    this.selectedColorCell.IsSelected = true;

                    this.selectedColor = (this.selectedColorCell.Brush as SolidColorBrush).Color;

                    OnSelectedColorChanged(EventArgs.Empty);

                    break;

                default :

                    return;
            }

            if(x >= COLUMN_COUNT || y >= ROW_COUNT)
            {
                MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
            else if(x < 0 || y < 0)
            {
                MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
            }
            else
            {
                this.highlightedColorCell.IsHighlighted = false;

                this.highlightedColorCell = this.colorCellArray[y, x];

                this.highlightedColorCell.IsHighlighted = true;
            }

            e.Handled = true;
        }

        #endregion
        #region 키보드 포커스 상실시 처리하기 - OnLostKeyboardFocus(e)

        /// <summary>
        /// 키보드 포커스 상실시 처리하기
        /// </summary>
        /// <param name="e">이벤트 인자</param>
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        {
            base.OnGotKeyboardFocus(e);

            if(this.highlightedColorCell != null)
            {
                this.highlightedColorCell.IsHighlighted = false;

                this.highlightedColorCell = null;
            }
        }

        #endregion

        #region 선택 색상 변경시 처리하기 - OnSelectedColorChanged(e)

        /// <summary>
        /// 선택 색상 변경시 처리하기
        /// </summary>
        /// <param name="e">이벤트 발생자</param>
        protected virtual void OnSelectedColorChanged(EventArgs e)
        {
            if(SelectedColorChanged != null)
            {
                SelectedColorChanged(this, e);
            }
        }

        #endregion
    }
}

 

300x250

 

▶ MainWindow.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            SizeToContent = SizeToContent.WidthAndHeight;
            Padding       = new Thickness(10);
            FontFamily    = new FontFamily("나눔고딕코딩");
            FontSize      = 16;
            Title         = "Control 클래스 : 색상 그리드 사용하기";

            StackPanel stackPanel = new StackPanel();

            stackPanel.Orientation = Orientation.Horizontal;

            Content = stackPanel;

            Button button1 = new Button();

            button1.Content             = "테스트 버튼";
            button1.Margin              = new Thickness(24);
            button1.HorizontalAlignment = HorizontalAlignment.Center;
            button1.VerticalAlignment   = VerticalAlignment.Center;

            stackPanel.Children.Add(button1);

            ColorGrid colorGrid = new ColorGrid();

            colorGrid.Margin              = new Thickness(24);
            colorGrid.HorizontalAlignment = HorizontalAlignment.Center;
            colorGrid.VerticalAlignment   = VerticalAlignment.Center;

            colorGrid.SelectedColorChanged += colorGrid_SelectedColorChanged;

            stackPanel.Children.Add(colorGrid);

            Button button2 = new Button();

            button2.Content             = "테스트 버튼";
            button2.Margin              = new Thickness(24);
            button2.HorizontalAlignment = HorizontalAlignment.Center;
            button2.VerticalAlignment   = VerticalAlignment.Center;

            stackPanel.Children.Add(button2);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 프로그램 시작하기 - Main()

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        [STAThread]
        private static void Main()
        {
            Application application = new Application();

            application.Run(new MainWindow());
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Instance
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 색상 그리드 선택 색상 변경시 처리하기 - colorGrid_SelectedColorChanged(sender, e)

        /// <summary>
        /// 색상 그리드 선택 색상 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void colorGrid_SelectedColorChanged(object sender, EventArgs e)
        {
            ColorGrid colorGrid = sender as ColorGrid;

            Background = new SolidColorBrush(colorGrid.SelectedColor);
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요