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

TestProject.zip
다운로드

▶ AngleGradientBrush.cs

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace TestProject
{
    [ContentProperty("Gradients")]
    [MarkupExtensionReturnType(typeof(ImageBrush))]
    public class AngleGradientBrush : MarkupExtension, INotifyPropertyChanged
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 속성 변경시 이벤트 - PropertyChanged

        /// <summary>
        /// 속성 변경시 이벤트
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

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

        #region Field

        /// <summary>
        /// 그라디언트 중단 컬렉션
        /// </summary>
        private GradientStopCollection gradientStopCollection = null;

        /// <summary>
        /// 그라디언트 크기
        /// </summary>
        private int gradientSize = 500;

        /// <summary>
        /// 그라디언트 디테일
        /// </summary>
        private double gradientDetail = 10;

        /// <summary>
        /// 중심 포인트
        /// </summary>
        private Point centerPoint = new Point(0.5, 0.5);

        #endregion

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

        #region 그라디언트 중단 컬렉션 - Gradients

        /// <summary>
        /// 그라디언트 중단 컬렉션
        /// </summary>
        public GradientStopCollection Gradients
        {
            get
            {
                return this.gradientStopCollection;
            }
            set 
            {
                this.gradientStopCollection = value;

                this.gradientStopCollection.Changed += gradientStopCollection_Changed;

                FirePropertyChangedEvent("Gradients"); 
            }
        }

        #endregion
        #region 그라디언트 크기 - GradientSize

        /// <summary>
        /// 그라디언트 크기
        /// </summary>
        public int GradientSize
        {
            get
            {
                return this.gradientSize;
            }
            set
            {
                this.gradientSize = value;
                
                FirePropertyChangedEvent("GradientSize");
            }
        }

        #endregion
        #region 그라디언트 디테일 - GradientDetail

        /// <summary>
        /// 그라디언트 디테일
        /// </summary>
        public double GradientDetail
        {
            get
            {
                return this.gradientDetail;
            }
            set
            {
                this.gradientDetail = value;
                
                FirePropertyChangedEvent("GradientDetail");
            }
        }

        #endregion
        #region 중심 포인트 - CenterPoint

        /// <summary>
        /// 중심 포인트
        /// </summary>
        public Point CenterPoint
        {
            get
            {
                return this.centerPoint;
            }
            set
            {
                this.centerPoint = value;
                
                FirePropertyChangedEvent("CenterPoint");
            }
        }

        #endregion

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

        #region 타겟 객체 - TargetObject

        /// <summary>
        /// 타겟 객체
        /// </summary>
        private DependencyObject TargetObject { get; set; }

        #endregion
        #region 타겟 속성 - TargetProperty

        /// <summary>
        /// 타겟 속성
        /// </summary>
        private DependencyProperty TargetProperty { get; set; }

        #endregion
        #region 기본 브러시 - BaseBrush

        /// <summary>
        /// 기본 브러시
        /// </summary>
        private ImageBrush BaseBrush { get; set; }

        #endregion

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

        #region 생성자 - AngleGradientBrush()

        /// <summary>
        /// 생성자
        /// </summary>
        public AngleGradientBrush()
        {
            BaseBrush = new ImageBrush();
            Gradients = new GradientStopCollection();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 값 제공하기 - ProvideValue(serviceProvider)

        /// <summary>
        /// 값 제공하기
        /// </summary>
        /// <param name="serviceProvider">서비스 공급자</param>
        /// <returns>값</returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            UpdateBrush();

            return BaseBrush;
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 그라데이션 색상 배열 구하기 - GetGradationColorArray()

        /// <summary>
        /// 그라데이션 색상 배열 구하기
        /// </summary>
        /// <returns>그라데이션 색상 배열</returns>
        protected int[] GetGradationColorArray()
        {
            int gradationCount = (int)(360 / GradientDetail);

            int[] gradationColorArray = new int[gradationCount];

            DrawingVisual DrawingVisual = new DrawingVisual();

            DrawingContext DrawingContext = DrawingVisual.RenderOpen();

            LinearGradientBrush linearGradientBrush = new LinearGradientBrush(Gradients)
            {
                StartPoint = new Point(0, 0),
                EndPoint   = new Point(1, 0)
            };

            DrawingContext.DrawRectangle(linearGradientBrush, null, new Rect(0, 0, gradationCount, 1));

            DrawingContext.Close();

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(gradationCount, 1, 96, 96, PixelFormats.Pbgra32);

            renderTargetBitmap.Render(DrawingVisual);           

            renderTargetBitmap.CopyPixels(new Int32Rect(0, 0, gradationCount, 1), gradationColorArray, gradationCount * 4, 0);

            return gradationColorArray;
        }
        
        #endregion
        #region 브러시 업데이트하기 - UpdateBrush()

        /// <summary>
        /// 브러시 업데이트하기
        /// </summary>
        protected void UpdateBrush()
        {
            int size = GradientSize * 2;

            Point actualCenterPoint = new Point(size * CenterPoint.X, size * CenterPoint.Y);

            int[,] pixelArray = new int[size, size];

            int[] gradationColorArray = GetGradationColorArray();

            for(int x = 0; x < size; x++)
            {
                for(int y = 0; y < size; y++)
                {
                    double angle = Math.Atan2(y - actualCenterPoint.X, x - actualCenterPoint.Y) * 180 / Math.PI;

                    int colorIndex = (int)(angle / GradientDetail);

                    if(colorIndex < 0)
                    {
                        colorIndex = gradationColorArray.Length + colorIndex;
                    }

                    int color = gradationColorArray[colorIndex];

                    pixelArray[x, y] = color;
                }
            }

            WriteableBitmap writeableBitmap = new WriteableBitmap(size, size, 96, 96, PixelFormats.Pbgra32, null);

            writeableBitmap.WritePixels(new Int32Rect(0, 0, size, size), pixelArray, (int)writeableBitmap.Width * 4, 0);

            writeableBitmap.Freeze();

            BaseBrush.ImageSource = writeableBitmap;
        }

        #endregion

        #region 속성 변경시 이벤트 발생시키기 - FirePropertyChangedEvent(propertyName)

        /// <summary>
        /// 속성 변경시 이벤트 발생시키기
        /// </summary>
        /// <param name="propertyName">속성명</param>
        protected void FirePropertyChangedEvent(string propertyName)
        {
            UpdateBrush();

            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 그라디언트 중단 컬렉션 변경시 처리하기 - gradientStopCollection_Changed(sender, e)

        /// <summary>
        /// 그라디언트 중단 컬렉션 변경시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void gradientStopCollection_Changed(object sender, EventArgs e)
        {
            FirePropertyChangedEvent("GradientDetail");
        }

        #endregion
    }
}

 

728x90

 

▶ 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:s="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:TestProject"
    Width="800"
    Height="600"
    Title="MarkupExtension 클래스 : 마크업 확장 사용하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Window.Resources>
        <ObjectDataProvider x:Key="ColorTypeObjectDataProviderKey"
            MethodName="GetType"
            ObjectType="{x:Type s:Type}">
            <ObjectDataProvider.MethodParameters>
                <s:String>
                    System.Windows.Media.Colors,PresentationCore,Version=3.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35
                </s:String>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
        <ObjectDataProvider x:Key="ColorPropertiesObjectDataProviderKey"
            ObjectInstance="{StaticResource ColorTypeObjectDataProviderKey}" 
            MethodName="GetProperties" />
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300" />
            <ColumnDefinition Width="*"   />
        </Grid.ColumnDefinitions>
        <Border Grid.Column="0" Margin="3">
            <GroupBox Header="설정">
                <StackPanel>
                    <TextBlock Margin="0 3 0 3">Gradient Stop 목록</TextBlock>
                    <ListBox Name="colorListBox"
                        HorizontalAlignment="Stretch"
                        Height="200"
                        BorderThickness="1"
                        Padding="3">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Rectangle
                                    HorizontalAlignment="Center"
                                    Width="280"
                                    Height="20"
                                    Fill="{Binding Path=Name}" />
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                    <Grid Margin="0 5 0 0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50*" />
                            <ColumnDefinition Width="3"   />
                            <ColumnDefinition Width="25*" />
                            <ColumnDefinition Width="3"   />
                            <ColumnDefinition Width="25*" />
                        </Grid.ColumnDefinitions>
                        <ComboBox Name="colorComboBox"
                            Grid.Column="0"
                            ItemsSource="{Binding Source={StaticResource ColorPropertiesObjectDataProviderKey}}">
                            <ComboBox.ItemTemplate>
                                <DataTemplate>
                                    <Rectangle
                                        Width="100"
                                        Height="20"
                                        Fill="{Binding Path=Name}" />
                                </DataTemplate>
                            </ComboBox.ItemTemplate>
                        </ComboBox>
                        <Button Name="addButton"    Grid.Column="2" Content="추가" />
                        <Button Name="deleteButton" Grid.Column="4" Content="삭제" />
                    </Grid>
                    <TextBlock Margin="0 30 0 3">
                        Gradient Size
                    </TextBlock>
                    <Slider
                        Minimum="10"
                        Maximum="600"
                        Value="{Binding ElementName=angleGradientBrush, Path=GradientSize}" />
                    <TextBlock Margin="0 10 0 3">
                        Gradient Detail
                    </TextBlock>
                    <Slider
                        Minimum="0.1"
                        Maximum="100"
                        Value="{Binding ElementName=angleGradientBrush, Path=GradientDetail}" />
                </StackPanel>
            </GroupBox>
        </Border>
        <Border Grid.Column="1" Margin="3">
            <GroupBox Header="브러시">
                <Ellipse Name="brushEllipse"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Width="420"
                    Height="420">
                    <Ellipse.Fill>
                        <local:AngleGradientBrush x:Name="angleGradientBrush" />
                    </Ellipse.Fill>
                </Ellipse>
            </GroupBox>
        </Border>
    </Grid>
</Window>

 

300x250

 

▶ MainWindow.xaml.cs

using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

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

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            this.addButton.Click        += addButton_Click;
            this.deleteButton.Click     += deleteButton_Click;
            this.brushEllipse.MouseDown += ellipseBrush_MouseDown;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 추가 버튼 클릭시 처리하기 - addButton_Click(sender, e)

        /// <summary>
        /// 추가 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void addButton_Click(object sender, RoutedEventArgs e)
        {
            if(this.colorComboBox.SelectedItem != null)
            {
                this.colorListBox.Items.Add(this.colorComboBox.SelectedItem);

                UpdateAngleGradientBrush();
            }
        }

        #endregion
        #region 삭제 버튼 클릭시 처리하기 - deleteButton_Click(sender, e)

        /// <summary>
        /// 삭제 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void deleteButton_Click(object sender, RoutedEventArgs e)
        {
            if(this.colorListBox.SelectedItem != null)
            {
                this.colorListBox.Items.Remove(this.colorListBox.SelectedItem);

                UpdateAngleGradientBrush();
            }
        }

        #endregion
        #region 브러시 원 마우스 다운시 처리하기 - ellipseBrush_MouseDown(sender, e)

        /// <summary>
        /// 브러시 원 마우스 다운시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void ellipseBrush_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Point mousePoint  = e.GetPosition(brushEllipse);
            Point centerPoint = new Point(mousePoint.X / brushEllipse.Width, mousePoint.Y / brushEllipse.Height);

            this.angleGradientBrush.CenterPoint = centerPoint;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 각도 그라디언트 브러시 갱신하기 - UpdateAngleGradientBrush()

        /// <summary>
        /// 각도 그라디언트 브러시 갱신하기
        /// </summary>
        private void UpdateAngleGradientBrush()
        {
            double offset = 1d / (this.colorListBox.Items.Count - 1);

            if(offset == double.PositiveInfinity)
            {
                offset = 1d;
            }

            GradientStopCollection gradientStopCollection = new GradientStopCollection();

            for(int i = 0; i < this.colorListBox.Items.Count; i++)
            {
                Color color = (Color)ColorConverter.ConvertFromString((this.colorListBox.Items[i] as PropertyInfo).Name);

                gradientStopCollection.Add(new GradientStop(){ Color = color, Offset = offset * i });
            }
          
            this.angleGradientBrush.Gradients = gradientStopCollection;
        }

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

댓글을 달아 주세요