728x90
반응형
728x170
▶ FrameworkElementExtention.cs
using System.Windows;
using System.Windows.Media;
namespace TestProject
{
/// <summary>
/// 프레임워크 엘리먼트 확장
/// </summary>
public static class FrameworkElementExtention
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 회전하기 - Rotate(source, angle)
/// <summary>
/// 회전하기
/// </summary>
/// <param name="source">소스 엘리먼트</param>
/// <param name="angle">각도</param>
public static void Rotate(this FrameworkElement source, double angle)
{
source.RenderTransformOrigin = new Point(0.5, 1);
source.HorizontalAlignment = HorizontalAlignment.Center;
source.VerticalAlignment = VerticalAlignment.Center;
if(source.RenderTransform is RotateTransform)
{
(source.RenderTransform as RotateTransform).Angle = angle;
}
else
{
source.RenderTransform = new RotateTransform(angle);
}
}
#endregion
}
}
728x90
▶ CircularGrid.cs
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace TestProject
{
/// <summary>
/// 환형 그리드
/// </summary>
public class CircularGrid : Grid
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 회전 변환 - RotateTransform
/// <summary>
/// 회전 변환
/// </summary>
public RotateTransform RotateTransform { get; private set; }
#endregion
#region 이동 변환 - TranslateTransform
/// <summary>
/// 이동 변환
/// </summary>
public TranslateTransform TranslateTransform { get; private set; }
#endregion
#region 항목 각도 - ItemAngle
/// <summary>
/// 항목 각도
/// </summary>
public double ItemAngle { get; private set; }
#endregion
#region 항목 너비 - ItemWidth
/// <summary>
/// 항목 너비
/// </summary>
public double ItemWidth { get; private set; }
#endregion
#region 항목 높이 - ItemHeight
/// <summary>
/// 항목
/// </summary>
public double ItemHeight { get; private set; }
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - CircularGrid()
/// <summary>
/// 생성자
/// </summary>
public CircularGrid()
{
RenderTransformOrigin = new Point(0.5, 0.5);
TransformGroup transformGroup = new TransformGroup();
RotateTransform = new RotateTransform();
TranslateTransform = new TranslateTransform();
transformGroup.Children.Add(RotateTransform );
transformGroup.Children.Add(TranslateTransform);
RenderTransform = transformGroup;
PreviewMouseWheel += Grid_PreviewMouseWheel;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 그리드 프리뷰 마우스 DOWN 처리하기 - Grid_PreviewMouseDown(sender, e)
/// <summary>
/// 그리드 프리뷰 마우스 DOWN 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement selectedItem = sender as FrameworkElement;
double currentAngle = RotateTransform.Angle % 360 ;
int itemCount = Children.Count;
int currentIndex = itemCount - (int)(currentAngle / ItemAngle);
int selectedIndex = Children.IndexOf(selectedItem);
int distance = selectedIndex - currentIndex;
int absoluteDistance = Math.Abs(distance);
double rotateAngle = 0;
if(distance > 0)
{
if(absoluteDistance > itemCount / 2)
{
rotateAngle = (itemCount - absoluteDistance) * ItemAngle;
}
else
{
rotateAngle = -(absoluteDistance * ItemAngle);
}
}
else
{
if(absoluteDistance > itemCount / 2)
{
rotateAngle = -(itemCount - absoluteDistance) * ItemAngle;
}
else
{
rotateAngle = absoluteDistance * ItemAngle;
}
}
DoubleAnimation angleAnimation = new DoubleAnimation()
{
SpeedRatio = 2,
AccelerationRatio = 0.7
};
angleAnimation.By = rotateAngle;
RotateTransform.BeginAnimation(RotateTransform.AngleProperty, angleAnimation, HandoffBehavior.Compose);
}
#endregion
#region 그리드 프리뷰 마우스 휠 처리하기 - Grid_PreviewMouseWheel(sender, e)
/// <summary>
/// 그리드 프리뷰 마우스 휠 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Grid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
DoubleAnimation angleAnimation = new DoubleAnimation()
{
SpeedRatio = 2,
AccelerationRatio = 0.7
};
angleAnimation.By = (e.Delta > 0 ? -ItemAngle : ItemAngle);
RotateTransform.BeginAnimation(RotateTransform.AngleProperty, angleAnimation, HandoffBehavior.Compose);
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Protected
#region 비주얼 자식 컬렉션 변경시 처리하기 - OnVisualChildrenChanged(addedObject, removedObject)
/// <summary>
/// 비주얼 자식 컬렉션 변경시 처리하기
/// </summary>
/// <param name="addedObject">추가 객체</param>
/// <param name="removedObject">제거 객체</param>
protected override void OnVisualChildrenChanged(DependencyObject addedObject, DependencyObject removedObject)
{
if(addedObject != null)
{
(addedObject as FrameworkElement).PreviewMouseDown += Grid_PreviewMouseDown;
}
else if(removedObject != null)
{
(addedObject as FrameworkElement).PreviewMouseDown -= Grid_PreviewMouseDown;
}
base.OnVisualChildrenChanged(addedObject, removedObject);
UpdateList();
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 리스트 업데이트하기 - UpdateList()
/// <summary>
/// 리스트 업데이트하기
/// </summary>
private void UpdateList()
{
if(!IsInitialized)
{
return;
}
int itemCount = Children.Count;
ItemAngle = 360.0 / itemCount;
if(IsItemsHost == true)
{
FrameworkElement Parent = TemplatedParent as FrameworkElement;
ItemWidth = (Parent.Width * Math.PI) / (itemCount * 1.5);
ItemHeight = Parent.Height / 2;
}
else
{
ItemWidth = (this.ActualWidth * Math.PI) / (itemCount * 1.5);
ItemHeight = this.ActualHeight / 2;
}
int i = 0;
foreach(FrameworkElement child in Children)
{
child.Width = ItemWidth;
child.Height = ItemHeight;
child.Rotate(i * ItemAngle);
i++;
}
TranslateTransform.Y = -ItemHeight / 2;
RotateTransform.CenterY = ItemHeight / 2;
}
#endregion
}
}
300x250
▶ 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:local="clr-namespace:TestProject"
Width="800"
Height="600"
Title="Grid 클래스 : 환형 패널 사용하기"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid>
<ListBox Name="listBox"
Width="400"
Height="400">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Transparent" />
</ListBox.Resources>
<ListBox.Template>
<ControlTemplate>
<local:CircularGrid IsItemsHost="True" />
</ControlTemplate>
</ListBox.Template>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="맥주"
Source="IMAGE/beer.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="메달"
Source="IMAGE/medal.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="연필"
Source="IMAGE/pencil.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="방사능"
Source="IMAGE/radiation.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="반지"
Source="IMAGE/ring.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="맥주"
Source="IMAGE/beer.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="메달"
Source="IMAGE/medal.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="연필"
Source="IMAGE/pencil.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="방사능"
Source="IMAGE/radiation.png" />
</Grid>
<Grid>
<Rectangle
Width="40"
Height="100"
Fill="Gray"
Opacity="0.5" />
<Image
Width="32"
Height="32"
Tag="반지"
Source="IMAGE/ring.png" />
</Grid>
</ListBox>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="20"
FontWeight="Bold"
Text="{Binding ElementName=listBox, Path=SelectedValue.Children[1].Tag}" />
</Grid>
</Window>
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] FFMpeg을 사용해 웹 카메라 사용하기 (기능 개선) (0) | 2020.12.25 |
---|---|
[C#/WPF] ItemsControl 클래스 : 리스트 컨트롤 사용하기 (드래그 기능 개선) (0) | 2020.12.19 |
[C#/WPF] MarkupExtension 클래스 : 마크업 확장 사용하기 (0) | 2020.12.15 |
[C#/WPF] Image 클래스 : LayoutUpdated 이벤트를 사용해 이미지 픽셀 보정하기 (0) | 2020.12.13 |
[C#/WPF] FrameworkElement 클래스 : 장평을 설정하는 커스텀 텍스트 블럭 사용하기 (0) | 2020.12.13 |
[C#/WPF] ObjectDataProvider 엘리먼트 : Colors 클래스의 색상 정적 속성 구하기 (0) | 2020.12.07 |
[C#/WPF] 파노라마 뷰 사용하기 (0) | 2020.12.06 |
[C#/WPF] TabControl 클래스 : FADE IN/OUT 탭 컨트롤 사용하기 (0) | 2020.12.06 |
[C#/WPF] FrameworkElement 엘리먼트 : FocusVisualStyle 속성을 사용해 포커스 사각형 제거하기 (0) | 2020.12.05 |
[C#/WPF] UIElement 클래스 : MouseMove 이벤트를 사용해 마우스 이동시 애니메이션 설정하기 (0) | 2020.12.05 |
댓글을 달아 주세요