인스펙터 기본값 도입 + Choice 콤보의 속성 삭제 버그 수정

[값 삭제 버그] InspectorView 의 ComboBox SelectedItem 은 TwoWay 기본이라, 저장된 값이
Choices 에 없으면 null 로 코어스한 뒤 그 null 을 소스에 되써서 속성을 삭제했다.
Label TextAlign Choices 에 Bottom* 3값이 빠져 있어, 해당 라벨을 선택하는 것만으로
발동했다(운영 활성 디자인 1,305건 census: BottomCenter 126 / BottomLeft 107 / BottomRight 16).
- ContentAlignment 9값 전체로 보정
- ChoiceRowViewModel.EnsureChoice — 목록 밖 값을 표시 전에 편입(사이트 커스텀 값 방어)

[기본값] PropertyDef.Default 추가. RowBinding.Get 한 곳에서만 주입하므로
Initialize(building=true) 경로를 타 Commit 이 발생하지 않는다 — 사용자가 건드리기 전까지
PropBag 에 아무것도 쓰이지 않아 왕복 무손실이 유지된다. 다중 선택 병합도 자동으로 옳아진다.
지정 대상(레거시 필드 초기값/WinForms DefaultValueAttribute 근거):
  TextBox.RwdRsvWrdYon=True (TextBox.vb:63, 2022-09-28 추가라 이전 서식엔 키 없음)
  DataTable.ExcuteQuery=True (MDataTable.vb:15)
  Label.TextAlign=TopLeft / TextBox.TextAlign=Left / TextBox.BorderStyle=Fixed3D
  Panel.BorderStyle=None / PictureBox.SizeMode=Normal / DateTimePicker.Format=Long
이게 없으면 기본 True 속성이 항상 '꺼짐'으로 보이고, 사용자가 껐다 켜는 순간
명시 False 가 기록돼 상용구 입력·데이터소스 자동 실행이 실제로 죽는다.

ControlRegistryTests 신설 — Default⊆Choices, Toggle 기본값 표기, 그리고 운영 실사용
열거값이 Choices 에 전부 포함되는지(census 근거) 검사.

검증: 테스트 59/59, edit-smoke 실패 0, 전수 왕복 1,271건 diff 0/예외 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-11 17:30:28 +09:00
co-authored by Claude Fable 5
parent 20e982faae
commit c445b851a1
4 changed files with 126 additions and 12 deletions
@@ -108,12 +108,27 @@ public sealed class ToggleRowViewModel : PropertyRowViewModel
/// <summary>선택지 행</summary>
public sealed class ChoiceRowViewModel : PropertyRowViewModel
{
private readonly List<string> choices;
/// <summary>선택지 목록</summary>
public string[] Choices { get; }
public IReadOnlyList<string> Choices => choices;
public ChoiceRowViewModel(string label, string[] choices) : base(label)
{
Choices = choices;
this.choices = choices.ToList();
}
/// <summary>
/// 현재 값이 선택지에 없으면 목록에 편입한다.
/// ComboBox.SelectedItem 은 TwoWay 기본이라, 바인딩 값이 ItemsSource 에 없으면 null 로 코어스한 뒤
/// 그 null 을 소스에 되써서 <b>속성이 삭제된다</b>. 선택만 해도 데이터가 손상되므로 방어가 필요하다.
/// </summary>
public void EnsureChoice(string? value)
{
if (!string.IsNullOrEmpty(value) && !choices.Contains(value, StringComparer.Ordinal))
{
choices.Add(value);
}
}
}