2026-01-26 14:51:28 +09:00

314 lines
10 KiB
C#

using AuroraUIComponent.UserControls.Dialog;
using System;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace AuroraUIComponent.UserControls
{
public abstract class CustomControlBase<TSubClass> : Control
{
static CustomControlBase()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TSubClass),
new FrameworkPropertyMetadata(typeof(TSubClass)));
LoadResourceDictionary();
}
private static void LoadResourceDictionary()
{
Uri resourceLocater =
new Uri($"/AuroraUIComponent;component/UserControls/Input/{typeof(TSubClass).Name}Resources.xaml",
UriKind.Relative);
ResourceDictionary resourceDictionary = new ResourceDictionary { Source = resourceLocater };
Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
InitializeControlReferences();
InitializeControls();
}
protected abstract void InitializeControlReferences();
protected abstract void InitializeControls();
protected TType GetChild<TType>(string xamlElementName)
{
return (TType)Convert.ChangeType(GetTemplateChild(xamlElementName), typeof(TType));
}
}
public class UCNumericTextBox : UCKeyValueNumber<UCNumericTextBox>
{
private static readonly Thickness UnitPadding = new Thickness(2, 0, 15, 0);
private string _rangeStr;
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register(
nameof(Maximum),
typeof(decimal),
typeof(UCNumericTextBox),
new PropertyMetadata(
decimal.MaxValue, OnMaximumChanged, CoerceMaximumCallback)
);
public decimal Maximum {
get { return (decimal)GetValue(MaximumProperty); }
set {
SetValue(MaximumProperty, value);
}
}
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (UCNumericTextBox)d;
var maxValue = (decimal)e.NewValue;
// If maxValue steps over Minimum, shift it
if (maxValue < control.Minimum) {
control.Minimum = maxValue;
}
// desired 값이 경계 내에 존재하도록 강제하는 로직..
if (maxValue <= control.Value) {
control.Value = maxValue;
}
}
private static object CoerceMaximumCallback(DependencyObject d, object baseValue)
{
var control = (UCNumericTextBox)d;
var maxValue = (decimal)baseValue;
control.SetMaximum = true;
return maxValue;
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register(
nameof(Minimum),
typeof(decimal),
typeof(UCNumericTextBox),
new PropertyMetadata(
Decimal.MinValue, OnMinimumChanged, CoerceMinimumCallback)
);
public decimal Minimum {
get { return (decimal)GetValue(MinimumProperty); }
set {
SetValue(MinimumProperty, value);
}
}
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (UCNumericTextBox)d;
var minValue = (decimal)e.NewValue;
// If minValue steps over Maximum, shift it
if (minValue > control.Maximum) {
control.Maximum = minValue;
}
if (minValue >= control.Value) {
control.Value = minValue;
}
}
private static object CoerceMinimumCallback(DependencyObject d, object baseValue)
{
var control = (UCNumericTextBox)d;
var minValue = (decimal)baseValue;
control.SetMinimum = true;
return minValue;
}
// min, max 둘 중 하나 이상 설정됐을 때만 Tooltip 보임
private bool _setMinimum;
public bool SetMinimum {
get => _setMinimum; set {
_setMinimum = value;
}
}
private bool _setMaximum;
public bool SetMaximum {
get => _setMaximum; set {
_setMaximum = value;
}
}
private void UpdateTooltipRange()
{
if (SetMinimum || SetMaximum) {
StringBuilder range = new StringBuilder();
if (SetMinimum) range.Append("Min: ").Append(Minimum);
if (SetMinimum && SetMaximum) range.Append(", ");
if (SetMaximum) range.Append("Max: ").Append(Maximum);
_rangeStr = range.ToString();
}
}
private Grid _gridParent;
private TextBlock _textKey;
private TextBox _textValue;
private Button _buttonMouse;
private ToolTip _tooltipRange;
private Border _borderKey;
private TextBlock _textUnit;
private Border _valueBorder;
public UCNumericTextBox()
{
Loaded += OnControlLoaded;
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
UpdateLayout();
}
protected void OnControlLoaded(object sender, RoutedEventArgs e)
{
UpdateLayout();
}
protected override void InitializeControlReferences()
{
// class 내에서 참조할 Control들의 레퍼런스를 업데이트 (미리 변수 선언 필요)
_gridParent = GetChild<Grid>("GridParent");
_textKey = GetChild<TextBlock>("TextKey");
_textValue = GetChild<TextBox>("TextValue");
_buttonMouse = GetChild<Button>("ButtonMouse");
_tooltipRange = GetChild<ToolTip>("TooltipRange");
_borderKey = GetChild<Border>("BorderKey");
_textUnit = GetChild<TextBlock>("TextUnit");
_valueBorder = GetChild<Border>("ValueBorder");
}
protected override void InitializeControls()
{
ShowKeypad = false; // AA customization
_textValue.LostFocus += TextBoxOnLostFocus;
_textValue.IsReadOnly = IsReadOnly;
_textValue.FontSize = ValueTextSize;
_textValue.Padding = string.IsNullOrEmpty(Unit) ? UCCommonDef.UCKeyValueCommon.DEFAULT_TEXTBOX_PADDING : UnitPadding;
if (string.IsNullOrEmpty(KeyText)) {
// KeyText 가 없으므로, 해당 grid 의 width 를 0 으로 만든다
KeyTextWidth = "0px";
_borderKey.Visibility = Visibility.Collapsed;
}
if (ShowKeypad && !IsReadOnly) {
_buttonMouse.Visibility = Visibility.Visible;
_buttonMouse.Click += Button_Click;
_buttonMouse.Content = (Image)FindResource("Electronics_MouseDrawingImage");
} else {
_buttonMouse.Visibility = Visibility.Collapsed;
}
if (string.IsNullOrEmpty(Unit)) _textUnit.Visibility = Visibility.Collapsed;
_valueBorder.PreviewMouseLeftButtonDown += Text_PreviewMouseLeftButtonDown;
if (SetMinimum || SetMaximum) {
UpdateTooltipRange();
_tooltipRange.Visibility = Visibility.Visible;
_tooltipRange.Content = _rangeStr;
}
}
private void TextBoxOnLostFocus(object sender, RoutedEventArgs e)
{
decimal value = ParseString2Decimal(_textValue.Text);
CoerceValue2Bounds(ref value);
Value = value;
}
protected override void ChangeThousandSeparator(decimal value)
{
//change formatting based on this flag
if (ThousandSeparator) {
if (_textValue != null) {
_textValue.Text = value.ToString("N", Culture);
}
} else {
if (_textValue != null) {
_textValue.Text = value.ToString($"F", Culture);
}
}
}
protected override void KeyTextChanged(string newValue)
{
if (!string.IsNullOrEmpty(newValue) && _gridParent != null) {
// KeyText가 있으면, 해당 grid 의 width 를 1* 으로 만든다
_gridParent.ColumnDefinitions[0].Width = new GridLength(1, GridUnitType.Star);
}
}
protected override void KeyTextFGColorChanged(Brush brush)
{
_textKey.Foreground = brush;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
ShowWinCalculator(_textValue);
}
private void Text_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (IsReadOnly) return;
e.Handled = true;
ShowWinCalculator(_textValue);
}
protected void ShowWinCalculator(TextBox text)
{
WinCalculator window = new WinCalculator {
Foreground = Brushes.White,
DecimalPlaces = DecimalPlaces,
IsAllowMinus = true,
Unit = Unit,
Value = Value.ToString(CultureInfo.InvariantCulture),
Owner = Window.GetWindow(this),
ResultCallback = CalcWindowResult,
TextRange = _rangeStr
};
window.SetWindowControl(Window.GetWindow(this), text);
window.ShowDialog();
}
private void CalcWindowResult(string strValue)
{
decimal value = ParseString2Decimal(strValue);
CoerceValue2Bounds(ref value);
Value = value;
}
private void CoerceValue2Bounds(ref decimal value)
{
if (value < Minimum) {
value = Minimum;
} else if (value > Maximum) {
value = Maximum;
}
}
}
}