2026-06-05 13:44:39 +09:00

201 lines
7.3 KiB
C#

using AuroraUIComponent.UserControls.KeyValueBase;
using Microsoft.Xaml.Behaviors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace AuroraUIComponent.UserControls.Behavior
{
public class BlinkHighlightBehavior : Behavior<UCKeyValueBase>
{
// 외부에서 직접 바인딩할 필요 없는 내부 상태
public static readonly DependencyProperty IsActiveProperty =
DependencyProperty.Register(nameof(IsActive), typeof(bool), typeof(BlinkHighlightBehavior),
new PropertyMetadata(false, OnIsActiveChanged));
public bool IsActive {
get => (bool)GetValue(IsActiveProperty);
private set => SetValue(IsActiveProperty, value); // ← set을 private로
}
// 하이라이트 색/속도 파라미터
public static readonly DependencyProperty HighlightColorProperty =
DependencyProperty.Register(nameof(HighlightColor), typeof(Color), typeof(BlinkHighlightBehavior),
new PropertyMetadata(Colors.Orange, OnAnimParamChanged));
public Color HighlightColor {
get => (Color)GetValue(HighlightColorProperty);
set => SetValue(HighlightColorProperty, value);
}
public static readonly DependencyProperty DurationMillisProperty =
DependencyProperty.Register(nameof(DurationMillis), typeof(int), typeof(BlinkHighlightBehavior),
new PropertyMetadata(400, OnAnimParamChanged));
public int DurationMillis {
get => (int)GetValue(DurationMillisProperty);
set => SetValue(DurationMillisProperty, value);
}
// ★ 이벤트 소스 주입 (컨버터 대신)
public static readonly DependencyProperty HoverSourceProperty =
DependencyProperty.Register(nameof(HoverSource), typeof(FrameworkElement), typeof(BlinkHighlightBehavior),
new PropertyMetadata(null, OnSourceChanged));
public FrameworkElement HoverSource {
get => (FrameworkElement)GetValue(HoverSourceProperty);
set => SetValue(HoverSourceProperty, value);
}
public static readonly DependencyProperty ToolTipSourceProperty =
DependencyProperty.Register(nameof(ToolTipSource), typeof(ToolTip), typeof(BlinkHighlightBehavior),
new PropertyMetadata(null, OnSourceChanged));
public ToolTip ToolTipSource {
get => (ToolTip)GetValue(ToolTipSourceProperty);
set => SetValue(ToolTipSourceProperty, value);
}
// 내부 상태
bool _hover;
bool _open;
SolidColorBrush _keyBgBrush;
SolidColorBrush _valueBgBrush;
Color _originKeyColor;
Color _originValueColor;
ColorAnimation _anim;
protected override void OnAttached()
{
base.OnAttached();
_keyBgBrush = EnsureRuntimeBrush(AssociatedObject.KeyTextBgColor, out _originKeyColor);
_valueBgBrush = EnsureRuntimeBrush(AssociatedObject.ValueTextBgColor, out _originValueColor);
AssociatedObject.KeyTextBgColor = _keyBgBrush;
AssociatedObject.ValueTextBgColor = _valueBgBrush;
RebuildAnimation();
HookSources(); // ★ 이벤트 연결
UpdateIsActive(); // 현재 상태 반영
}
protected override void OnDetaching()
{
UnhookSources();
Stop();
base.OnDetaching();
}
static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var bh = (BlinkHighlightBehavior)d;
if (bh.AssociatedObject == null) return;
if ((bool)e.NewValue) bh.Start();
else bh.Stop();
}
static void OnAnimParamChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var bh = (BlinkHighlightBehavior)d;
if (bh.AssociatedObject == null) return;
bh.RebuildAnimation();
if (bh.IsActive) bh.Start();
}
static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var bh = (BlinkHighlightBehavior)d;
if (bh.AssociatedObject == null) return;
bh.UnhookSources();
bh.HookSources();
bh.UpdateIsActive();
}
SolidColorBrush EnsureRuntimeBrush(SolidColorBrush source, out Color original)
{
var color = (source as SolidColorBrush)?.Color ?? Colors.Transparent;
original = color;
return new SolidColorBrush(color); // 동결되지 않은 브러시
}
void RebuildAnimation()
{
_anim = new ColorAnimation {
To = HighlightColor,
Duration = TimeSpan.FromMilliseconds(Math.Max(1, DurationMillis)),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever
};
}
void Start()
{
_keyBgBrush?.BeginAnimation(SolidColorBrush.ColorProperty, _anim);
_valueBgBrush?.BeginAnimation(SolidColorBrush.ColorProperty, _anim);
}
void Stop()
{
if (_keyBgBrush != null) {
_keyBgBrush.BeginAnimation(SolidColorBrush.ColorProperty, null);
_keyBgBrush.Color = _originKeyColor;
}
if (_valueBgBrush != null) {
_valueBgBrush.BeginAnimation(SolidColorBrush.ColorProperty, null);
_valueBgBrush.Color = _originValueColor;
}
}
// ===== 이벤트 소스 처리 =====
void HookSources()
{
if (HoverSource != null) {
HoverSource.MouseEnter += HoverSource_MouseEnter;
HoverSource.MouseLeave += HoverSource_MouseLeave;
_hover = HoverSource.IsMouseOver;
}
if (ToolTipSource != null) {
ToolTipSource.Opened += ToolTipSource_Opened;
ToolTipSource.Closed += ToolTipSource_Closed;
_open = ToolTipSource.IsOpen;
}
}
void UnhookSources()
{
if (HoverSource != null) {
HoverSource.MouseEnter -= HoverSource_MouseEnter;
HoverSource.MouseLeave -= HoverSource_MouseLeave;
}
if (ToolTipSource != null) {
ToolTipSource.Opened -= ToolTipSource_Opened;
ToolTipSource.Closed -= ToolTipSource_Closed;
}
}
void HoverSource_MouseEnter(object s, System.Windows.Input.MouseEventArgs e)
{
_hover = true; UpdateIsActive();
}
void HoverSource_MouseLeave(object s, System.Windows.Input.MouseEventArgs e)
{
_hover = false; UpdateIsActive();
}
void ToolTipSource_Opened(object s, RoutedEventArgs e)
{
_open = true; UpdateIsActive();
}
void ToolTipSource_Closed(object s, RoutedEventArgs e)
{
_open = false; UpdateIsActive();
}
void UpdateIsActive()
{
IsActive = _hover || _open; // ★ OR 연산을 내부에서 처리
}
}
}