/* * 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; } } }