MsystechandClaude Fable 5 5771a824d7 '데이터 필드 배선' → '값 가져오기' — 개발자 말을 걷어낸다
사용자가 "어떻게 사용하는지 모르겠다, 개발자가 아닌 사람도 쓸 수 있어야 한다" 고 했다.
화면을 열어 보니 낱말만 문제가 아니었다.

## 낱말

- 창 제목 '데이터 필드 배선' → <b>'값 가져오기'</b>. 전산실에서 '배선'은 랜선·전원이고,
  '배선 지우기' 는 데이터소스나 쿼리가 지워지는 것처럼 읽힌다(실제로는 이 컨트롤 속성만 빈다).
- 인스펙터 행 라벨 '데이터 필드' → '값 가져오기'. 빈 상태 '(배선 없음)' → <b>'(가져오지 않음)'</b> —
  대화상자의 지우기 버튼과 <b>글자까지 같게</b> 두어, 누르면 무엇이 되는지 미리 읽히게 했다.
- '필드' → '가져올 컬럼'. 앱은 이미 결과 창에서 '컬럼 N개', 배선 실패 문구에서
  '결과에 X 컬럼이 없습니다' 로 컬럼을 쓴다 — 낱말을 하나 더 만들지 않는다.
- '형태 Select/Rows' 를 화면에서 지웠다. .NET DataTable API 이름이라
  <b>SQL 을 아는 사람이 오히려 더 확실히 오해한다</b>(여기의 Select 는 SQL SELECT 가 아니다).
- '필터' → '행 조건'. WHERE 연상을 끊는다 — 서버로 가지 않고 이미 받아 온 표를 거르는 식이라
  NVL·TO_CHAR·|| 가 통하지 않는다. 되는 예와 안 되는 예를 나란히 적었다.

## 화면이 "무엇을 먼저 하나"의 답을 '지우기'로 주고 있었다

네 칸(형태·필터·행 번호·필드)이 같은 굵기로 나란히 있어 넷 다 채워야 하는 것처럼 보였다.
정작 검증이 요구하는 <b>필수는 둘</b>(데이터소스·컬럼)이고, 그 둘이 화면에서 가장 눈에 안 띄는
자리에 있었다. 게다가 선언 순서 때문에 첫 Tab 정지점이 '배선 지우기' 였다.

①②③ 으로 다시 세웠다 — ① 가져올 데이터소스 ② 가져올 컬럼, ③ '여러 행 중에서 고르기' 는 접는다.
접는 근거는 실측이다: 조건을 쓴 배선이 <b>0건</b>, 행 번호가 0 인 것이 98%.
기본값이 아닐 때만 접힌 머리에 칩('3번째 행' · '조건 있음')을 띄워 숨지 않게 했다.
초기 포커스도 다음 할 일로 보낸다.

## 첫 화면이 굳이 어려운 쪽으로 열리고 있었다

새 배선이 레거시 편집기와 같은 Select 형으로 시작해서, 처음 여는 사람이
<b>평생 안 쓸 개념(조건)</b>을 먼저 봤다. 새 배선을 Rows 형으로 바꿨다.

<b>동작은 같다.</b> 조건이 비면 Select("")(0) 과 Rows(0) 이 같은 행을 가리키고,
해석기 자신이 그 등가를 코드로 인정한다 — DataTableFieldPicker 는 조건이 비어 있으면
필터 경로를 아예 타지 않는다. 기존 값의 형태는 그대로 유지한다(원문을 안 건드리는 것이
왕복 무손실의 조건이다).

## 사용자를 창 밖으로 내보내던 문구

"필드 후보는 쿼리를 실행해야 알 수 있어 목록으로 제시하지 않습니다" —
이 창은 <b>모달이라 밖이 잠겨 있다</b>. 취소 → 데이터소스 찾기 → 쿼리 편집기 → 검증 실행 →
컬럼명 외우기 → 다시 열기. 레거시 편집기는 이 목록을 이미 보여 줬으므로
그 문구는 퇴행을 설명하는 문장이었다.

이제 데이터소스를 고르면 그 조회 결과의 컬럼 이름을 보여 준다. 실행은 이 창이 하지 않는다 —
호출부가 MDataTableRunner 를 함수로 감싸 넘기므로 접속·치환·캐시·실패 처리가 한 군데에 남는다.
창은 데이터소스별로 <b>한 번만</b> 묻는다(Refresh 가 키 입력마다 도는데 그때마다 조회하면 타이핑이 끊긴다).
못 읽으면 <b>왜</b> 못 읽는지 말하고 직접 입력 칸을 남긴다.

