728x90
반응형
728x170
▶ 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
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] 마우스 애니메이션 사용하기 (0) | 2018.02.18 |
---|---|
[C#/WPF] 하이브리드 시계 사용하기 (0) | 2018.02.18 |
[C#/WPF] 마우스 드래그를 사용해 원 그리기 (0) | 2018.02.18 |
[C#/WPF] 도트 폰트 생성하기 (0) | 2018.02.18 |
[C#/WPF] 글자 애니메이션 사용하기 (0) | 2018.02.18 |
[C#/WPF] MediaElement 클래스 : 동영상 재생하기 (0) | 2017.06.14 |
[C#/WPF] ListView 클래스 : 그리드 뷰 컬럼 헤더 클릭시 정렬하기 (0) | 2017.06.11 |
[C#/WPF] DataGrid 클래스 : RowValidationRules 속성을 사용해 검증하기 (0) | 2017.06.11 |
[C#/WPF] DataGrid 클래스 : 그룹핑, 정렬 및 필터링 사용하기 (0) | 2017.06.11 |
[C#/WPF] 방사형 패널 사용하기 (0) | 2017.06.11 |
댓글을 달아 주세요