2026-03-30 17:09:29 +09:00

200 lines
7.2 KiB
C#

/*
* Copyright (c) 2022 LG Electronics Inc.
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
*/
using Aurora.View;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace AuroraUIComponent.UserControls.KeyValueBase
{
public abstract class UCKeyValueNumber : UCKeyValueBase
{
protected readonly CultureInfo Culture;
public static readonly DependencyProperty ValueProperty
= DependencyProperty.Register(
nameof(Value),
typeof(decimal),
typeof(UCKeyValueNumber),
// 2번째 인자: a PropertyChangedCallback delegate: called only when the property really changes
// 3번째 인자: a CoerceValueCallback delegate: called when Value is set
new FrameworkPropertyMetadata(
0m, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceValueCallback)
);
public decimal Value {
get { return (decimal)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
protected static object CoerceValueCallback(DependencyObject d, object baseValue)
{
var control = (UCKeyValueNumber)d;
var value = (decimal)baseValue;
control.CoerceValue2Bounds(ref value);
// Get the text representation of Value
var valueString = value.ToString(control.Culture);
// Count all decimal places
var decimalPlaces = control.GetDecimalPlacesCount(valueString);
if (decimalPlaces > control.DecimalPlaces) {
// Remove all overflowing decimal places
value = control.TruncateValue(valueString, decimalPlaces);
}
control.ChangeThousandSeparator(value);
return value;
}
public static readonly DependencyProperty DecimalPlacesProperty =
DependencyProperty.Register(
nameof(DecimalPlaces),
typeof(int),
typeof(UCKeyValueNumber),
new PropertyMetadata(
0, OnDecimalPlacesChanged, CoerceDecimalPlacesCallback)
);
private static object CoerceDecimalPlacesCallback(DependencyObject d, object baseValue)
{
var decimalPlaces = (int)baseValue;
// 흠, 윈폼 문서에는 [0, 99] 범위인것 같은데, 참고자료에서
// the number of decimal places cannot be a negative number and by the architecture's limitation, there can only be up to 28 decimal places.
// 왜 28일까...??
if (decimalPlaces < 0) {
decimalPlaces = 0;
} else if (decimalPlaces > 28) {
decimalPlaces = 28;
}
return decimalPlaces;
}
public int DecimalPlaces {
get { return (int)GetValue(DecimalPlacesProperty); }
set { SetValue(DecimalPlacesProperty, value); }
}
private static void OnDecimalPlacesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (UCKeyValueNumber)d;
var decimalPlaces = (int)e.NewValue;
control.Culture.NumberFormat.NumberDecimalDigits = decimalPlaces;
// tell Value to invalidate itself (run the CoerceValueCallback() method again)
control.InvalidateProperty(ValueProperty);
}
public static readonly DependencyProperty ThousandSeparatorProperty =
DependencyProperty.Register(
nameof(ThousandSeparator),
typeof(bool),
typeof(UCKeyValueNumber),
new PropertyMetadata(
false, OnIsThousandSeperatorVisibleChanged)
);
public bool ThousandSeparator {
get { return (bool)GetValue(ThousandSeparatorProperty); }
set { SetValue(ThousandSeparatorProperty, value); }
}
private static void OnIsThousandSeperatorVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (UCKeyValueNumber)d;
control.InvalidateProperty(ValueProperty);
}
public static readonly DependencyProperty UnitProperty
= DependencyProperty.Register(nameof(Unit),
typeof(string),
typeof(UCKeyValueNumber),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public string Unit {
get { return (string)GetValue(UnitProperty); }
set { SetValue(UnitProperty, value); }
}
public static readonly DependencyProperty ShowKeypadProperty
= DependencyProperty.Register(nameof(ShowKeypad), typeof(bool), typeof(UCKeyValueNumber),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public bool ShowKeypad {
get { return (bool)GetValue(ShowKeypadProperty); }
set { SetValue(ShowKeypadProperty, value); }
}
public UCKeyValueNumber()
{
//===============
// 국가마다 숫자 표기 (특히 소수점)가 다르므로, 소수점 표기 관련
Culture = (CultureInfo)CultureInfo.CurrentCulture.Clone(); // 복사
// 소수점 속성 변경
Culture.NumberFormat.NumberDecimalDigits = DecimalPlaces;
}
public int GetDecimalPlacesCount(String valueString)
{
// 첫번째 소수점을 찾은 후, counts all characters that follow
return valueString.SkipWhile(c => c.ToString(Culture) != Culture.NumberFormat.NumberDecimalSeparator).Skip(1).Count();
}
private decimal TruncateValue(string valueString, int decimalPlaces)
{
var endPoint = valueString.Length - (decimalPlaces - DecimalPlaces);
var tempValueString = valueString.Substring(0, endPoint);
return decimal.Parse(tempValueString, Culture);
}
protected abstract void ChangeThousandSeparator(decimal value);
protected void ShowNumberKeypad(TextBox text)
{
WinKBDNumber window = new WinKBDNumber();
window.IsAllowPoint = DecimalPlaces == 0 ? false : true;
window.IsAllowMinus = true;
window.Unit = Unit;
window.Value = Value.ToString();
window.Owner = Window.GetWindow(this);
window.ResultCallback = KBDWindowResult;
window.SetWindowControl(Window.GetWindow(this), text);
window.Show();
}
private void KBDWindowResult(string strValue)
{
Value = Convert.ToDecimal(strValue);
}
private void CoerceValue2Bounds(ref decimal value)
{
}
protected decimal ParseString2Decimal(string source)
{
_ = decimal.TryParse(source, out decimal value);
return value;
}
}
}