## 원문은 없애지 않고 접었다

'저장될 값'에 MDataTable1.Select("")(0).Item("") 이 큰 자리로 보이던 것을
사람 말 한 줄로 바꿨다 — "서식을 열면 — MDataTable2 조회 결과의 첫 행에서 ALGYON 값을
가져와 이 칸에 넣습니다." 원문은 접힌 '저장 형식' 줄로 내리고 복사 버튼을 붙였다.

없애지는 않았다. 인스펙터 툴팁·진단 덤프·레거시 문서가 전부 이 표기로 이야기되고,
이 속성에는 자유 텍스트 편집 경로가 없어 무엇이 저장되는지 볼 수 있는 곳이 이 줄뿐이다.

## 곁가지로 고친 조용한 결함 둘

- <b>행 번호가 조용히 0 이 됐다</b>. 전각 '1' 을 넣으면 파싱 실패가 그대로 0 이 되어
  아무 말 없이 첫 행을 가리켰다. 이제 이유를 말하고 확인을 막는다.
- <b>형태를 바꾸면 조건이 조용히 사라졌다</b>. Rows 조립은 Filter 를 아예 쓰지 않는데
  화면은 칸을 흐리게만 해서 값이 살아 있는 것처럼 보였다. 다시 열면 영구히 없어진다.
  이제 명시적 버튼이고, 버려지는 조건 원문을 확인 문구에 적어 보여 준다.
- 데이터소스가 0개일 때 '데이터소스를 선택하세요'(따를 수 없는 지시) 대신 다음 행동을 말한다.

## 판정

- 단위 시험 388 · edit-smoke 405건 전건 통과 (옛 문구를 기대한 검사 4건도 새 낱말로 갱신)
- --dialog-shots 69장 전건 통과 — 다크·라이트 양쪽을 눈으로 확인
- --modal-check · --maxrect · --scale-budget 전건 통과
- --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변
- <b>저장되는 문자열은 한 글자도 바꾸지 않았다</b> — 화면 문구와 배치만 바뀐다

## 남은 것

컬럼 목록과 값 확인은 DB 접속이 있어야 동작한다. 오프라인 설계에서는 여전히 직접 입력이고,
그때 컬럼명 대소문자 함정이 남는다. '가져올 값 확인'(현재 환자로 실제 한 칸을 뽑아 보여 주기)은
이번에 넣지 않았다 — 환자 세션까지 이 창에 들이는 일이라 별건이다.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 12:16:55 +09:00

