11 KiB
원본 WinForms Designer 이벤트 동등성 감사
감사 기준일은 2026-07-15이다. 원본 C:\Users\MD\source\repos\MBN_STOCK_N의 커밋
309286309eaf20b58172247263f575753a860700을 읽기 전용으로 조사했다. 대상은 실제로
Designer가 구독하는 이벤트이며, 선언만 있고 구독되지 않은 메서드는 수에 넣지 않았다.
Designer 구독은 186개이고, 같은 핸들러를 여러 컨트롤에 연결한 구독을 화면별로 합치면 171개다. 이 문서의 상세 목록은 그 171개를 한 번씩 모두 분류한다.
분류 기준
IMPL: 원본의 활성 업무 동작이 C# 소유 상태/워크플로, 엄격한 WebView 브리지 intent, 또는 네이티브 playout 경로로 이관됐다.DEAD: 원본 메서드가 비어 있거나 전부 주석이거나 즉시 반환한다. 새 명령을 만들지 않는 것이 원본과 같다.VISUAL: WinForms 전용 paint/draw/focus/resize 동작이며 DOM, CSS, 브라우저 기본 동작으로 대체됐다.DRAG: 원본 drag/mouse 순서를 Web drag-and-drop과 C# 소유 순서 변경으로 이관한 묶음이다.SAFETY: 원본과 의도적으로 다르다. 기존 송출 안전 정책 때문에 자동StopAll을 넣지 않는다.
집계
| 화면 | Designer 구독 | 고유 핸들러 | IMPL | DEAD | VISUAL | DRAG | SAFETY |
|---|---|---|---|---|---|---|---|
| UC1 | 9 | 9 | 3 | 2 | 4 | 0 | 0 |
| UC2 | 4 | 4 | 3 | 1 | 0 | 0 | 0 |
| UC3 | 18 | 18 | 14 | 4 | 0 | 0 | 0 |
| UC4 | 15 | 15 | 13 | 2 | 0 | 0 | 0 |
| UC5 | 20 | 9 | 6 | 3 | 0 | 0 | 0 |
| UC6 | 13 | 13 | 12 | 1 | 0 | 0 | 0 |
| UC7 | 7 | 6 | 5 | 1 | 0 | 0 | 0 |
| AList | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
| EList | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
| FSell | 3 | 3 | 3 | 0 | 0 | 0 | 0 |
| GraphE | 15 | 15 | 14 | 1 | 0 | 0 | 0 |
| PList | 7 | 7 | 6 | 1 | 0 | 0 | 0 |
| ThemeA | 13 | 13 | 12 | 1 | 0 | 0 | 0 |
| VIList | 10 | 10 | 10 | 0 | 0 | 0 | 0 |
| MainForm | 46 | 43 | 24 | 3 | 6 | 9 | 1 |
| 합계 | 186 | 171 | 131 | 20 | 10 | 9 | 1 |
UC5는 20개 구독이 9개 핸들러를, UC7은 7개 구독이 6개 핸들러를, MainForm은 46개 구독이 43개 핸들러를 공유한다. 따라서 구독 수와 고유 핸들러 수가 다르다.
171개 핸들러 상세 증거
@숫자는 각 원본 *.Designer.cs의 이벤트 구독 줄이다.
UC1 — Control/UC1.Designer.cs
IMPL (3):treeView_DoubleClick@51,chE_CheckedChanged@73,UC1_Load@84DEAD (2):treeView_BeforeSelect@49,treeView_AfterSelect@50VISUAL (4):treeView_BeforeCollapse@46,treeView_BeforeExpand@47,treeView_DrawNode@48,treeView_MouseDown@52
UC2 — Control/UC2.Designer.cs
IMPL (3):btnswap_Click@75,listbox_DoubleClick@106,UC2_Load@126DEAD (1):listbox_SelectedIndexChanged@105
UC3 — Control/UC3.Designer.cs
IMPL (14):btnswap_Click@154,txtSearch_KeyPress@220,listBox_DoubleClick@232,btnsearch_Click@249,txtj_KeyPress@314,btnsearch2_Click@328,FpSpread2_CellDoubleClick@396,btnAdd_Click@470,btn4_Click@531,btn3_Click@545,btn2_Click@559,btn1_Click@573,listBox1_DoubleClick@720,UC3_Load@741DEAD (4):txtSearch_KeyDown@219,listBox_SelectedIndexChanged@231,FpSpread2_CellClick_1@395,FpSpread_CellClick@641
UC4 — Control/UC4.Designer.cs
IMPL (13):btn1_Click@288,txts_KeyDown@297,btn2_Click@311,btn3_Click@325,btn4_Click@339,FpSpread1_CellClick@406,FpSpread1_CellDoubleClick@407,btnpre_Click@483,btnnow_Click@497,timer1_Tick@659,btnnow_6_Click@673,btnnow_12_Click@687,UC4_Load@752DEAD (2):FpSpread1_DoubleClick@408,FpSpread2_CellClick@564
UC5 — Control/UC5.Designer.cs
IMPL (6):btn1_Click@497,btnsearch2_Click@571,txtj_KeyPress@581,btnsearch1_Click@747,txts_KeyPress@757,UC5_Load@1007DEAD (3):txtj_TextChanged@580,txts_TextChanged@756,FpSpread_CellClick@939
UC6 — Control/UC6.Designer.cs
IMPL (12):btlistadd_Click@263,txtSearch_KeyPress@284,listBox_DoubleClick@295,btnsearch_Click@312,btnsave_Click@365,btndel_Click@379,FpSpread1_CellClick@456,FpSpread2_CellClick@570,FpSpread2_KeyDown@571,btnDelete_Click@648,btnAdd_Click@662,UC6_Load@673DEAD (1):tabp6_1_Paint@331- 이벤트 구독과 별도로 원본
FpSpread2.AllowDragDrop = true가Control/UC6.Designer.cs:519에 있다. 이는DRAG경로의 전문가 추천행 재정렬로 이관한다.
UC7 — Control/UC7.Designer.cs
IMPL (5):btnsearch_Click@185,txts_KeyPress@194,btn4_Click@219,FpSpread1_CellClick@301,UC7_Load@369DEAD (1):groupBox3_Enter@161
AList — Form/AList.Designer.cs
IMPL (3):btnok_Click@64,btncn_Click@88,AList_Load@124
EList — Form/EList.Designer.cs
IMPL (3):btncn_Click@56,btnok_Click@82,EList_Load@137
FSell — Form/FSell.Designer.cs
IMPL (3):btncn_Click@109,btnok_Click@125,FSell_Load@337
GraphE — Form/GraphE.Designer.cs
IMPL (14):upSearch_Click@220,txt1_KeyPress@229,downSearch_Click@244,FpSpread1_CellClick@312,FpSpread1_CellDoubleClick@313,btndel_Click@402,btnall_Click@417,btnAdd_Click@432,txtSearch_KeyPress@453,listBox_DoubleClick@464,btnsearch_Click@481,btadd_Click@531,btnok_Click@1274,GraphE_Load@1318DEAD (1):GraphE_KeyPress@1319
PList — Form/PList.Designer.cs
IMPL (6):btnadd_Click@55,listBox_DoubleClick@79,btncn_Click@95,button3_Click@111,button1_Click@127,PList_Load@139DEAD (1):listBox_SelectedIndexChanged@78
ThemeA — Form/ThemeA.Designer.cs
IMPL (12):btncancel_Click@246,btnok_Click@260,FpSpread_KeyDown@353,btn4_Click@422,btn3_Click@436,btn2_Click@450,btn1_Click@464,btnC_Click@479,listBox_DoubleClick@521,txtSearch_KeyPress@530,btnsearch_Click@547,Theme_Load@569DEAD (1):listBox_SelectedIndexChanged@520
VIList — Form/VIList.Designer.cs
IMPL (10):txtSearch_KeyPress@188,btnok_Click@202,btn4_Click@391,btn3_Click@405,btn2_Click@419,btn1_Click@433,listBox_DoubleClick@456,btnsearch_Click@473,btncancel_Click@487,VILIST_Load@528
MainForm — MainForm.Designer.cs
IMPL (24):tabControl1_SelectedIndexChanged@1062,btnPrepare_Click@1465,PlayList_CellClick@1723,PlayList_KeyPress@1726,ckback_CheckedChanged@1818,btnback_Click@1854,btntdelete_Click@1869,btndelete_Click@1884,btnload_Click@1899,button5_Click@1914,btndown_Click@1930,btnup_Click@1946,checkBox1_CheckedChanged@1986,btnTake_Click@2018,txtSearch_KeyPress@2047,b1_Click@2108,button9_Click@2207,btnNext_Click@2410,btnTakeout_Click@2428,timer1_Tick@2433,timer3_Tick@2443,Form1_Load@2470,MainForm_KeyDown@2472,MainForm_KeyUp@2473DEAD (3):PlayList_LeaveCell@1722,GridView1_RowLeave@2081,FpSpread2_CellDoubleClick@2280VISUAL (6):panel6_Paint@1426,GridView1_CellEnter@2080,listBox_DrawItem@2189,timer2_Tick@2438,MainForm_Paint@2471,MainForm_Resize@2474DRAG (9):tab_DragOver@1063,tab_MouseDown@1064,tab_MouseMove@1065,tab_MouseUp@1066,PlayList_DragDrop@1724,PlayList_DragOver@1725,listView1_MouseDown@2349,listView1_MouseMove@2350,listView1_MouseUp@2351SAFETY (1):MainForm_FormClosing@2469
ThemeA 중복확인 동등성
원본 Form/ThemeA.cs:84-109는 입력 이름과 현재 KRX/NXT 선택을 기준으로 정확히 같은
테마명을 조회하고 이미 사용중인 테마명입니다. 또는 사용 가능한 테마명입니다.를 표시한다.
새 구현은 다음 경로를 사용한다.
Web/index.html의operator-catalog-name-check가 원본중복확인버튼이다.- Web은 이름만 담은
check-operator-catalog-theme-nameintent를 보낸다. market, code, table 이름 같은 DB 권한 정보는 보내지 못한다. LegacyBridgeProtocol이 닫힌 payload와 128자 canonical text를 검증한다.LegacyOperatorController.CheckOperatorCatalogThemeNameAsync가LegacyOperatorCatalogWorkflowController.CheckThemeNameAvailabilityAsync를 호출한다.- 워크플로는 C#이 소유한 현재 KRX/NXT 대상과 exact title을
IThemeCatalogPersistenceService.ThemeNameExistsAsync에 전달한다. 구현은 선택한 provider의SB_LIST에 parameterizedCOUNT(*)SELECT를 정확히 한 번 실행하며 mutation executor를 호출하지 않는다. 128자 테마명도 잘림 없는 exact query로 처리한다. - 조회 결과를 확정할 수 없으면
Indeterminate로 표시하며 DB 쓰기를 하지 않는다.
원본 쿼리는 edit 중인 현재 SB_CODE를 제외하지 않는다. 따라서 제목을 바꾸지 않은 기존
테마에서 중복확인을 누르면 자기 행 때문에 이미 사용중인 테마명입니다.가 표시된다. 새 구현도
고객의 원본 우선 요구에 따라 KRX/NXT 모두 이 동작을 그대로 보존한다.
검증은 LegacyThemeCatalogPersistenceServiceTests, LegacyOperatorCatalogWorkflowTests,
LegacyOperatorCatalogBridgeTests, LegacyOperatorCatalogParityWebTests에 있다.
KRX와 NXT의 같은 이름을 서로 혼동하지 않는지,
create의 중복/사용 가능, edit의 자기 행 중복, 128자 parameter binding, 결과 불명 상태,
엄격한 payload, Web 버튼 및 native dispatch를 확인한다.
의도적인 종료 안전 차이
원본 MainForm.cs:751-780은 종료 확인 뒤 KAScenePlayer.StopAll(), KAScene.Unload(),
500ms 대기, 현재 프로세스 강제 종료를 수행한다. 새 앱은 이를 그대로 이관하지 않는다.
MainWindow.CloseConfirmation.cs:88-119는 PREPARED/PROGRAM, pending callback,OutcomeUnknown을 사용자에게 명시하고 종료 과정에서 TAKE OUT을 자동 실행하지 않는다.MainWindow.Playout.cs:778-823은 on-air 장면, pending callback, quarantine,OutcomeUnknown이 없을 때만 bounded disconnect를 시도한다.- 이 차이는 기존 안전 게이트의
결과 불명 시 반복 금지와명시적 송출 명령정책을 지키기 위한 활성 안전 요구사항이다. 동등성 작업에서 완화하거나 자동StopAll로 바꾸지 않는다.
기타 감사 메모
- 원본
MainForm.Designer.cs:1399에서 PREPARE가 들어 있는panel3.Visible = false다. 새 Web UI도 PREPARE를 일반 조작 화면에서는 숨기고 네이티브/승인된 검증 경로는 유지한다. - 원본의 단일 인스턴스 기대는
LegacyParityApp/App.xaml.cs의AppInstance.FindOrRegisterForKey로 구현됐다. - 원본
timer3_Tick의 Tornado 상태 감시는IPlayoutEngine뒤의TornadoPlayoutEnginemonitor/reconnect 상태 기계로 격리돼 있다. - 이벤트 이름이 여러 화면에서 같더라도 화면별 메서드는 별개로 셌다. 예를 들어
btn1_Click,btnsearch_Click,listBox_DoubleClick은 전역 이름 하나가 아니라 각 화면의 서로 다른 바인딩이다.