728x90
반응형
728x170
▶ CustomButtonChrome.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace TestProject
{
/// <summary>
/// 커스텀 크롬 버튼
/// </summary>
public sealed class CustomButtonChrome : Decorator
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Class
////////////////////////////////////////////////////////////////////////////////////////// Private
#region 지역 리소스 - LocalResource
/// <summary>
/// 지역 리소스
/// </summary>
private class LocalResource
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 내부 테두리 펜
/// </summary>
public Pen InnerBorderPen;
/// <summary>
/// 테두리 오버레이 펜
/// </summary>
public Pen BorderOverlayPen;
/// <summary>
/// 배경 오버레이 브러시
/// </summary>
public LinearGradientBrush BackgroundOverlayBrush;
/// <summary>
/// 왼쪽 DROP SHADOW 브러시
/// </summary>
public LinearGradientBrush LeftDropShadowBrush;
/// <summary>
/// 위쪽 DROP SHADOW
/// </summary>
public LinearGradientBrush TopDropShadowBrush;
#endregion
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 테두리 브러시 색상 - BorderBrushProperty
/// <summary>
/// 테두리 브러시 색상
/// </summary>
public static readonly DependencyProperty BorderBrushProperty = Border.BorderBrushProperty.AddOwner
(
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
null,
FrameworkPropertyMetadataOptions.AffectsRender
)
);
#endregion
#region 라운드 코너 여부 속성 - RoundCornersProperty
/// <summary>
/// 라운드 코너 여부 속성
/// </summary>
public static readonly DependencyProperty RoundCornersProperty = DependencyProperty.Register
(
"RoundCorners",
typeof(bool),
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
true,
FrameworkPropertyMetadataOptions.AffectsRender
)
);
#endregion
#region 내부 테두리 비활성화 여부 속성 - DisableInnerBorderProperty
/// <summary>
/// 내부 테두리 비활성화 여부 속성
/// </summary>
public static readonly DependencyProperty DisableInnerBorderProperty = DependencyProperty.Register
(
"DisableInnerBorder",
typeof(bool),
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
true,
FrameworkPropertyMetadataOptions.AffectsRender
)
);
#endregion
#region 배경 색상 - BackgroundProperty
/// <summary>
/// 배경 색상
/// </summary>
public static readonly DependencyProperty BackgroundProperty = Control.BackgroundProperty.AddOwner
(
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
null,
FrameworkPropertyMetadataOptions.AffectsRender
)
);
#endregion
#region 디폴트 렌더링 여부 속성 - RenderDefaultedProperty
/// <summary>
/// 디폴트 렌더링 여부 속성
/// </summary>
public static readonly DependencyProperty RenderDefaultedProperty = DependencyProperty.Register
(
"RenderDefaulted",
typeof(bool),
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
false,
new PropertyChangedCallback(RenderDefaultedPropertyChangedCallback)
)
);
#endregion
#region 마우스 오버 렌더링 여부 속성 - RenderMouseOverProperty
/// <summary>
/// 마우스 오버 렌더링 여부 속성
/// </summary>
public static readonly DependencyProperty RenderMouseOverProperty = DependencyProperty.Register
(
"RenderMouseOver",
typeof(bool),
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
false,
new PropertyChangedCallback(RenderMouseOverPropertyChangedCallback)
)
);
#endregion
#region PRESS 렌더링 여부 속성 - RenderPressedProperty
/// <summary>
/// PRESS 렌더링 여부 속성
/// </summary>
public static readonly DependencyProperty RenderPressedProperty = DependencyProperty.Register
(
"RenderPressed",
typeof(bool),
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
false,
new PropertyChangedCallback(RenderPressedPropertyChangedCallback)
)
);
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 공통 테두리 펜
/// </summary>
private static Pen _commonBorderPen;
/// <summary>
/// 공통 디폴트 내부 테두리 펜
/// </summary>
private static Pen _commonDefaultInnerBorderPen;
/// <summary>
/// 공통 내부 테두리 펜
/// </summary>
private static Pen _commonInnerBorderPen;
/// <summary>
/// 공통 비활성 테두리 오버레이 펜
/// </summary>
private static Pen _commonDisabledBorderOverlayPen;
/// <summary>
/// 공통 HOVER 테두리 오버레이 펜
/// </summary>
private static Pen _commonHoverBorderOverlayPen;
/// <summary>
/// 공통 PRESS 테두리 오버레이 펜
/// </summary>
private static Pen _commonPressedBorderOverlayPen;
/// <summary>
/// 공통 비활성 배경 오버레이 브러시
/// </summary>
private static SolidColorBrush _commonDisabledBackgroundOverlayBrush;
/// <summary>
/// 공통 HOVER 배경 오버레이 브러시
/// </summary>
private static LinearGradientBrush _commonHoverBackgroundOverlayBrush;
/// <summary>
/// 공통 PRESS 배경 오버레이 브러시
/// </summary>
private static LinearGradientBrush _commonPressedBackgroundOverlayBrush;
/// <summary>
/// 공통 PRESS 왼쪽 DROP SHADOW 브러시
/// </summary>
private static LinearGradientBrush _commonPressedLeftDropShadowBrush;
/// <summary>
/// 공통 PRESS 위쪽 DROP SHADOW 브러시
/// </summary>
private static LinearGradientBrush _commonPressedTopDropShadowBrush;
/// <summary>
/// 잠금 객체
/// </summary>
private static object _lockObject = new object();
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 로컬 리소스
/// </summary>
private LocalResource localResource;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 공통 디폴트 내부 테두리 펜 - CommonDefaultInnerBorderPen
/// <summary>
/// 공통 디폴트 내부 테두리 펜
/// </summary>
private static Pen CommonDefaultInnerBorderPen
{
get
{
if(_commonDefaultInnerBorderPen == null)
{
lock(_lockObject)
{
if(_commonDefaultInnerBorderPen == null)
{
Pen pen = new Pen
{
Thickness = 1.0,
Brush = new SolidColorBrush(Color.FromArgb(0xf9, 0, 0xcc, 0xff))
};
pen.Freeze();
_commonDefaultInnerBorderPen = pen;
}
}
}
return _commonDefaultInnerBorderPen;
}
}
#endregion
#region 공통 내부 테두리 펜 - CommonInnerBorderPen
/// <summary>
/// 공통 내부 테두리 펜
/// </summary>
private static Pen CommonInnerBorderPen
{
get
{
if(_commonInnerBorderPen == null)
{
lock(_lockObject)
{
if(_commonInnerBorderPen == null)
{
Pen pen = new Pen
{
Thickness = 1.0
};
LinearGradientBrush brush = new LinearGradientBrush
{
StartPoint = new Point(0.0, 0.0),
EndPoint = new Point(0.0, 1.0),
GradientStops =
{
new GradientStop(Color.FromArgb(250 , 0xff, 0xff, 0xff), 0.0),
new GradientStop(Color.FromArgb(0x85, 0xff, 0xff, 0xff), 1.0)
}
};
pen.Brush = brush;
pen.Freeze();
_commonInnerBorderPen = pen;
}
}
}
return _commonInnerBorderPen;
}
}
#endregion
#region 공통 비활성 테두리 오버레이 펜 - CommonDisabledBorderOverlayPen
/// <summary>
/// 공통 비활성 테두리 오버레이 펜
/// </summary>
private static Pen CommonDisabledBorderOverlayPen
{
get
{
if(_commonDisabledBorderOverlayPen == null)
{
lock(_lockObject)
{
if(_commonDisabledBorderOverlayPen == null)
{
Pen pen = new Pen
{
Thickness = 1.0,
Brush = new SolidColorBrush(Color.FromRgb(0xad, 0xb2, 0xb5))
};
pen.Freeze();
_commonDisabledBorderOverlayPen = pen;
}
}
}
return _commonDisabledBorderOverlayPen;
}
}
#endregion
#region 공통 HOVER 테두리 오버레이 펜 - CommonHoverBorderOverlayPen
/// <summary>
/// 공통 HOVER 테두리 오버레이 펜
/// </summary>
private static Pen CommonHoverBorderOverlayPen
{
get
{
if(_commonHoverBorderOverlayPen == null)
{
lock(_lockObject)
{
if(_commonHoverBorderOverlayPen == null)
{
Pen pen = new Pen
{
Thickness = 1.0,
Brush = new SolidColorBrush(Color.FromRgb(60, 0x7f, 0xb1))
};
pen.Freeze();
_commonHoverBorderOverlayPen = pen;
}
}
}
return _commonHoverBorderOverlayPen;
}
}
#endregion
#region 공통 PRESS 테두리 오버레이 펜 - CommonPressedBorderOverlayPen
/// <summary>
/// 공통 PRESS 테두리 오버레이 펜
/// </summary>
private static Pen CommonPressedBorderOverlayPen
{
get
{
if(_commonPressedBorderOverlayPen == null)
{
lock(_lockObject)
{
if(_commonPressedBorderOverlayPen == null)
{
Pen pen = new Pen
{
Thickness = 1.0,
Brush = new SolidColorBrush(Color.FromRgb(0x2c, 0x62, 0x8b))
};
pen.Freeze();
_commonPressedBorderOverlayPen = pen;
}
}
}
return _commonPressedBorderOverlayPen;
}
}
#endregion
#region 공통 비활성 배경 오버레이 브러시 - CommonDisabledBackgroundOverlayBrush
/// <summary>
/// 공통 비활성 배경 오버레이 브러시
/// </summary>
private static SolidColorBrush CommonDisabledBackgroundOverlayBrush
{
get
{
if(_commonDisabledBackgroundOverlayBrush == null)
{
lock(_lockObject)
{
if(_commonDisabledBackgroundOverlayBrush == null)
{
SolidColorBrush brush = new SolidColorBrush(Color.FromRgb(0xf4, 0xf4, 0xf4));
brush.Freeze();
_commonDisabledBackgroundOverlayBrush = brush;
}
}
}
return _commonDisabledBackgroundOverlayBrush;
}
}
#endregion
#region 공통 HOVER 배경 오버레이 브러시 - CommonHoverBackgroundOverlayBrush
/// <summary>
/// 공통 HOVER 배경 오버레이 브러시
/// </summary>
private static LinearGradientBrush CommonHoverBackgroundOverlayBrush
{
get
{
if(_commonHoverBackgroundOverlayBrush == null)
{
lock(_lockObject)
{
if(_commonHoverBackgroundOverlayBrush == null)
{
LinearGradientBrush brush = new LinearGradientBrush
{
StartPoint = new Point(0.0, 0.0),
EndPoint = new Point(0.0, 1.0),
GradientStops =
{
new GradientStop(Color.FromArgb(0xff, 0xea, 0xf6, 0xfd), 0.0),
new GradientStop(Color.FromArgb(0xff, 0xd9, 240 , 0xfc), 0.5),
new GradientStop(Color.FromArgb(0xff, 190 , 230 , 0xfd), 0.5),
new GradientStop(Color.FromArgb(0xff, 0xa7, 0xd9, 0xf5), 1.0)
}
};
brush.Freeze();
_commonHoverBackgroundOverlayBrush = brush;
}
}
}
return _commonHoverBackgroundOverlayBrush;
}
}
#endregion
#region 공통 PRESS 배경 오버레이 브러시 - CommonPressedBackgroundOverlayBrush
/// <summary>
/// 공통 PRESS 배경 오버레이 브러시
/// </summary>
private static LinearGradientBrush CommonPressedBackgroundOverlayBrush
{
get
{
if(_commonPressedBackgroundOverlayBrush == null)
{
lock(_lockObject)
{
if(_commonPressedBackgroundOverlayBrush == null)
{
LinearGradientBrush brush = new LinearGradientBrush
{
StartPoint = new Point(0.0, 0.0),
EndPoint = new Point(0.0, 1.0),
GradientStops =
{
new GradientStop(Color.FromArgb(0xff, 0xc2, 0xe4, 0xf6), 0.5),
new GradientStop(Color.FromArgb(0xff, 0xab, 0xda, 0xf3), 0.5),
new GradientStop(Color.FromArgb(0xff, 0x90, 0xcb, 0xeb), 1.0)
}
};
brush.Freeze();
_commonPressedBackgroundOverlayBrush = brush;
}
}
}
return _commonPressedBackgroundOverlayBrush;
}
}
#endregion
#region 공통 PRESS 왼쪽 DROP SHADOW 브러시 - CommonPressedLeftDropShadowBrush
/// <summary>
/// 공통 PRESS 왼쪽 DROP SHADOW 브러시
/// </summary>
private static LinearGradientBrush CommonPressedLeftDropShadowBrush
{
get
{
if(_commonPressedLeftDropShadowBrush == null)
{
lock(_lockObject)
{
if(_commonPressedLeftDropShadowBrush == null)
{
LinearGradientBrush brush = new LinearGradientBrush
{
StartPoint = new Point(0.0, 0.0),
EndPoint = new Point(1.0, 0.0),
GradientStops =
{
new GradientStop(Color.FromArgb(0x80, 0x33, 0x33, 0x33), 0.0),
new GradientStop(Color.FromArgb(0 , 0x33, 0x33, 0x33), 1.0)
}
};
brush.Freeze();
_commonPressedLeftDropShadowBrush = brush;
}
}
}
return _commonPressedLeftDropShadowBrush;
}
}
#endregion
#region 공통 PRESS 위쪽 DROP SHADOW 브러시 - CommonPressedTopDropShadowBrush
/// <summary>
/// 공통 PRESS 위쪽 DROP SHADOW 브러시
/// </summary>
private static LinearGradientBrush CommonPressedTopDropShadowBrush
{
get
{
if(_commonPressedTopDropShadowBrush == null)
{
lock(_lockObject)
{
if(_commonPressedTopDropShadowBrush == null)
{
LinearGradientBrush brush = new LinearGradientBrush
{
StartPoint = new Point(0.0, 0.0),
EndPoint = new Point(0.0, 1.0),
GradientStops =
{
new GradientStop(Color.FromArgb(0x80, 0x33, 0x33, 0x33), 0.0),
new GradientStop(Color.FromArgb(0 , 0x33, 0x33, 0x33), 1.0)
}
};
brush.Freeze();
_commonPressedTopDropShadowBrush = brush;
}
}
}
return _commonPressedTopDropShadowBrush;
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 내부 테두리 비활성화 여부 - DisableInnerBorder
/// <summary>
/// 내부 테두리 비활성화 여부
/// </summary>
public bool DisableInnerBorder
{
get
{
return (bool)GetValue(DisableInnerBorderProperty);
}
set
{
SetValue(DisableInnerBorderProperty, value);
}
}
#endregion
#region 테두리 오버레이 펜 - BorderOverlayPen
/// <summary>
/// 테두리 오버레이 펜
/// </summary>
private Pen BorderOverlayPen
{
get
{
if(!IsEnabled)
{
if(RoundCorners)
{
return CommonDisabledBorderOverlayPen;
}
return null;
}
if(!Animates)
{
if(RenderPressed)
{
return CommonPressedBorderOverlayPen;
}
if(RenderMouseOver)
{
return CommonHoverBorderOverlayPen;
}
return null;
}
if(this.localResource == null)
{
return null;
}
if(this.localResource.BorderOverlayPen == null)
{
this.localResource.BorderOverlayPen = CommonHoverBorderOverlayPen.Clone();
this.localResource.BorderOverlayPen.Brush.Opacity = 0.0;
}
return this.localResource.BorderOverlayPen;
}
}
#endregion
#region 내부 테두리 펜 - InnerBorderPen
/// <summary>
/// 내부 테두리 펜
/// </summary>
private Pen InnerBorderPen
{
get
{
if(!IsEnabled)
{
return CommonInnerBorderPen;
}
if(!Animates)
{
if(RenderPressed)
{
return null;
}
if(RenderDefaulted)
{
return CommonDefaultInnerBorderPen;
}
return CommonInnerBorderPen;
}
if(this.localResource == null)
{
return CommonInnerBorderPen;
}
if(this.localResource.InnerBorderPen == null)
{
this.localResource.InnerBorderPen = CommonInnerBorderPen.Clone();
}
return this.localResource.InnerBorderPen;
}
}
#endregion
#region 테두리 브러시 - BorderBrush
/// <summary>
/// 테두리 브러시
/// </summary>
public Brush BorderBrush
{
get
{
return (Brush)GetValue(BorderBrushProperty);
}
set
{
SetValue(BorderBrushProperty, value);
}
}
#endregion
#region 배경 오버레이 브러시 - BackgroundOverlayBrush
/// <summary>
/// 배경 오버레이 브러시
/// </summary>
private Brush BackgroundOverlayBrush
{
get
{
if(!IsEnabled)
{
return CommonDisabledBackgroundOverlayBrush;
}
if(!Animates)
{
if(RenderPressed)
{
return CommonPressedBackgroundOverlayBrush;
}
if(RenderMouseOver)
{
return CommonHoverBackgroundOverlayBrush;
}
return null;
}
if(this.localResource == null)
{
return null;
}
if(this.localResource.BackgroundOverlayBrush == null)
{
this.localResource.BackgroundOverlayBrush = CommonHoverBackgroundOverlayBrush.Clone();
this.localResource.BackgroundOverlayBrush.Opacity = 0.0;
}
return this.localResource.BackgroundOverlayBrush;
}
}
#endregion
#region 왼쪽 DROP SHADOW 브러시 - LeftDropShadowBrush
/// <summary>
/// 왼쪽 DROP SHADOW 브러시
/// </summary>
private LinearGradientBrush LeftDropShadowBrush
{
get
{
if(!IsEnabled)
{
return null;
}
if(!Animates)
{
if(RenderPressed)
{
return CommonPressedLeftDropShadowBrush;
}
return null;
}
if(this.localResource == null)
{
return null;
}
if(this.localResource.LeftDropShadowBrush == null)
{
this.localResource.LeftDropShadowBrush = CommonPressedLeftDropShadowBrush.Clone();
this.localResource.LeftDropShadowBrush.Opacity = 0.0;
}
return this.localResource.LeftDropShadowBrush;
}
}
#endregion
#region 위쪽 DROP SHADOW 브러시 - TopDropShadowBrush
/// <summary>
/// 위쪽 DROP SHADOW 브러시
/// </summary>
private LinearGradientBrush TopDropShadowBrush
{
get
{
if(!IsEnabled)
{
return null;
}
if(!Animates)
{
if(RenderPressed)
{
return CommonPressedTopDropShadowBrush;
}
return null;
}
if(this.localResource == null)
{
return null;
}
if(this.localResource.TopDropShadowBrush == null)
{
this.localResource.TopDropShadowBrush = CommonPressedTopDropShadowBrush.Clone();
this.localResource.TopDropShadowBrush.Opacity = 0.0;
}
return this.localResource.TopDropShadowBrush;
}
}
#endregion
#region 라운드 코너 여부 - RoundCorners
/// <summary>
/// 라운드 코너 여부
/// </summary>
public bool RoundCorners
{
get
{
return (bool)base.GetValue(RoundCornersProperty);
}
set
{
base.SetValue(RoundCornersProperty, value);
}
}
#endregion
#region 배경 - Background
/// <summary>
/// 배경
/// </summary>
public Brush Background
{
get
{
return (Brush)GetValue(BackgroundProperty);
}
set
{
SetValue(BackgroundProperty, value);
}
}
#endregion
#region 디폴트 렌더링 여부 - RenderDefaulted
/// <summary>
/// 디폴트 렌더링 여부
/// </summary>
public bool RenderDefaulted
{
get
{
return (bool)GetValue(RenderDefaultedProperty);
}
set
{
SetValue(RenderDefaultedProperty, value);
}
}
#endregion
#region 마우스 오버 렌더링 여부 - RenderMouseOver
/// <summary>
/// 마우스 오버 렌더링 여부
/// </summary>
public bool RenderMouseOver
{
get
{
return (bool)GetValue(RenderMouseOverProperty);
}
set
{
SetValue(RenderMouseOverProperty, value);
}
}
#endregion
#region PRESS 렌더링 여부 - RenderPressed
/// <summary>
/// PRESS 렌더링 여부
/// </summary>
public bool RenderPressed
{
get
{
return (bool)GetValue(RenderPressedProperty);
}
set
{
SetValue(RenderPressedProperty, value);
}
}
#endregion
#region 애니메이션 여부 - Animates
/// <summary>
/// 애니메이션 여부
/// </summary>
private bool Animates
{
get
{
return (SystemParameters.PowerLineStatus == PowerLineStatus.Online) &&
SystemParameters.ClientAreaAnimation && (RenderCapability.Tier > 0) &&
IsEnabled;
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - CustomButtonChrome()
/// <summary>
/// 생성자
/// </summary>
static CustomButtonChrome()
{
IsEnabledProperty.OverrideMetadata
(
typeof(CustomButtonChrome),
new FrameworkPropertyMetadata
(
true,
FrameworkPropertyMetadataOptions.AffectsRender
)
);
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 디폴트 렌더링 여부 속성 변경시 콜백 처리하기 - RenderDefaultedPropertyChangedCallback(d, e)
/// <summary>
/// 디폴트 렌더링 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void RenderDefaultedPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CustomButtonChrome chrome = d as CustomButtonChrome;
if(chrome.Animates)
{
if(!chrome.RenderPressed)
{
if((bool)e.NewValue)
{
if(chrome.localResource == null)
{
chrome.localResource = new LocalResource();
chrome.InvalidateVisual();
}
Duration duration = new Duration(TimeSpan.FromSeconds(0.3));
ColorAnimation colorAnimation = new ColorAnimation(Color.FromArgb(0xf9, 0, 0xcc, 0xff), duration);
GradientStopCollection collection = ((LinearGradientBrush)chrome.InnerBorderPen.Brush).GradientStops;
collection[0].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
collection[1].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
DoubleAnimationUsingKeyFrames doubleAnimation = new DoubleAnimationUsingKeyFrames();
doubleAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, TimeSpan.FromSeconds(0.5)));
doubleAnimation.KeyFrames.Add(new DiscreteDoubleKeyFrame(1.0, TimeSpan.FromSeconds(0.75)));
doubleAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, TimeSpan.FromSeconds(2.0)));
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
Timeline.SetDesiredFrameRate(doubleAnimation, 10);
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
}
else if(chrome.localResource == null)
{
chrome.InvalidateVisual();
}
else
{
Duration duration = new Duration(TimeSpan.FromSeconds(0.2));
DoubleAnimation doubleAnimation = new DoubleAnimation
{
Duration = duration
};
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
ColorAnimation colorAnimation = new ColorAnimation
{
Duration = duration
};
GradientStopCollection collection = ((LinearGradientBrush)chrome.InnerBorderPen.Brush).GradientStops;
collection[0].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
collection[1].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
}
}
}
else
{
chrome.localResource = null;
chrome.InvalidateVisual();
}
}
#endregion
#region 마우스 오버 렌더링 여부 속성 변경시 콜백 처리하기 - RenderMouseOverPropertyChangedCallback(d, e)
/// <summary>
/// 마우스 오버 렌더링 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void RenderMouseOverPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CustomButtonChrome chrome = d as CustomButtonChrome;
if(chrome.Animates)
{
if(!chrome.RenderPressed)
{
if((bool)e.NewValue)
{
if(chrome.localResource == null)
{
chrome.localResource = new LocalResource();
chrome.InvalidateVisual();
}
Duration duration = new Duration(TimeSpan.FromSeconds(0.3));
DoubleAnimation animation = new DoubleAnimation(1.0, duration);
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, animation);
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, animation);
}
else if(chrome.localResource == null)
{
chrome.InvalidateVisual();
}
else if(chrome.RenderDefaulted)
{
double opacity = chrome.BackgroundOverlayBrush.Opacity;
double secondCount = (1.0 - opacity) * 0.5;
DoubleAnimationUsingKeyFrames animation = new DoubleAnimationUsingKeyFrames();
animation.KeyFrames.Add(new LinearDoubleKeyFrame(1.0, TimeSpan.FromSeconds(secondCount)));
animation.KeyFrames.Add(new DiscreteDoubleKeyFrame(1.0, TimeSpan.FromSeconds(secondCount + 0.25)));
animation.KeyFrames.Add(new LinearDoubleKeyFrame(0.0, TimeSpan.FromSeconds(secondCount + 1.5)));
animation.KeyFrames.Add(new LinearDoubleKeyFrame(opacity, TimeSpan.FromSeconds(2.0)));
animation.RepeatBehavior = RepeatBehavior.Forever;
Timeline.SetDesiredFrameRate(animation, 10);
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, animation);
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, animation);
}
else
{
Duration duration = new Duration(TimeSpan.FromSeconds(0.2));
DoubleAnimation animation = new DoubleAnimation
{
Duration = duration
};
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, animation);
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, animation);
}
}
}
else
{
chrome.localResource = null;
chrome.InvalidateVisual();
}
}
#endregion
#region PRESS 렌더링 여부 속성 변경시 콜백 처리하기 - RenderPressedPropertyChangedCallback(d, e)
/// <summary>
/// PRESS 렌더링 여부 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void RenderPressedPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CustomButtonChrome chrome = d as CustomButtonChrome;
if(chrome.Animates)
{
if((bool)e.NewValue)
{
if(chrome.localResource == null)
{
chrome.localResource = new LocalResource();
chrome.InvalidateVisual();
}
Duration duration = new Duration(TimeSpan.FromSeconds(0.1));
DoubleAnimation doubleAnimation = new DoubleAnimation(1.0, duration);
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.LeftDropShadowBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.TopDropShadowBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
doubleAnimation = new DoubleAnimation(0.0, duration);
chrome.InnerBorderPen.Brush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
ColorAnimation colorAnimation = new ColorAnimation(Color.FromRgb(0xc2, 0xe4, 0xf6), duration);
GradientStopCollection collection = ((LinearGradientBrush)chrome.BackgroundOverlayBrush).GradientStops;
collection[0].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
collection[1].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
colorAnimation = new ColorAnimation(Color.FromRgb(0xab, 0xda, 0xf3), duration);
collection[2].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
colorAnimation = new ColorAnimation(Color.FromRgb(0x90, 0xcb, 0xeb), duration);
collection[3].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
colorAnimation = new ColorAnimation(Color.FromRgb(0x2c, 0x62, 0x8b), duration);
chrome.BorderOverlayPen.Brush.BeginAnimation(SolidColorBrush.ColorProperty, colorAnimation);
}
else if(chrome.localResource == null)
{
chrome.InvalidateVisual();
}
else
{
bool renderMouseOver = chrome.RenderMouseOver;
Duration duration = new Duration(TimeSpan.FromSeconds(0.1));
DoubleAnimation doubleAnimation = new DoubleAnimation
{
Duration = duration
};
chrome.LeftDropShadowBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.TopDropShadowBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.InnerBorderPen.Brush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
if(!renderMouseOver)
{
chrome.BorderOverlayPen.Brush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
chrome.BackgroundOverlayBrush.BeginAnimation(Brush.OpacityProperty, doubleAnimation);
}
ColorAnimation colorAnimation = new ColorAnimation
{
Duration = duration
};
chrome.BorderOverlayPen.Brush.BeginAnimation(SolidColorBrush.ColorProperty, colorAnimation);
GradientStopCollection collection = ((LinearGradientBrush)chrome.BackgroundOverlayBrush).GradientStops;
collection[0].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
collection[1].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
collection[2].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
collection[3].BeginAnimation(GradientStop.ColorProperty, colorAnimation);
}
}
else
{
chrome.localResource = null;
chrome.InvalidateVisual();
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Protected
#region 측정하기 (오버라이드) - MeasureOverride(availableSize)
/// <summary>
/// 측정하기 (오버라이드)
/// </summary>
/// <param name="availableSize">이용 가능한 크기</param>
/// <returns>측정 크기</returns>
protected override Size MeasureOverride(Size availableSize)
{
UIElement childElement = Child;
if(childElement != null)
{
Size size = new Size();
bool flag1 = availableSize.Width < 4.0;
bool flag2 = availableSize.Height < 4.0;
if(!flag1)
{
size.Width = availableSize.Width - 4.0;
}
if(!flag2)
{
size.Height = availableSize.Height - 4.0;
}
childElement.Measure(size);
Size desiredSize = childElement.DesiredSize;
if(!flag1)
{
desiredSize.Width += 4.0;
}
if(!flag2)
{
desiredSize.Height += 4.0;
}
return desiredSize;
}
return new Size
(
Math.Min(4.0, availableSize.Width ),
Math.Min(4.0, availableSize.Height)
);
}
#endregion
#region 배열하기 (오버라이드) - ArrangeOverride(finalSize)
/// <summary>
/// 배열하기 (오버라이드)
/// </summary>
/// <param name="finalSize">최종 크기</param>
/// <returns>최종 크기</returns>
protected override Size ArrangeOverride(Size finalSize)
{
Rect rectangle = new Rect
{
Width = Math.Max(0.0, (double)(finalSize.Width - 4.0)),
Height = Math.Max(0.0, (double)(finalSize.Height - 4.0))
};
rectangle.X = (finalSize.Width - rectangle.Width ) * 0.5;
rectangle.Y = (finalSize.Height - rectangle.Height) * 0.5;
UIElement childElement = Child;
if(childElement != null)
{
childElement.Arrange(rectangle);
}
return finalSize;
}
#endregion
#region 렌더링시 처리하기 - OnRender(context)
/// <summary>
/// 렌더링시 처리하기
/// </summary>
/// <param name="context">드로잉 컨텍스트</param>
protected override void OnRender(DrawingContext context)
{
Rect boundRectangle = new Rect(0.0, 0.0, ActualWidth, ActualHeight);
this.DrawBackground(context, ref boundRectangle);
this.DrawDropShadow(context, ref boundRectangle);
this.DrawBorder(context, ref boundRectangle);
this.DrawInnerBorder(context, ref boundRectangle);
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 배경 그리기 - DrawBackground(context, boundRectangle)
/// <summary>
/// 배경 그리기
/// </summary>
/// <param name="context">드로잉 컨텍스트</param>
/// <param name="boundRectangle">테두리 사각형</param>
private void DrawBackground(DrawingContext context, ref Rect boundRectangle)
{
if(IsEnabled || RoundCorners)
{
Brush backgroundBrush = Background;
if((boundRectangle.Width > 4.0) && (boundRectangle.Height > 4.0))
{
Rect rectangle = new Rect
(
boundRectangle.Left + 1.0,
boundRectangle.Top + 1.0,
boundRectangle.Width - 2.0,
boundRectangle.Height - 2.0
);
if(backgroundBrush != null)
{
context.DrawRectangle(backgroundBrush, null, rectangle);
}
backgroundBrush = this.BackgroundOverlayBrush;
if(backgroundBrush != null)
{
context.DrawRectangle(backgroundBrush, null, rectangle);
}
}
}
}
#endregion
#region 테두리 그리기 - DrawBorder(context, boundRectangle)
/// <summary>
/// 테두리 그리기
/// </summary>
/// <param name="context">드로잉 컨텍스트</param>
/// <param name="boundRectangle">테두리 사각형</param>
private void DrawBorder(DrawingContext context, ref Rect boundRectangle)
{
if((boundRectangle.Width >= 5.0) && (boundRectangle.Height >= 5.0))
{
Brush borderBrush = BorderBrush;
Pen pen1 = null;
if(borderBrush != null)
{
if(_commonBorderPen == null)
{
lock(_lockObject)
{
if(_commonBorderPen == null)
{
if(!borderBrush.IsFrozen && borderBrush.CanFreeze)
{
borderBrush = borderBrush.Clone();
borderBrush.Freeze();
}
Pen pen2 = new Pen(borderBrush, 1.0);
if(pen2.CanFreeze)
{
pen2.Freeze();
_commonBorderPen = pen2;
}
}
}
}
if((_commonBorderPen != null) && (borderBrush == _commonBorderPen.Brush))
{
pen1 = _commonBorderPen;
}
else
{
if(!borderBrush.IsFrozen && borderBrush.CanFreeze)
{
borderBrush = borderBrush.Clone();
borderBrush.Freeze();
}
pen1 = new Pen(borderBrush, 1.0);
if(pen1.CanFreeze)
{
pen1.Freeze();
}
}
}
Pen borderOverlayPen = this.BorderOverlayPen;
if((pen1 != null) || (borderOverlayPen != null))
{
if(RoundCorners)
{
Rect rectangle = new Rect
(
boundRectangle.Left + 0.5,
boundRectangle.Top + 0.5,
boundRectangle.Width - 1.0,
boundRectangle.Height - 1.0
);
if(IsEnabled && (pen1 != null))
{
context.DrawRoundedRectangle(null, pen1, rectangle, 2.75, 2.75);
}
if(borderOverlayPen != null)
{
context.DrawRoundedRectangle(null, borderOverlayPen, rectangle, 2.75, 2.75);
}
}
else
{
PathFigure figure = new PathFigure
{
StartPoint = new Point(0.5, 0.5)
};
figure.Segments.Add
(
new LineSegment
(
new Point(0.5, boundRectangle.Bottom - 0.5),
true
)
);
figure.Segments.Add
(
new LineSegment
(
new Point(boundRectangle.Right - 2.5, boundRectangle.Bottom - 0.5),
true
)
);
figure.Segments.Add
(
new ArcSegment
(
new Point(boundRectangle.Right - 0.5, boundRectangle.Bottom - 2.5),
new Size(2.0, 2.0),
0.0,
false,
SweepDirection.Counterclockwise,
true
)
);
figure.Segments.Add
(
new LineSegment
(
new Point(boundRectangle.Right - 0.5, boundRectangle.Top + 2.5),
true
)
);
figure.Segments.Add
(
new ArcSegment
(
new Point(boundRectangle.Right - 2.5, boundRectangle.Top + 0.5),
new Size(2.0, 2.0),
0.0,
false,
SweepDirection.Counterclockwise,
true
)
);
figure.IsClosed = true;
PathGeometry geometry = new PathGeometry
{
Figures = { figure }
};
if(IsEnabled && (pen1 != null))
{
context.DrawGeometry(null, pen1, geometry);
}
if(borderOverlayPen != null)
{
context.DrawGeometry(null, borderOverlayPen, geometry);
}
}
}
}
}
#endregion
#region DROP SHADOW 그리기 - DrawDropShadow(context, boundRectangle)
/// <summary>
/// DROP SHADOW 그리기
/// </summary>
/// <param name="context">드로잉 컨텍스트</param>
/// <param name="boundRectangle">테두리 사각형</param>
private void DrawDropShadow(DrawingContext context, ref Rect boundRectangle)
{
if((boundRectangle.Width > 4.0) && (boundRectangle.Height > 4.0))
{
Brush leftDropShadowBrush = this.LeftDropShadowBrush;
if(leftDropShadowBrush != null)
{
context.DrawRectangle
(
leftDropShadowBrush,
null,
new Rect(1.0, 1.0, 2.0, boundRectangle.Bottom - 2.0)
);
}
Brush topDropShadowBrush = this.TopDropShadowBrush;
if(topDropShadowBrush != null)
{
context.DrawRectangle
(
topDropShadowBrush,
null,
new Rect(1.0, 1.0, boundRectangle.Right - 2.0, 2.0)
);
}
}
}
#endregion
#region 내부 테두리 그리기 - DrawInnerBorder(context, boundRectangle)
/// <summary>
/// 내부 테두리 그리기
/// </summary>
/// <param name="context">드로잉 컨텍스트</param>
/// <param name="boundRectangle">테두리 사각형</param>
private void DrawInnerBorder(DrawingContext context, ref Rect boundRectangle)
{
if
(
DisableInnerBorder == false &&
(IsEnabled || RoundCorners) &&
(boundRectangle.Width >= 4.0) &&
(boundRectangle.Height >= 4.0)
)
{
Pen innerBorderPen = this.InnerBorderPen;
if(innerBorderPen != null)
{
context.DrawRoundedRectangle
(
null,
innerBorderPen,
new Rect
(
boundRectangle.Left + 1.5,
boundRectangle.Top + 1.5,
boundRectangle.Width - 3.0,
boundRectangle.Height - 3.0
),
1.75,
1.75
);
}
}
}
#endregion
}
}
728x90
▶ ResourceDictionary.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject">
<Style x:Key="ButtonFocusVisualStyleKey">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle
Margin="2"
StrokeThickness="1"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
StrokeDashArray="1 2"
SnapsToDevicePixels="true" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackgroundBrushKey"
StartPoint="0 0"
EndPoint="0 1">
<GradientStop Offset="0" Color="#f3f3f3" />
<GradientStop Offset="0.5" Color="#ebebeb" />
<GradientStop Offset="0.5" Color="#dddddd" />
<GradientStop Offset="1" Color="#cdcdcd" />
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorderBrushKey" Color="#ff707070" />
<Style x:Key="CustomChromeButtonStyleKey" TargetType="{x:Type Button}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorderBrushKey}" />
<Setter Property="Background" Value="{StaticResource ButtonNormalBackgroundBrushKey}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="Padding" Value="1" />
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisualStyleKey}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<local:CustomButtonChrome x:Name="buttonChrome"
BorderBrush="{TemplateBinding BorderBrush}"
RoundCorners="False"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true"
RenderDefaulted="{TemplateBinding IsDefaulted}"
RenderMouseOver="{TemplateBinding IsMouseOver}"
RenderPressed="{TemplateBinding IsPressed}">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</local:CustomButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter
TargetName="buttonChrome"
Property="RenderDefaulted"
Value="true" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter
TargetName="buttonChrome"
Property="RenderPressed"
Value="true" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#adadad" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
반응형
▶ MainApplication.xaml
<Application x:Class="TestProject.MainApplication"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
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"
Width="800"
Height="600"
Title="Decorator 엘리먼트 : 커스텀 버튼 크롬 만들기"
Background="LightGray"
FontFamily="나눔고딕코딩"
FontSize="16">
<Grid>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button
Width="200"
Height="30"
BorderBrush="Transparent"
Background="Transparent"
Content="일반 버튼" />
<Button
Style="{DynamicResource CustomChromeButtonStyleKey}"
Margin="0 10 0 0"
Width="200"
Height="30"
BorderBrush="Transparent"
Background="Transparent"
Content="커스텀 크롬 버튼" />
</StackPanel>
</Grid>
</Window>
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] Button 엘리먼트 : FocusVisualStyle 속성을 사용해 포커스 비주얼 스타일 설정하기 (0) | 2022.01.28 |
---|---|
[C#/WPF] UIElement 클래스 : GotFocus/LostFocus 이벤트를 사용해 키보드 포커스 획득/상실시 처리하기 (0) | 2022.01.28 |
[C#/WPF] WeakEventManager<TEventSource, TEventArgs> 클래스 : AddHandler 정적 메소드를 사용해 이벤트 핸들러 추가하기 (0) | 2022.01.28 |
[C#/WPF] EventManager 클래스 : RegisterClassHandler 정적 메소드를 사용해 특정 라우팅 이벤트에 대한 클래스 처리기 등록하기 (0) | 2022.01.27 |
[C#/WPF] ControlTemplate 엘리먼트 : Button 엘리먼트 정의하기 (0) | 2022.01.27 |
[C#/WPF] Decorator 엘리먼트 : 커스텀 버튼 크롬 만들기 (0) | 2022.01.27 |
[C#/WPF] ButtonChrome 엘리먼트 사용하기 (0) | 2022.01.27 |
[C#/WPF] 커스텀 포커스 범위 사용하기 (0) | 2022.01.27 |
[C#/WPF] Image 클래스 : 이미지 색상 선택기 사용하기 (0) | 2022.01.22 |
[C#/WPF] IValueConverter 인터페이스 : 색상→단색 브러시 변환자 사용하기 (0) | 2022.01.22 |
[C#/WPF] FrameworkElement 클래스 : ContextMenuOpening 이벤트를 사용해 컨텍스트 메뉴 표시 방지하기 (0) | 2022.01.19 |
댓글을 달아 주세요