SheetMe 서식생성기 (C#/.NET 10 WPF)

MsystechHIS 레거시 서식생성기([003]EMR\[001]SheetDesigner, VB.NET WinForms)를 대체하는 신규 WPF 서식 디자이너. 레거시 XML 포맷을 읽기·쓰기 모두 무손실 호환하여, 여기서 만든 서식을 기존 EMR 런타임(EMRLoader)이 그대로 렌더링한다.

프로젝트 구성

프로젝트 TFM 역할
src/SheetMe.Core net10.0 포맷 중립 모델(FormDocument) · LegacyXmlSerializer(읽기+쓰기, PropBag 무손실 왕복) · FormJsonSerializer(부 포맷) · ControlRegistry(팔레트/속성 스키마)
src/SheetMe.Data net10.0 Oracle 저장소 — OracleLegacyFormStore(E_ShtMst/E_SdgMst/E_SctMst, 레거시 동일 저장 의미론) · SctMstXmlWalker · EmrDataContext(M.MW.Data.EMR)
src/SheetMe.Designer net10.0-windows WPF MVVM 디자이너(M.Framework.WPF) — 캔버스/팔레트/인스펙터/페이지/레이어
tests/SheetMe.Core.Tests net10.0 MSTest 44건 — 실서식 XML 왕복 의미론 diff 0 게이트 포함

실행

dotnet build
dotnet run --project src/SheetMe.Designer
dotnet test

진단 모드 (자동 검증)

# 첫 페이지 오프스크린 렌더 → PNG (레거시 시각 대조용)
SheetMe.Designer.exe --render-smoke <서식.xml> <출력.png>
# 편집 코어 자동 검증(선택/이동/리사이즈/마퀴/복붙/Undo/왕복) → 리포트
SheetMe.Designer.exe --edit-smoke <리포트.txt>

주요 기능 (v1)

  • 캔버스 편집: 클릭/Ctrl/Shift/마퀴 선택, 드래그 이동(스냅: 그리드+정렬 가이드, Alt=자유), 8핸들 리사이즈(다중선택 비례), 키보드 넛지, z-order, 정렬 6종
  • Undo/Redo: 문서 스냅샷 메멘토 — 드래그=1스텝, 넛지 400ms 코얼레스
  • 팔레트 14종: Label·TextBox·MaskedTextBox·CheckBox·RadioButton·ComboBox·ListBox·CheckList·DateTimePicker·Panel·GroupBox·Line·PictureBox·CalcBox — 미지원 레거시 컨트롤(Spread/MSign 등)은 자리표시로 무손실 보존(이동/리사이즈 가능, 저장 시 원본 속성 전부 유지)
  • 인스펙터: 스키마 기반 속성 편집(다중선택 교집합), 폰트/색은 레거시 invariant 문자열 정합
  • 페이지/레이어: 페이지 추가/삭제/용지 크기, 레이어 목록(잠금/숨김)
  • 그룹: Ctrl+G/Ctrl+Shift+G — 그룹 멤버 클릭 시 그룹 전체가 한 단위로 선택/이동
  • 컨테이너 자식 편집: Panel/GroupBox 내부 컨트롤을 캔버스에서 직접 클릭·이동·리사이즈·삭제(상대좌표 유지)
  • 미리보기/인쇄: 편집 크롬 없는 렌더(캔버스와 동일 템플릿), FixedPage 1:1(DIP) 인쇄
  • 파일: 레거시 .xml 열기/저장(TK_ExportXML 호환) + JSON 가져오기/내보내기(부 포맷)
  • DB: E_ShtMst 검색 → 활성 디자인 열기 · DB 저장(레거시 동일: ShtCneYon='Y'→제자리 갱신 / 그 외 SdgDelYon 버저닝 + E_SctMst 재생성, 시퀀스→MAX+1 채번, 단일 트랜잭션) · 신규 서식 등록(미등록 코드 저장 시 자동 안내 — ShtTyp='D' 관행 기본값)

설정 (src/SheetMe.Designer/appsettings.json)

{
  "ConnectionStrings": { "His": "Oracle 접속 문자열" },
  "FormStore": { "SaveMode": "File" }   // DB 저장은 "Db" 로 명시 변경 시에만 활성(안전 게이트)
}

레거시 호환 규약 (정합성 기준: bzDesignSheetLoader.LoadObject 가 오류 없이 복원)

  • XML: <Sheet name="SheetDesignInfo"> 루트에 페이지당 <Object>(MDesignerHost) N개, 자식 Object 먼저 → Property 나중
  • 타입: 레거시 AQN 원문 보존, 신규는 M.EMR.UserControl.{Cls}, M.EMR.UserControl, Version=1.0.0.0, ...
  • 속성값: WinForms TypeConverter invariant 포맷("120, 88", "굴림, 11.25pt, style=Bold", "224, 224, 224")
  • LocationOnBase 는 저장 시 재계산(부모 절대좌표 누적), <Binary> 는 verbatim 보존(신규 생성 안 함 — .NET 10 BinaryFormatter 제거)
  • z-order: XML 첫 Object = 최상위(WinForms Controls 규약) ↔ WPF 캔버스는 역순 렌더

실DB 검증 결과 (2026-07-16, 테스트DB 192.168.100.222/MSYSTECHHIS)

  • 읽기: 전체 디자인 서식 1,271건 일괄 왕복(Read→Write) 의미론 diff 0 / 예외 0 — 미지원 컨트롤 보존 서식 242건 포함
  • 쓰기: S999 무변경 재저장 — 신규 버전 생성(SdgKey 52241→52380), 재저장본 diff 0, E_SctMst 36행 워커 기대치 일치, 이전 버전 SdgDelYon='Y' 이력 보존 확인
  • 호환성 세부: 텍스트 내 CR 은 NewLineHandling.Entitize( 보존), 레거시 데이터의 제어문자(0x05)는 CheckCharacters=false 관용 파싱(구식 XmlTextReader 동등)

계획 범위(P0~P5) 전체 완료 — 후속 아이디어

  • 레거시 SheetDesigner/EMR 미리보기로 S999 육안 확인 (권장)
  • v2 후보: 미지원 컨트롤 네이티브 지원(Spread 표, MSign 서명), 계산박스 수식 평가, 컨트롤 간 자식 드래그 재배치(reparent), 자 눈금(룰러), REST API 경유 모드

설계 계획서: C:\Users\Msystech\.claude\plans\c-net-wpf-flickering-gizmo.md

S
Description
No description provided
Readme
3.5 MiB
Languages
C# 99.8%
PowerShell 0.2%