020595f8d45af50c2639c644a657bb46509e49bc
1순위가 '틀린 것 고치기'였다면 여기는 <b>이미 있는 명령에 닿는 길</b>이다. 새 패널·새 화면 없이 커맨드·단축키·메뉴 층에서 끝난다. ## 선택 확장 4종 — 정렬 8종의 실효 사용률을 통째로 끌어올린다 정렬 6종·간격 4종·같은 크기가 다 있는데, 그 명령들이 전제하는 '올바른 선택'을 만들 수단이 없었다. 표 서식에서 가장 흔한 편집이 "이 행의 입력칸 8개를 조금 높이고 아래로 붙이자"인데, 그 8개를 고르는 길이 <b>Ctrl+클릭 8번뿐</b>이다. 마퀴는 교차 판정이라 행 띠를 스치는 것이 전부 딸려 온다 — 실측 787건에서 행 무리의 94.2%에 침입자가 있고 그 수가 중앙값 7개·p90 41개다. 즉 지금까지는 "드래그 → 딸려온 것 빼기"가 매번 앞에 붙었다. 주 선택 기준으로 같은 행/열/종류/크기인 <b>형제</b>를 선택에 더한다(Alt+1~4, 우클릭 메뉴 맨 위). 범위를 형제로 한 것은 정렬 명령이 쓰는 범위와 같아야 결과를 예측할 수 있어서다. 2px 오차를 허용한다. 정확히 같은 값만 묶으면 눈으로 맞춘 서식에서 <b>일부만</b> 잡히고, 8개 중 5개를 정렬해 놓고 나머지가 남은 것을 못 알아채는 것이 가장 나쁜 결과다. 격자 크기에 묶지 않았다 — 격자를 바꿨다고 선택 규칙이 달라지면 예측할 수 없다. 잠긴 것은 뺀다. 편집하려고 넓히는 선택인데 안 움직이는 것이 섞이면 정렬을 눌렀을 때 "왜 이건 그대로지"가 된다. ## 줌 단축키 — 커맨드는 처음부터 있었고 키만 없었다 8pt 글자를 확인하려 200% 로 올렸다가 전체 배치를 보려면, 캔버스에서 손을 떼고 <b>화면 맨 아래 가운데</b> 플로팅 바의 배율 버튼을 눌러 팝업을 열고 '화면 맞춤'을 골라야 했다. 확대·축소조차 Ctrl+휠뿐이라 트랙패드에서는 배율을 바꿀 키보드 수단이 아예 없었다. Ctrl+0(100%) · Ctrl+1(화면 맞춤) · Ctrl+± 를 <b>창</b> InputBindings 에 건다. 캔버스 키 처리기에 두면 안 된다 — 그쪽은 포커스가 TextBox/ComboBox 면 통째로 비켜서므로 인스펙터 값을 고친 직후에 줌 키가 죽는다. ## Ctrl+방향키로 크기 — 위치에만 있던 미세 조정의 짝 입력칸 폭을 3px 늘리려면 오른쪽 인스펙터 W 칸으로 가서 숫자를 읽고 3 을 더해 입력했다 — 캔버스와 300px 떨어진 패널 사이를 마우스로 왕복한다. 마우스 핸들은 판정 반경이 화면 6px 이라 작은 컨트롤에서 3px 를 정확히 집기 어렵고, 스냅이 붙으면 원하는 값에 못 선다. 넛지와 같은 400ms 코얼레스를 쓴다. 선은 LineGeometry 를 태워 두께 축이 늘어나지 않게 막는다 — 허용하면 디자이너에만 두꺼운 선이 보이고 EMR 은 원래 두께로 그린다. ## 잠금·숨김을 캔버스에서, 그리고 잠긴 것을 보이게 배경 괘선 40개를 잠가 두고 그 위에서 라벨만 만지고 싶을 때, 지금은 좌측 패널을 레이어 탭으로 바꾸고 트리에서 40행을 찾아 13px 자물쇠를 40번 눌러야 했다. 마퀴로 40개를 잡아 놔도 한 번에 잠글 수단이 없었다. Ctrl+L / Ctrl+Shift+H 와 우클릭 메뉴를 붙인다. <b>표시가 없던 것이 더 문제였다.</b> 숨김은 0.25 투명이라 티가 나는데 잠금은 아무 표시가 없어, 클릭도 드래그도 안 되는 이유가 화면에 없었다 — "왜 이것만 안 잡히지"만 남는다. 점선 테두리를 <b>오버레이 층</b>에 그린다. 종이 층(PageView)에 넣으면 db-render 게이트가 그것을 찍어 md5 가 깨진다 — 레거시와의 픽셀 동일성을 잠그는 게이트다. 메뉴 이름은 '선택 잠그기'로 한정했다. <b>해제는 캔버스에서 못 한다</b> — 히트 판정이 잠긴 것을 후보에서 빼므로 우클릭조차 닿지 않는다. 해제 경로는 레이어 패널이다. ## Ctrl+\ — 유일한 레이아웃 변경 좌 248 + 스플리터 10 + 우 300 = 558px 가 <b>항상</b> 점유된다. MinWidth 180/250 때문에 스플리터를 끝까지 밀어도 사라지지 않고, 보기 메뉴에도 항목이 없었다. 가로 용지를 120% 로만 올려도 캔버스에 가로 스크롤이 생기는데 '종이만 보기' 상태가 없다. 좌우를 <b>함께</b> 접는다. 개별 토글 두 개를 두지 않았다 — 목적이 하나라 키도 하나여야 손이 기억한다. MinWidth 도 함께 0 으로 내려야 실제로 사라진다(Width=0 만으로는 최소폭이 이긴다). 펼친 폭은 따로 기억한다 — 접힌 0 을 사용자가 정한 폭으로 착각하면 다음에 못 되돌린다. F4(인스펙터 진입)를 누르면 접힌 인스펙터를 먼저 편다. 레이아웃은 이것 말고 바꾸지 않았다. 좌 248 / 우 300 은 이미 측정된 값이고 (레이어 행 최소치, 인스펙터 X|Y 한 줄 최소치) 라벨 1개 선택 시 자주 쓰는 4종이 0 스크롤·0 클릭이다. 컨트롤 1,000개짜리 서식에서 트리와 속성을 동시에 봐야 하는 작업이라 떠 있는 패널로 바꾸면 겹침·재배치 비용만 생긴다. ## 판정 - 단위 시험 388 - edit-smoke 376건 전건 통과 (선택 확장 7건 · 크기 조절 2건 · 잠금 5건 추가) - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 (잠금 표시가 종이에 안 나온다는 증거) - <b>--cleartype 은 이번에 판정 불가다</b> — 게이트가 스스로 "캡처 실패, 색 픽셀 0" 이라고 보고한다. 이전 커밋에서 stash 로 되돌려 돌려도 같은 결과라 이 변경 탓이 아니다(환경 문제). 화면 캡처가 되는 상태에서 다시 확인할 것. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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
Languages
C#
99.8%
PowerShell
0.2%