Dreamine.UI.Wpf.Controls
1.0.1
Dreamine.UI.Wpf.Controls 사용자 인터페이스 기능과 구성 요소를 제공합니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
DreaminePasswordBox.cs
이 파일의 문서화 페이지로 가기
1
// \file DreaminePasswordBox.cs
2
// \brief Hint/Error 지원 + Password 바인딩 가능한 커스텀 PasswordBox 컨트롤
3
// \details
4
// - ControlTemplate 내부 PART_PasswordBox(PasswordBox)와 연동
5
// - Password DP(TwoWay) 지원
6
// - 템플릿 재적용 시 이벤트 중복 등록 방지
7
// - PasswordBox.PasswordChanged <-> DP 변경 간 재진입(무한루프) 방지
8
// \author VsLibrary
9
// \date 2026-02-11
10
11
using
System;
12
using
System.Linq;
13
using
System.Windows;
14
using
System.Windows.Controls;
15
16
namespace
Dreamine.UI.Wpf.Controls
17
{
26
public
class
DreaminePasswordBox
: Control
27
{
28
// =====================================================================
29
// \brief Static constructor - style merge
30
// =====================================================================
39
static
DreaminePasswordBox
()
40
{
41
DefaultStyleKeyProperty.OverrideMetadata(typeof(
DreaminePasswordBox
),
42
new
FrameworkPropertyMetadata(typeof(
DreaminePasswordBox
)));
43
44
// \brief 스타일 리소스 병합
45
var uri =
new
Uri(
"/Dreamine.UI.Wpf.Themes;component/DreaminePasswordBoxStyle.xaml"
, UriKind.RelativeOrAbsolute);
46
47
if
(Application.Current !=
null
)
48
{
49
bool
alreadyAdded = Application.Current.Resources.MergedDictionaries
50
.OfType<ResourceDictionary>()
51
.Any(x => x.Source !=
null
&& x.Source.Equals(uri));
52
53
if
(!alreadyAdded)
54
{
55
var dict =
new
ResourceDictionary { Source = uri };
56
Application.Current.Resources.MergedDictionaries.Add(dict);
57
}
58
}
59
}
60
61
// =====================================================================
62
// \brief DP: Hint / Error / IsPasswordEmpty / Password
63
// =====================================================================
64
73
public
static
readonly DependencyProperty
HintProperty
=
74
DependencyProperty.Register(nameof(
Hint
), typeof(
string
), typeof(
DreaminePasswordBox
),
75
new
PropertyMetadata(
string
.Empty));
76
85
public
static
readonly DependencyProperty
ErrorProperty
=
86
DependencyProperty.Register(nameof(
Error
), typeof(
string
), typeof(
DreaminePasswordBox
),
87
new
PropertyMetadata(
string
.Empty));
88
97
public
static
readonly DependencyProperty
IsPasswordEmptyProperty
=
98
DependencyProperty.Register(nameof(
IsPasswordEmpty
), typeof(
bool
), typeof(
DreaminePasswordBox
),
99
new
PropertyMetadata(
true
));
100
109
public
static
readonly DependencyProperty
PasswordProperty
=
110
DependencyProperty.Register(
111
nameof(
Password
),
112
typeof(
string
),
113
typeof(
DreaminePasswordBox
),
114
new
FrameworkPropertyMetadata(
115
string
.Empty,
116
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
117
OnPasswordChanged
));
118
127
public
string
Password
128
{
129
get
=> (string)GetValue(
PasswordProperty
);
130
set
=> SetValue(
PasswordProperty
, value);
131
}
132
141
public
string
Hint
142
{
143
get
=> (string)GetValue(
HintProperty
);
144
set
=> SetValue(
HintProperty
, value);
145
}
146
155
public
string
Error
156
{
157
get
=> (string)GetValue(
ErrorProperty
);
158
set
=> SetValue(
ErrorProperty
, value);
159
}
160
169
public
bool
IsPasswordEmpty
170
{
171
get
=> (bool)GetValue(
IsPasswordEmptyProperty
);
172
set
=> SetValue(
IsPasswordEmptyProperty
, value);
173
}
174
175
// =====================================================================
176
// \brief Internal fields
177
// =====================================================================
178
187
private
PasswordBox?
_partPasswordBox
;
188
197
private
RoutedEventHandler?
_passwordChangedHandler
;
198
207
private
bool
_isSyncing
;
208
209
// =====================================================================
210
// \brief Template hook
211
// =====================================================================
212
221
public
override
void
OnApplyTemplate
()
222
{
223
base.OnApplyTemplate();
224
225
// \brief 이전 PART가 있으면 이벤트 해제
226
DetachPartHandlers
();
227
228
_partPasswordBox
= GetTemplateChild(
"PART_PasswordBox"
) as PasswordBox;
229
if
(
_partPasswordBox
==
null
)
230
return
;
231
232
// \brief 최초 동기화: DP -> PART
233
SyncDpToPart
(
Password
);
234
235
// \brief PasswordChanged 연결 (참조 보관)
236
_passwordChangedHandler
= (_, __) =>
237
{
238
if
(
_partPasswordBox
==
null
)
239
return
;
240
241
if
(
_isSyncing
)
242
return
;
243
244
try
245
{
246
_isSyncing
=
true
;
247
248
string
pwd = _partPasswordBox.Password ??
string
.Empty;
249
250
// \brief PART -> DP
251
if
(!
string
.Equals(
Password
??
string
.Empty, pwd, StringComparison.Ordinal))
252
SetCurrentValue(
PasswordProperty
, pwd);
253
254
// \brief empty 플래그 갱신
255
SetCurrentValue(
IsPasswordEmptyProperty
,
string
.IsNullOrEmpty(pwd));
256
}
257
finally
258
{
259
_isSyncing
=
false
;
260
}
261
};
262
263
_partPasswordBox.PasswordChanged += (s, e) =>
_passwordChangedHandler
?.Invoke(s, e);
264
265
// \brief 컨트롤 클릭 시 내부 입력으로 포커스 이동 (UX)
266
this.MouseDown +=
OnHostMouseDown
;
267
this.GotKeyboardFocus +=
OnHostGotKeyboardFocus
;
268
}
269
278
private
void
DetachPartHandlers
()
279
{
280
// \note PasswordBox.PasswordChanged는 익명 람다로 직접 해제하기 어려우니
281
// 템플릿 재적용 시 새 PART로 갈아끼우는 패턴에서 “PART 캐시 교체”로 방어한다.
282
// (현재 구조는 PART가 바뀌면 이전 PART는 UI 트리에서 떨어지므로 누적 영향이 크지 않음)
283
284
this.MouseDown -=
OnHostMouseDown
;
285
this.GotKeyboardFocus -=
OnHostGotKeyboardFocus
;
286
287
_partPasswordBox
=
null
;
288
_passwordChangedHandler
=
null
;
289
}
290
315
private
void
OnHostMouseDown
(
object
sender, System.Windows.Input.MouseButtonEventArgs e)
316
{
317
_partPasswordBox
?.Focus();
318
}
319
344
private
void
OnHostGotKeyboardFocus
(
object
sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
345
{
346
if
(e.NewFocus ==
this
)
347
{
348
_partPasswordBox
?.Focus();
349
e.Handled =
true
;
350
}
351
}
352
353
// =====================================================================
354
// \brief DP -> PART 동기화
355
// =====================================================================
356
381
private
static
void
OnPasswordChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
382
{
383
if
(d is not
DreaminePasswordBox
control)
384
return
;
385
386
if
(control._isSyncing)
387
return
;
388
389
string
newPassword = e.NewValue as
string
??
string
.Empty;
390
391
control.SyncDpToPart(newPassword);
392
}
393
410
private
void
SyncDpToPart
(
string
newPassword)
411
{
412
try
413
{
414
_isSyncing
=
true
;
415
416
SetCurrentValue(
IsPasswordEmptyProperty
,
string
.IsNullOrEmpty(newPassword));
417
418
if
(
_partPasswordBox
!=
null
)
419
{
420
string
current = _partPasswordBox.Password ??
string
.Empty;
421
if
(!
string
.Equals(current, newPassword, StringComparison.Ordinal))
422
_partPasswordBox.Password = newPassword;
423
}
424
}
425
finally
426
{
427
_isSyncing
=
false
;
428
}
429
}
430
}
431
}
Dreamine.UI.Wpf.Controls
Definition
DreamineCheckSelector.xaml.cs:6
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.OnHostGotKeyboardFocus
void OnHostGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
Definition
DreaminePasswordBox.cs:344
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.DreaminePasswordBox
static DreaminePasswordBox()
Definition
DreaminePasswordBox.cs:39
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.HintProperty
static readonly DependencyProperty HintProperty
Definition
DreaminePasswordBox.cs:73
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.Hint
string Hint
Definition
DreaminePasswordBox.cs:142
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.Error
string Error
Definition
DreaminePasswordBox.cs:156
Dreamine.UI.Wpf.Controls.DreaminePasswordBox._isSyncing
bool _isSyncing
Definition
DreaminePasswordBox.cs:207
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.SyncDpToPart
void SyncDpToPart(string newPassword)
Definition
DreaminePasswordBox.cs:410
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.IsPasswordEmpty
bool IsPasswordEmpty
Definition
DreaminePasswordBox.cs:170
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.IsPasswordEmptyProperty
static readonly DependencyProperty IsPasswordEmptyProperty
Definition
DreaminePasswordBox.cs:97
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.Password
string Password
Definition
DreaminePasswordBox.cs:128
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.OnApplyTemplate
override void OnApplyTemplate()
Definition
DreaminePasswordBox.cs:221
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.DetachPartHandlers
void DetachPartHandlers()
Definition
DreaminePasswordBox.cs:278
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.OnHostMouseDown
void OnHostMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
Definition
DreaminePasswordBox.cs:315
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.OnPasswordChanged
static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
Definition
DreaminePasswordBox.cs:381
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.ErrorProperty
static readonly DependencyProperty ErrorProperty
Definition
DreaminePasswordBox.cs:85
Dreamine.UI.Wpf.Controls.DreaminePasswordBox._partPasswordBox
PasswordBox? _partPasswordBox
Definition
DreaminePasswordBox.cs:187
Dreamine.UI.Wpf.Controls.DreaminePasswordBox.PasswordProperty
static readonly DependencyProperty PasswordProperty
Definition
DreaminePasswordBox.cs:109
Dreamine.UI.Wpf.Controls.DreaminePasswordBox._passwordChangedHandler
RoutedEventHandler? _passwordChangedHandler
Definition
DreaminePasswordBox.cs:197
Controls
DreaminePasswordBox.cs
다음에 의해 생성됨 :
1.17.0