Dreamine.UI.Wpf.Equipment 1.0.1
Dreamine.UI.Wpf.Equipment 사용자 인터페이스 기능과 구성 요소를 제공합니다.
로딩중...
검색중...
일치하는것 없음
DreamineVirtualKeyboardAssist.cs
이 파일의 문서화 페이지로 가기
1using System.Windows;
2using System.Windows.Controls;
3using System.Windows.Data;
4using System.Windows.Documents;
5using System.Windows.Input;
6using System.Windows.Media;
7using System.Windows.Threading;
8using Dreamine.UI.Abstractions.VirtualKeyboard;
9
11
21{
22 #region Variable
23
41 private static DependencyObject? _placementTarget = null;
42
43 #endregion
44
45 #region Global Property
46
55 public static bool EnableDreamineVirtualKeyboard { get; set; } = true;
56
57 #endregion
58
59 #region Func/Action
60
69 public static Func<DependencyObject, VkLayout>? GetKeyboardLayoutAction { get; set; } = null;
78 public static Action<DependencyObject, VkLayout, DreamineVirtualKeyboardWindow>? SetBindingAction { get; set; } = null;
79
80 #endregion
81
82 #region Dependency Property
83
84 #region Layout Property
85
94 public static readonly DependencyProperty LayoutProperty =
95 DependencyProperty.RegisterAttached(
96 "Layout",
97 typeof(VkLayout),
99 new PropertyMetadata(default(VkLayout)));
100
133 public static VkLayout GetLayout(DependencyObject obj) =>
134 (VkLayout)obj.GetValue(LayoutProperty);
135
168 public static void SetLayout(DependencyObject obj, VkLayout value) =>
169 obj.SetValue(LayoutProperty, value);
170
171 #endregion
172
173 #region UseVirtualKeyBoard Property
174
183 public static readonly DependencyProperty UseVirtualKeyBoardProperty =
184 DependencyProperty.RegisterAttached(
185 "UseVirtualKeyBoard",
186 typeof(bool),
188 new PropertyMetadata(false, OnUseVirtualKeyBoardChanged));
189
222 public static void SetUseVirtualKeyBoard(DependencyObject obj, bool value) =>
223 obj.SetValue(UseVirtualKeyBoardProperty, value);
224
257 public static bool GetUseVirtualKeyBoard(DependencyObject obj) =>
258 (bool)obj.GetValue(UseVirtualKeyBoardProperty);
259
260 #endregion
261
262 #region Minimum Property
263
272 public static readonly DependencyProperty MinimumProperty =
273 DependencyProperty.RegisterAttached(
274 "Minimum",
275 typeof(decimal),
277 new PropertyMetadata(decimal.MinValue));
278
311 public static void SetMinimum(DependencyObject obj, decimal value) =>
312 obj.SetValue(MinimumProperty, value);
313
346 public static decimal GetMinimum(DependencyObject obj) =>
347 (decimal)obj.GetValue(MinimumProperty);
348
349 #endregion
350
351 #region Maximum Property
352
361 public static readonly DependencyProperty MaximumProperty =
362 DependencyProperty.RegisterAttached(
363 "Maximum",
364 typeof(decimal),
366 new PropertyMetadata(decimal.MaxValue));
367
400 public static void SetMaximum(DependencyObject obj, decimal value) =>
401 obj.SetValue(MaximumProperty, value);
402
435 public static decimal GetMaximum(DependencyObject obj) =>
436 (decimal)obj.GetValue(MaximumProperty);
437
438 #endregion
439
440 #region DecimalFormat Property
441
450 public static readonly DependencyProperty DecimalFormatProperty =
451 DependencyProperty.RegisterAttached(
452 "DecimalFormat",
453 typeof(string),
455 new PropertyMetadata(string.Empty));
456
489 public static void SetDecimalFormat(DependencyObject obj, string value) =>
490 obj.SetValue(DecimalFormatProperty, value);
491
524 public static string GetDecimalFormat(DependencyObject obj) =>
525 (string)obj.GetValue(DecimalFormatProperty);
526
527 #endregion
528
529 #region DreamineVkbIconAdorner Property
530
539 private static readonly DependencyProperty DreamineVkbIconAdornerProperty =
540 DependencyProperty.RegisterAttached(
541 "DreamineVkbIconAdorner", typeof(DreamineVkbIconAdorner), typeof(DreamineVirtualKeyboardAssist),
542 new PropertyMetadata(null));
575 private static void SetDreamineVkbIconAdorner(UIElement element, DreamineVkbIconAdorner value)
576 => element.SetValue(DreamineVkbIconAdornerProperty, value);
577
611
620 public static readonly DependencyProperty VkbIconVisibleProperty =
621 DependencyProperty.RegisterAttached(
622 "VkbIconVisible",
623 typeof(bool),
625 new PropertyMetadata(false, OnVkbIconVisibleChanged));
626
659 public static bool GetVkbIconVisible(DependencyObject obj)
660 => (bool)obj.GetValue(VkbIconVisibleProperty);
661
694 public static void SetVkbIconVisible(DependencyObject obj, bool value)
695 => obj.SetValue(VkbIconVisibleProperty, value);
696
729 private static void OnVkbIconVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
730 {
731 if (d is not UIElement el) return;
732
733 #pragma warning disable CS1587
744 void Apply()
745 {
746 var layer = AdornerLayer.GetAdornerLayer(el);
747 if (layer == null) return;
748
749 bool visible = (bool)e.NewValue;
750 var current = GetDreamineVkbIconAdorner(el);
751
752 if (visible)
753 {
754 if (current == null)
755 {
756 var vkbIcon = new DreamineVkbIconAdorner(el);
757 vkbIcon.SetPreviewMouseDownAction((_, _) => _virtualKeyboardWindow?.Hide());
758 layer.Add(vkbIcon);
759 SetDreamineVkbIconAdorner(el, vkbIcon);
760 }
761 }
762 else
763 {
764 if (current != null)
765 {
766 layer.Remove(current);
767 SetDreamineVkbIconAdorner(el, null!);
768 }
769 }
770 }
771 #pragma warning restore CS1587
772
773 if (d is FrameworkElement fe)
774 {
775 if (fe.IsLoaded)
776 {
777 Apply();
778 }
779 else
780 {
781 RoutedEventHandler? h = null;
782 h = (_, __) =>
783 {
784 fe.Loaded -= h;
785 Apply();
786 };
787 fe.Loaded += h;
788 }
789 }
790 else
791 {
792 // UIElement만 있는 경우: Loaded 없음 → Dispatcher로 지연
793 el.Dispatcher.InvokeAsync(Apply, DispatcherPriority.Loaded);
794 }
795 }
796
797 #endregion
798
799 #endregion
800
801 #region Action Provider Property
802
811 public static readonly DependencyProperty EnterActionProviderProperty =
812 DependencyProperty.RegisterAttached(
813 "EnterActionProvider",
814 typeof(IEnterActionProvider),
816 new PropertyMetadata(null, OnEnterActionProviderChanged));
817
850 public static IEnterActionProvider? GetEnterActionProvider(DependencyObject obj)
851 => (IEnterActionProvider?)obj.GetValue(EnterActionProviderProperty);
852
885 public static void SetEnterActionProvider(DependencyObject obj, IEnterActionProvider value)
886 => obj.SetValue(EnterActionProviderProperty, value);
887
912 private static void OnEnterActionProviderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
913 {
914 if (e.NewValue is IEnterActionProvider provider)
915 {
916 provider.PlacementTarget = d;
917 }
918 }
919 #endregion
920
921 #region
922
936
937 #endregion
938
939
940 #region Event Handlers
941
966 private static void OnUseVirtualKeyBoardChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
967 {
968 if (!(e.NewValue is bool enabled) || d is not UIElement ui) return;
969
970 if (enabled)
971 {
972 ui.PreviewMouseDown += OnControlMouseDown;
973 ui.IsEnabledChanged += OnIsEnabledChanged;
974 ui.IsHitTestVisibleChanged += OnIsEnabledChanged;
975 ui.IsVisibleChanged += OnIsVisibleChanged;
976 }
977 else
978 {
979 ui.PreviewMouseDown -= OnControlMouseDown;
980 ui.IsEnabledChanged -= OnIsEnabledChanged;
981 ui.IsHitTestVisibleChanged -= OnIsEnabledChanged;
982 ui.IsVisibleChanged -= OnIsVisibleChanged;
983 }
984 }
985
1018 private static void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
1019 {
1020 var isEnable = (bool)e.NewValue;
1021
1022 if (!isEnable && _virtualKeyboardWindow?.IsVisible == true)
1023 {
1025 }
1026 }
1027
1052 private static void OnControlMouseDown(object sender, MouseButtonEventArgs e)
1053 {
1054 if (sender is DependencyObject d)
1055 {
1057 }
1058 }
1059
1092 private static void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
1093 {
1094 var isVisible = (bool)e.NewValue;
1095 if (!isVisible && _virtualKeyboardWindow?.IsVisible == true)
1096 {
1098 }
1099 }
1100
1117 private static void ToggleVirtualKeyBoard(DependencyObject placementTarget)
1118 {
1120 {
1121 return;
1122 }
1123
1124 if ( _virtualKeyboardWindow.IsVisible && !TargetChanged(placementTarget) || IsReadOnly(placementTarget) == true)
1125 {
1127 return;
1128 }
1129
1130 ShowDreamineVirtualKeyboard(placementTarget);
1131 }
1132
1133 #endregion
1134
1135 #region Public Methods
1136
1161 public static bool TargetChanged(DependencyObject? placementTarget)
1162 {
1163 return _placementTarget != placementTarget;
1164 }
1165
1190 public static void ShowDreamineVirtualKeyboard(DependencyObject? placementTarget)
1191 {
1192 if (placementTarget is null)
1193 {
1194 return;
1195 }
1196
1197 SetVkbIconVisibility(placementTarget, true);
1198
1199 _placementTarget = placementTarget;
1200 var layout = GetKeyboardLayoutAction?.Invoke(placementTarget) ?? default;
1201
1202 _virtualKeyboardWindow.SetLayout(layout);
1203 _virtualKeyboardWindow.SetPlacementTarget(_placementTarget);
1204
1205 SetBindingAction?.Invoke(placementTarget, layout, _virtualKeyboardWindow);
1206
1208 _virtualKeyboardWindow.Activate();
1209 }
1210
1235 public static void SetVkbIconVisibility(DependencyObject? placementTarget, bool visible)
1236 {
1237 if (placementTarget is not UIElement uIElement || AdornerLayer.GetAdornerLayer(uIElement) is not { } adornerLayer)
1238 {
1239 return;
1240 }
1241
1242 if (visible)
1243 {
1244 var vkbIcon = new DreamineVkbIconAdorner(uIElement);
1245 vkbIcon.SetPreviewMouseDownAction((_, _) =>
1246 {
1247 _virtualKeyboardWindow?.Hide();
1248 });
1249 adornerLayer.Add(vkbIcon);
1250 SetDreamineVkbIconAdorner(uIElement, vkbIcon);
1251 }
1252 else
1253 {
1254 if (GetDreamineVkbIconAdorner(uIElement) is { } vkbIcon)
1255 {
1256 adornerLayer.Remove(vkbIcon);
1257 }
1258 }
1259 }
1260
1309 public static void SetBinding(DependencyObject placementTarget, VkLayout layout, DreamineVirtualKeyboardWindow virtualKeyboardWindow)
1310 {
1311 if (layout == VkLayout.Password)
1312 {
1313 if (TryBindPasswordProperty(placementTarget, out var pwdBinding))
1314 {
1315 virtualKeyboardWindow.SetBinding(pwdBinding);
1316 return;
1317 }
1318
1319 if (placementTarget is PasswordBox)
1320 {
1321 virtualKeyboardWindow.SetBinding(null!);
1322 return;
1323 }
1324
1325 virtualKeyboardWindow.SetBinding(null!);
1326 return;
1327 }
1328
1329 if (placementTarget is TextBox textBox)
1330 {
1331 var binding = new Binding("Text")
1332 {
1333 Source = textBox,
1334 Mode = BindingMode.TwoWay,
1335 UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
1336 };
1337
1338 var min = GetMinimum(placementTarget);
1339 var max = GetMaximum(placementTarget);
1340
1341 switch (layout)
1342 {
1343 case VkLayout.Numeric:
1344 virtualKeyboardWindow.SetBinding(binding, Math.Max(int.MinValue, (int)min), Math.Min(int.MaxValue, (int)max));
1345 return;
1346
1347 case VkLayout.Decimal:
1348 var decimalFormat = GetDecimalFormat(placementTarget);
1349 virtualKeyboardWindow.SetBinding(binding, min, max, decimalFormat);
1350 return;
1351
1352 default: // Text
1353 virtualKeyboardWindow.SetBinding(binding);
1354 return;
1355 }
1356 }
1357
1358 if (HasPasswordProperty(placementTarget))
1359 {
1360 virtualKeyboardWindow.SetBinding(null!);
1361 return;
1362 }
1363
1364 if (placementTarget is PasswordBox)
1365 {
1366 virtualKeyboardWindow.SetBinding(null!);
1367 return;
1368 }
1369
1370 virtualKeyboardWindow.SetBinding(null!);
1371 }
1372
1413 private static bool TryBindPasswordProperty(DependencyObject target, out Binding binding)
1414 {
1415 binding = null!;
1416
1417 var type = target.GetType();
1418
1419 var clrProp = type.GetProperty("Password");
1420 if (clrProp != null &&
1421 clrProp.CanRead &&
1422 clrProp.CanWrite &&
1423 clrProp.PropertyType == typeof(string))
1424 {
1425 binding = new Binding("Password")
1426 {
1427 Source = target,
1428 Mode = BindingMode.TwoWay,
1429 UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
1430 };
1431 return true;
1432 }
1433
1434 var dpField = type.GetField("PasswordProperty",
1435 System.Reflection.BindingFlags.Public |
1436 System.Reflection.BindingFlags.Static |
1437 System.Reflection.BindingFlags.FlattenHierarchy);
1438
1439 if (dpField?.GetValue(null) is DependencyProperty)
1440 {
1441 binding = new Binding("Password")
1442 {
1443 Source = target,
1444 Mode = BindingMode.TwoWay,
1445 UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
1446 };
1447 return true;
1448 }
1449
1450 return false;
1451 }
1452
1485 private static bool HasPasswordProperty(DependencyObject target)
1486 {
1487 var type = target.GetType();
1488 if (type.GetProperty("Password") is { } p &&
1489 p.CanRead && p.CanWrite && p.PropertyType == typeof(string))
1490 return true;
1491
1492 var dpField = type.GetField("PasswordProperty",
1493 System.Reflection.BindingFlags.Public |
1494 System.Reflection.BindingFlags.Static |
1495 System.Reflection.BindingFlags.FlattenHierarchy);
1496 return dpField?.GetValue(null) is DependencyProperty;
1497 }
1498
1515 public static void ResetDreamineVirtualKeyboard()
1516 {
1517 _virtualKeyboardWindow = null!;
1518 _placementTarget = null;
1519 }
1520
1537 public static void Shutdown()
1538 {
1539 if (_virtualKeyboardWindow is { } win)
1540 {
1541 try
1542 {
1543 // 비주얼 트리에서 DreamineVirtualKeyboard를 찾아 Dispose → SharpHook 중지
1544 DisposeVkControl(win);
1545 }
1546 catch { }
1547
1548 try { if (win.IsLoaded) win.Close(); } catch { }
1549 }
1550
1551 _virtualKeyboardWindow = null!;
1552 _placementTarget = null;
1553 }
1554
1579 private static void DisposeVkControl(System.Windows.DependencyObject root)
1580 {
1581 if (root is DreamineVirtualKeyboard vk) { vk.Dispose(); return; }
1582 int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(root);
1583 for (int i = 0; i < count; i++)
1584 DisposeVkControl(System.Windows.Media.VisualTreeHelper.GetChild(root, i));
1585 }
1586
1619 public static List<IEnterActionProvider> GetEnterActionProviders(DependencyObject d)
1620 {
1621 var list = new List<IEnterActionProvider>();
1622
1623 if (GetEnterActionProvider(d) is { } provider)
1624 {
1625 list.Add(provider);
1626 }
1627
1628 if (TreeHelper.FindParent<DreamineEnterActionGroupProvider>(d) is { } groupControl)
1629 {
1630 var subProviders = GetProviders(groupControl, []) ?? [];
1631 list.AddRange(subProviders.Where(x => x.PlacementTarget != d));
1632
1633 if (groupControl.Commit is { } commitProvider)
1634 {
1635 if (subProviders.Any())
1636 {
1637 commitProvider.PlacementTarget = subProviders.Last().PlacementTarget;
1638 }
1639
1640 list.Add(commitProvider);
1641 }
1642 }
1643
1644 return list;
1645 }
1646
1687 private static IEnumerable<IEnterActionProvider> GetProviders(DependencyObject root, DependencyObject[] excepts)
1688 {
1689 if (root == null) yield break;
1690
1691 var count = VisualTreeHelper.GetChildrenCount(root);
1692 for (int i = 0; i < count; i++)
1693 {
1694 var child = VisualTreeHelper.GetChild(root, i);
1695 if (!excepts.Contains(child) && GetEnterActionProvider(child) is { } provider)
1696 {
1697 yield return provider;
1698 }
1699
1700 foreach (var descendant in GetProviders(child, excepts))
1701 yield return descendant;
1702 }
1703 }
1704
1737 private static bool? IsReadOnly(DependencyObject placementTarget)
1738 {
1739 var prop = placementTarget.GetType().GetProperty("IsReadOnly");
1740 return (bool?)prop?.GetValue(placementTarget);
1741 }
1742
1743 #endregion
1744}
static ? Action< DependencyObject, VkLayout, DreamineVirtualKeyboardWindow > SetBindingAction
static void OnEnterActionProviderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
static void SetEnterActionProvider(DependencyObject obj, IEnterActionProvider value)
static void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
static IEnumerable< IEnterActionProvider > GetProviders(DependencyObject root, DependencyObject[] excepts)
static void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
static void SetDreamineVkbIconAdorner(UIElement element, DreamineVkbIconAdorner value)
static void SetBinding(DependencyObject placementTarget, VkLayout layout, DreamineVirtualKeyboardWindow virtualKeyboardWindow)
static void SetVkbIconVisibility(DependencyObject? placementTarget, bool visible)
static void OnUseVirtualKeyBoardChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
static void OnVkbIconVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
void SetBinding(System.Windows.Data.Binding binding, decimal min=decimal.MinValue, decimal max=decimal.MaxValue, string decimalFormat="")