수정 이력(7건, 최종 수정 2026년 09월 03일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- permalink·저자 표기·지식 맵 래퍼·깨진 내부 링크 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
- 일본어 원문의 완역으로 다시 번역했습니다. 기존 한국어판은 원문의 일부만 옮긴 축약본이라 절, 표, Mermaid 그림, 그림 설명, FAQ가 빠져 있었습니다. 일본어 원문에 맞춰 이들을 모두 복원했고, 기술적인 주장은 일본어판과 같습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.21635187)
- 부자연스러운 구어·비유를, 의미를 바꾸지 않고 기술 문서에 맞는 자연스러운 일본어로 고쳤습니다. 수정 전 버전 보기 (DOI: 10.5281/zenodo.22064711)
- WinForms/WPF/WinUI를 고르는 흐름, WinUI와 Windows App SDK의 구별, package identity 확인 절차 등을 그림으로도 따라갈 수 있도록 Mermaid 그림 24개를 추가했습니다(본문 500~750자당 1그림 규칙에 맞춘 것입니다). 본문 문장은 바꾸지 않았습니다.
- 글 맨 앞에 「이 글의 지식 맵」 절을 추가했습니다. 본문에서 다루는 개념과 그 관계를 요약·그림·상세 페이지 링크로 정리한 것입니다. 본문의 주장은 바꾸지 않았습니다.
- 외부 리뷰(1283건) 대응으로 본문을 업데이트했습니다. 개별 변경 내용은 아래 이력을 참고하면 됩니다.
- 같은 화면을 WinForms와 WPF로 쓰는 최소 대비를 추가했습니다(`DataContext` 설정을 잊으면 Binding이 동작하지 않는 점도 함께 적었습니다). WinUI 배포 형태 3모델과 package identity가 필요한 기능, 확인 절차 5단계, 용어표, 세 기술의 최근 움직임과 장기 유지보수를 읽는 법, 대상 독자를 추가하고, 구어적 비유를 평이한 표현으로 바꿨습니다.
- 최초 공개
이 글을 인용하기(DOI: 10.5281/zenodo.21635186)
이 글은 Zenodo에 보관되어 있습니다. 항상 최신 버전으로 연결되는 DOI와 지금 보고 있는 버전에 고정된 DOI를 아래에 함께 제시합니다.
Go Komura (2026). 「WinForms/WPF/WinUI 고르는 법 - 실무 판단표」. 합동회사 코무라소프트. https://doi.org/10.5281/zenodo.21635186 https://comcomponent.com/ko/blog/winforms-wpf-winui-decision-table/
- DOI(최신 버전)
- 10.5281/zenodo.21635186
- DOI(이 버전)
- 10.5281/zenodo.22217465
대상 독자: Windows 데스크톱 앱을 C# / .NET으로 만드는 개발자와, 그 기술 선정을 결정하는 입장인 분. 전제: 현행 .NET(.NET Framework가 아니라)을 쓰고, 대상 플랫폼은 Windows만으로 둡니다. 읽는 법: 결론만 보려면 1장과 3장, 기존 앱의 수명 연장 방침을 정하려면 7장, 마지막 결정 근거가 필요하면 8장부터 읽으면 됩니다.
Windows 데스크톱 앱을 C# / .NET으로 만들 때, 매번 은근히 까다로운 것이 WinForms, WPF, WinUI 중 무엇을 고를지입니다.
여기서 위험한 것은,
- 가장 새로우니까 WinUI
- 가장 익숙하니까 WinForms
- 왠지 중간 같으니까 WPF
같은, 흐릿한 고르는 방식입니다.
flowchart TB
accTitle: 흐릿한 고르는 방식의 위험
accDescr: 가장 새로우니까 WinUI, 가장 익숙하니까 WinForms, 왠지 중간 같으니까 WPF라는 흐릿한 고르는 방식은 위험하고, 실무에서는 좀 더 분명한 축으로 본다는 것을 나타내는 그림.
w1["새로우니까 WinUI"] --> w4["흐릿한 고르는 방식"]
w2["익숙하니까 WinForms"] --> w4
w3["중간 같으니까 WPF"] --> w4
w4 --> w5["실무에서는 분명한 축으로 본다"]
그림1: 「새로운·익숙한·중간 같다」가 아니라, 분명한 축으로 고른다.
실무에서 봐야 할 축은 좀 더 분명합니다.
- 신규 개발인가, 기존 자산의 연장인가
- 화면이 입력 폼 중심인가, 표현력이 필요한가
- Windows다운 모던 UI가 제품 가치 그 자체인가
- 배포·업데이트·기업 내 운영을 어떻게 할 것인가
- Windows Forms Designer 중심의 개발 스타일인가, XAML/MVVM 중심의 개발 스타일인가
이 글에서는 이를 한 장의 판단표로 정리합니다. 참고로, 이 글에서 말하는 WinUI는 주로 WinUI 3 + Windows App SDK를 가리킵니다.12
또한 이 셋은 전부 Windows 전용입니다. macOS / Linux도 시야에 들어온다면, 애초에 문제 설정이 다릅니다.341
flowchart TB
accTitle: 셋 모두 Windows 전용
accDescr: WinForms·WPF·WinUI는 모두 Windows 전용이며, macOS나 Linux도 시야에 들어온다면 애초에 문제 설정이 다르다는 것을 나타내는 그림.
t1["WinForms"] --> t4["전부 Windows 전용"]
t2["WPF"] --> t4
t3["WinUI"] --> t4
t4 -.-> t5["macOS / Linux도 시야에 있으면 문제 설정이 다르다"]
그림2: 셋 모두 Windows 전용이며, 크로스 플랫폼이라면 다른 문제 설정이 된다.
1. 먼저 결론(한마디로)
먼저 꽤 거칠게, 그러나 실무에서 쓰기 쉬운 말로 하면 이렇습니다.
- 기존 WinForms 앱이 크다면, 먼저 WinForms 유지를 기본으로 봅니다
- 기존 WPF 앱이 크다면, 먼저 WPF 유지를 기본으로 봅니다
- 신규 소~중규모 사내 도구에서 표준 컨트롤 중심·입력 화면 중심·빨리 만들고 싶다면, WinForms는 아직 상당히 강합니다35
- 신규 중~대규모 업무 앱에서 화면 수가 많고, 데이터 바인딩, 스타일, 템플릿, 커맨드, MVVM을 제대로 쓰고 싶다면, WPF가 가장 무난한 경우가 많습니다467
- 신규 Windows 전용 제품에서 모던 Windows UI, Fluent, 최신 Windows 경험이 제품 가치에 직결된다면, WinUI가 유력합니다12
- 최신 Windows API를 쓰고 싶을 뿐이라면 WinUI가 필수는 아닙니다. WPF / WinForms에서도 Windows App SDK 기능을 가져올 수 있습니다28910
- 「나중에 조금씩 WinUI를 끼워 넣으면 된다」를 전제로 고르는 것은 조금 위험합니다. 단계 이전 이야기는 생각보다 지저분합니다1011
요컨대 대개 이렇습니다.
- 기존 자산이 크다면, 그 계열을 먼저 유지한다
- 신규로 표준 폼을 빨리 만든다면 WinForms
- 신규로 길게 자랄 Windows 업무 앱이라면 WPF
- 신규로 모던 Windows UI 자체가 요건이라면 WinUI
- Windows App SDK를 쓰고 싶을 뿐이라면, 갑자기 전부 WinUI로 하지 않는다
프레임워크 선정은 UI 기술 선정이기도 하고, 배포·운영·학습 비용·이전 비용의 선정이기도 합니다. 여기를 「새로운 / 낡은」만으로 정하면, 이후 배포 설계와 유지보수 비용으로 되돌아옵니다.
flowchart TB
accTitle: 먼저 결론의 고르는 법
accDescr: 기존 자산이 크다면 그 계열을 먼저 남기고, 신규로 표준 폼을 빨리 만든다면 WinForms, 길게 자랄 Windows 업무 앱이라면 WPF, 모던 Windows UI 자체가 요건이라면 WinUI라는 고르는 법을 나타내는 그림.
r1{"기존 자산이 큰가"} -->|"예"| r2["그 계열을 먼저 유지한다"]
r1 -->|"아니요, 신규"| r3{"표준 폼 중심인가"}
r3 -->|"예"| r4["WinForms"]
r3 -->|"아니요"| r5{"모던 UI 자체가 요건인가"}
r5 -->|"아니요"| r6["WPF, 길게 자랄 업무 앱"]
r5 -->|"예"| r7["WinUI"]
r7 -.-> r8["SDK 목적뿐이라면 전면 WinUI로 하지 않는다"]
그림3: 기존 자산·화면의 성격·모던 UI 요건 순으로 보면, 결론은 대개 정해진다.
이 글의 지식 맵
WinForms·WPF·WinUI를 어떻게 고를지, 신규 개발인지 기존 자산의 연장인지, 화면이 표준 폼 중심인지 표현력 중시인지라는 축으로 정리하는 기사로, 표준 컨트롤 중심의 업무 앱에는 WinForms, 데이터 바인딩과 MVVM을 살리는 중~대규모 업무 앱에는 WPF, Fluent나 최신 Windows 체험이 제품 가치에 직결되는 신규 Windows 전용 제품에는 WinUI를 추천합니다. WinUI는 Windows App SDK의 UI 프레임워크 부분이며 기본적으로 MSIX 패키지와 package identity를 전제로 하는 한편, Windows App SDK 자체는 기존 WPF/WinForms 자산에도 기능을 추가할 수 있으므로 UI 전면 이행이 필수는 아니라고 하고, XAML Islands에 의한 단계 이행은 주전략으로 삼기 전에 작게 검증해야 한다고 주의를 당부합니다.
flowchart LR
accTitle: WinForms/WPF/WinUI 선택법 지식 맵
accDescr: WinForms·WPF·WinUI가 신규 개발과 기존 자산 중 어느 쪽에 맞는지의 판단 축, WinUI가 Windows App SDK·MSIX·package identity를 전제로 한다는 점, MVVM과 데이터 바인딩의 관계, XAML Islands에 의한 단계 이행의 주의점을 보여주는 그림
windows_forms["Windows Forms"]
wpf["WPF"]
winui["WinUI(Windows App SDK)"]
xaml["XAML"]
data_binding["데이터 바인딩"]
mvvm_pattern["MVVM(Model-View-ViewModel)"]
windows_app_sdk["Windows App SDK"]
msix["MSIX"]
package_identity["package identity"]
sparse_package["외부 위치를 가리키는 sparse package"]
unpackaged_app["패키지되지 않은 앱(unpackaged app)"]
xaml_islands["XAML Islands"]
gradual_winui_migration["기존 WPF/WinForms에 WinUI를 단계적으로 도입"]
standard_control_centric_app["표준 컨트롤 중심 업무 앱"]
multi_screen_business_app["화면이 많은 중~대규모 업무 앱"]
windows_native_modern_product["Windows 전용 신규 모던 제품 UI"]
fluent_design["Fluent Design System"]
wpf -->|"이용한다"| xaml
winui -->|"이용한다"| xaml
wpf -->|"이용한다"| data_binding
mvvm_pattern -->|"전제로 한다"| data_binding
wpf -.->|"이용한다"| mvvm_pattern
winui -.->|"이용한다"| mvvm_pattern
winui -->|"구현을 담당한다"| windows_app_sdk
wpf -.->|"이용한다"| windows_app_sdk
windows_forms -.->|"이용한다"| windows_app_sdk
winui -.->|"전제로 한다"| msix
msix -->|"전제로 한다"| package_identity
sparse_package -->|"전제로 한다"| package_identity
unpackaged_app -->|"양립하지 않는다"| package_identity
wpf -.->|"이용한다"| xaml_islands
windows_forms -.->|"이용한다"| xaml_islands
gradual_winui_migration -->|"전제로 한다"| xaml_islands
gradual_winui_migration -->|"사용은 비권장"| winui
windows_forms -->|"권장되는 대응"| standard_control_centric_app
wpf -->|"권장되는 대응"| multi_screen_business_app
winui -->|"권장되는 대응"| windows_native_modern_product
windows_forms -->|"보다 먼저 해야 한다"| winui
wpf -->|"보다 먼저 해야 한다"| winui
windows_app_sdk -->|"보다 먼저 해야 한다"| winui
winui -->|"이용한다"| fluent_design
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 24건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle
2. 이 글에서 말하는 세 가지 기술
먼저 말을 조금 맞춰 둡니다. 앞으로 계속 나오는 약어는 여기서 풀어 둡니다.
| 용어 | 풀어 쓰기 | 대략 말하면 |
|---|---|---|
| XAML | eXtensible Application Markup Language | 화면 구조를 선언적으로 쓰기 위한 XML 기반 마크업 언어. WPF와 WinUI가 씁니다 |
| Designer | Windows Forms Designer | Visual Studio에서 컨트롤을 끌어다 화면을 짜는 기능. 생성 결과는 *.Designer.cs라는 코드로 남습니다 |
| Data Binding | 데이터 바인딩 | 화면 속성과 데이터 쪽 속성을 묶어, 한쪽이 바뀌면 다른 쪽도 따라가게 하는 메커니즘 |
| MVVM | Model-View-ViewModel | 화면(View), 화면용 상태와 커맨드(ViewModel), 업무 로직과 데이터(Model)로 나누는 설계 패턴. View와 ViewModel은 Data Binding으로 잇습니다 |
| Fluent | Fluent Design System | Windows 11의 모습과 조작감을 정한 Microsoft 디자인 체계. WinUI가 전제로 삼습니다 |
| Windows App SDK | — | WinUI를 포함하는, 지금 Windows용 개발 라이브러리 묶음. UI 밖의 기능도 있고, WPF / WinForms / Win32의 기존 앱에도 더할 수 있습니다 |
| XAML Islands | — | 기존 WPF / WinForms / Win32 앱의 한 부분에만 새 XAML 컨트롤을 심기 위한 메커니즘. 자세한 내용은 5.3.3에서 다룹니다 |
| MSIX | — | Windows 앱 패키지 형식. 설치, 업데이트, 제거를 OS 쪽 메커니즘으로 다룰 수 있습니다 |
| package identity | 패키지 ID | 그 프로세스가 어느 앱 패키지 것인지 Windows가 식별할 수 있는 상태. 알림이나 연결 등 일부 Windows 기능은 이것이 없으면 쓸 수 없습니다 |
| 기술 | 대략 말하면 | 강한 축 |
|---|---|---|
| WinForms | Visual Studio Designer로 폼을 빠르게 짜기 쉬운, Windows용 전통 .NET 데스크톱 UI | 빠른 화면 작성, 표준 컨트롤, 기존 자산 활용 |
| WPF | XAML, 데이터 바인딩, 스타일, 템플릿, 커맨드로 표현력 있는 UI를 만들기 쉬운 Windows 전용 UI | 중~대규모 업무 앱, MVVM, 화면 정리의 수월함 |
| WinUI | Windows App SDK 위의 모던 Windows 네이티브 UI | Fluent, 최신 Windows 경험, 고 DPI, 모던 제품 UI |
WinForms는 Microsoft Learn에서도 컨트롤, 그래픽, 데이터 바인딩, 사용자 입력을 갖추고 Visual Studio의 끌어다 놓기 Designer로 앱을 만들기 쉬운 프레임워크로 설명됩니다.3
WPF는 해상도 독립의 벡터 기반 그리기, XAML, 데이터 바인딩, 스타일 / 템플릿, 2D / 3D, 애니메이션까지 포함하는 표현력 높은 UI 프레임워크입니다.4
WinUI는 Windows App SDK의 일부로, 고 DPI, 모던 입력, 부드러운 애니메이션, Fluent 계열 경험을 전제로 한 지금 Windows용 UI 프레임워크입니다.12 또한 data binding / MVVM 경로도 당연히 갖추고 있습니다.12
여기서 중요한 것은 Windows App SDK와 WinUI는 같지 않다는 점입니다. WinUI는 Windows App SDK의 UI 프레임워크 부분이지만, Windows App SDK 자체는 WPF / WinForms / Win32의 기존 앱에도 추가할 수 있습니다.210
그래서,
- WinUI를 쓴다
- Windows App SDK 기능을 쓴다
는 비슷해 보여도 다른 판단입니다. 여기가 섞인 채로 논의하면 「UI를 이전할지」와 「기능을 더할지」가 같은 이야기로 취급되어, 결론이 나오기 어려워집니다.
flowchart TB
accTitle: Windows App SDK와 WinUI는 같지 않다
accDescr: WinUI는 Windows App SDK의 UI 프레임워크 부분이며, Windows App SDK 자체는 WPF나 WinForms나 Win32의 기존 앱에도 추가할 수 있으므로, WinUI를 쓰는 판단과 SDK 기능을 쓰는 판단은 다르다는 것을 나타내는 그림.
sdk["Windows App SDK"] --> ui["WinUI, 그 UI 프레임워크 부분"]
sdk -.-> ex["WPF / WinForms / Win32에도 추가할 수 있다"]
ui --> d1["「WinUI를 쓴다」 판단"]
ex --> d2["「SDK 기능을 쓴다」 판단"]
d1 --> d3["비슷해 보여도 다른 판단"]
d2 --> d3
그림4: 「WinUI를 쓴다」와 「Windows App SDK 기능을 쓴다」는 다른 판단이 된다.
3. 한 장으로 보는 판단표
먼저, 실무에서 가장 쓰기 쉬운 표를 둡니다.
| 상황 | 먼저 고르는 것 | 이유 |
|---|---|---|
| 기존 WinForms 앱의 수정·수명 연장·.NET으로의 업데이트 | WinForms 유지 | 기존 화면, Designer 자산, 컨트롤 자산을 살리기 쉽다 |
| 기존 WPF 앱의 수정·수명 연장·.NET으로의 업데이트 | WPF 유지 | XAML, Binding, MVVM, 화면 구조를 그대로 살리기 쉽다 |
| 신규, 사내 도구, 설정 화면, 관리 화면, 입력 폼 중심 | WinForms | 표준 컨트롤 중심이면 착수가 빠르다 |
| 신규, 화면 수가 많다, 상태가 복잡하다, 스타일 / 템플릿 / MVVM을 쓰고 싶다 | WPF | 화면 책임 분리와 UI 정리가 쉽다 |
| 신규, Windows다운 모던 UI 자체가 요건 | WinUI | Fluent나 최신 Windows 경험에 맞추기 쉽다 |
| 기존 WPF / WinForms 그대로 Toast / Windowing / App Lifecycle 등을 쓰고 싶다 | 현행 프레임워크 + Windows App SDK | 최신 Windows 기능을 위해 UI 전면 이전까지는 불필요한 경우가 많다 |
| COM / ActiveX / 오래된 서드파티 컨트롤 의존이 짙다 | 기존 프레임워크 쪽 | UI에 앞서 의존 관계의 이전 비용이 크다 |
| 배포·업데이트·기업 내 운영 여건을 강하게 받는다 | WPF / WinForms를 우선 검토, WinUI는 배포 설계를 일찍 확인 | WinUI는 Windows App SDK / packaging 전제의 논점을 일찍 볼 필요가 있다 |
| 장래에 크로스 플랫폼화하고 싶다 | 이 셋 밖을 포함해 재검토 | 이 셋은 전부 Windows 전용 |
이 표만으로도 대체로 충분하지만, 고민하기 쉬운 지점이 두 가지 남습니다.
- 신규 Windows 업무 앱에서 WinForms와 WPF 중 어느 쪽에 붙일지
- 기존 WPF / WinForms가 있는데도 WinUI로 가야 할지
이 두 점은 이어지는 비교표를 보면서 생각하면 판단하기 쉬워집니다.
flowchart TB
accTitle: 판단표 뒤에 남는 두 가지 고민
accDescr: 한 장의 판단표만으로는 신규 Windows 업무 앱에서 WinForms와 WPF 중 어느 쪽에 붙일지, 기존 WPF나 WinForms가 있는데도 WinUI로 가야 할지라는 두 점이 남고, 이어지는 비교표로 생각한다는 것을 나타내는 그림.
hyo["한 장의 판단표"] --> n1["신규 업무 앱은 WinForms인가 WPF인가"]
hyo --> n2["기존이 있는데도 WinUI로 갈 것인가"]
n1 --> hik["관점별 비교표로 생각한다"]
n2 --> hik
그림5: 판단표에서 남는 두 가지 고민은 관점별 비교표로 생각한다.
4. 관점별 비교표
여기는 공식 우열표가 아니라, 꽤 실무 쪽 비교입니다.
| 관점 | WinForms | WPF | WinUI |
|---|---|---|---|
| 작은 입력 폼을 빠르게 만든다 | ◎ | ○ | ○ |
| 표준 컨트롤 중심의 사내 도구 | ◎ | ○ | △~○ |
| 데이터 바인딩 / MVVM과의 궁합 | △ | ◎ | ○~◎ |
| 스타일 / 템플릿 / 화면 표현력 | △ | ◎ | ◎ |
| 기존 Windows 데스크톱 자산과의 적합성 | ◎ | ○ | △ |
| 모던한 Windows다움 | △ | ○ | ◎ |
| 기존 화면의 수명 연장·단계 수정 | ◎ | ◎ | △ |
| Windows App SDK 기능 추가만 하고 싶다 | ○ | ○ | ◎ |
| 배포 / 업데이트 / 운영 설계의 가벼움 | ○ | ○ | △~○ |
| 「새롭고 길게 자랄 Windows 전용 제품 UI」를 만든다 | △ | ○ | ◎ |
보는 요령은 무엇이 최강인가가 아니라 무엇이 마찰이 가장 적은가입니다.
예를 들어,
- 사내 설정 도구
- 장치 설정 화면
- 목록, 명세, 검색, 설정, 버튼
- 겉모습보다 운영의 안정과 수정 속도가 중요하다
라면, WinForms는 아직 충분히 합리적입니다.
반대로,
- 화면 수가 많다
- 표시 상태 전환이 많다
- View와 로직을 나누고 싶다
- 데이터 변화를 UI에 자연스럽게 잇고 싶다
- 스타일 / 템플릿으로 UI를 통제하고 싶다
그리고,
- Windows 11다운 모습을 전제로 하고 싶다
- Fluent를 제대로 살리고 싶다
- 고 DPI, 터치, 모던 윈도우 API를 전제로 하고 싶다
- 신규로, Windows 전용 제품으로서 UI 인상도 중요하다
flowchart TB
accTitle: 마찰의 적음으로 고른다
accDescr: 무엇이 최강인가가 아니라 무엇이 마찰이 가장 적은가를 보는 요령으로서, 표준 컨트롤 중심의 사내 도구는 WinForms, 화면 수가 많고 MVVM을 쓰고 싶은 프로젝트는 WPF, Fluent나 최신 Windows 경험 전제의 프로젝트는 WinUI가 자연스럽다는 것을 나타내는 그림.
k0["무엇이 마찰이 가장 적은가"] --> k1["사내 도구·표준 컨트롤 중심"]
k0 --> k2["화면 수가 많고 MVVM을 쓰고 싶다"]
k0 --> k3["Fluent·최신 Windows 경험이 전제"]
k1 --> k4["WinForms"]
k2 --> k5["WPF"]
k3 --> k6["WinUI"]
그림6: 「무엇이 최강인가」가 아니라 「무엇이 마찰이 가장 적은가」로 셋을 나눠 쓴다.
4.1 「표현력 차이」를 최소 코드로 본다
위 표의 「데이터 바인딩 / MVVM과의 궁합」은 말만으로는 잡히기 어려운 부분입니다. 같은 화면을 WinForms와 WPF로 쓰면 무엇이 바뀌는지를 최소 코드로 나란히 둡니다.
만드는 것은 「텍스트 상자 하나와 저장 버튼 하나」뿐인 화면입니다.
WinForms: Designer가 *.Designer.cs를 생성하고, 이벤트 핸들러 안에서 화면에서 값을 꺼냅니다.
// MainForm.Designer.cs — Designer가 생성하는 쪽. 손으로 쓰는 자리가 아닙니다
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Button saveButton;
private void InitializeComponent()
{
this.nameTextBox = new System.Windows.Forms.TextBox();
this.saveButton = new System.Windows.Forms.Button();
this.SuspendLayout();
this.nameTextBox.Location = new System.Drawing.Point(12, 12);
this.nameTextBox.Size = new System.Drawing.Size(200, 23);
this.saveButton.Location = new System.Drawing.Point(218, 12);
this.saveButton.Size = new System.Drawing.Size(75, 23);
this.saveButton.Text = "저장";
this.saveButton.Click += new System.EventHandler(this.SaveButton_Click);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.saveButton);
this.ResumeLayout(false);
}
// MainForm.cs — 이쪽이 손으로 쓰는 쪽
public partial class MainForm : Form
{
private readonly EditorService _service;
public MainForm(EditorService service)
{
_service = service;
InitializeComponent();
}
private void SaveButton_Click(object sender, EventArgs e)
{
// 화면 컨트롤에서 값을 직접 꺼내 넘긴다
_service.Save(this.nameTextBox.Text);
}
}
WPF: XAML에는 「무엇과 이어질지」만 쓰고, 값의 넣고 빼기는 Binding이 합니다.
<!-- MainWindow.xaml -->
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="편집" Width="360" Height="120">
<StackPanel Orientation="Horizontal" Margin="12">
<TextBox Width="200"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
<Button Width="75" Margin="6,0,0,0" Content="저장"
Command="{Binding SaveCommand}" />
</StackPanel>
</Window>
// MainWindow.xaml.cs — DataContext를 넘기는 것을 잊으면 Binding은 아무 일도 일어나지 않습니다
public partial class MainWindow : Window
{
public MainWindow(EditorService service)
{
InitializeComponent();
this.DataContext = new MainViewModel(service);
}
}
// MainViewModel.cs — 화면을 모르는 쪽. 단위 테스트도 여기서 쓸 수 있습니다
public sealed class MainViewModel : INotifyPropertyChanged
{
private readonly EditorService _service;
private string _name = string.Empty;
public MainViewModel(EditorService service)
{
_service = service;
SaveCommand = new RelayCommand(() => _service.Save(Name));
}
public string Name
{
get => _name;
set
{
if (_name == value) return;
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public ICommand SaveCommand { get; }
public event PropertyChangedEventHandler PropertyChanged;
}
RelayCommand는 ICommand를 구현한 작은 클래스이며, CommunityToolkit.Mvvm 같은 라이브러리에도 들어 있고, 20줄 정도로 직접 만들 수도 있습니다.
줄 수만 보면 WPF 쪽이 많습니다. 차이가 나는 것은 여기서부터입니다.
| WinForms | WPF | |
|---|---|---|
| 화면에서 값을 꺼내는 곳 | 이벤트 핸들러 안에서 nameTextBox.Text를 직접 읽는다 |
Name 속성. View를 건드리지 않는다 |
| 저장 처리를 단위 테스트한다 | Form을 세워야 한다 | MainViewModel을 직접 new해서 호출할 수 있다 |
| 같은 입력란을 다른 화면에도 낸다 | 컨트롤을 다시 놓고, 핸들러도 다시 쓴다 | 같은 ViewModel에 다른 View를 맞춘다 |
| 모습을 전 화면에서 통일한다 | 각 컨트롤 속성을 개별적으로 맞춘다 | Style / Template을 한곳에 둔다 |
화면이 3장이면 WinForms가 빠르고, 30장이 되면 WPF가 가볍다는 것이 이 차이의 실무적 의미입니다.
flowchart TB
accTitle: 값 흐름의 차이
accDescr: WinForms에서는 이벤트 핸들러가 화면 컨트롤에서 값을 직접 꺼내 서비스로 넘기는 반면, WPF에서는 Binding이 View와 ViewModel을 잇고, 화면을 모르는 ViewModel이 서비스를 호출한다는 값 흐름의 차이를 나타내는 그림.
subgraph wf["WinForms"]
a1["View의 컨트롤"] --> a2["이벤트 핸들러"]
a2 --> a3["서비스를 직접 호출한다"]
end
subgraph wp["WPF"]
b1["View의 XAML"] --> b2["Binding"]
b2 --> b3["ViewModel"]
b3 --> b4["서비스를 호출한다"]
end
a3 -.-> c1["화면 3장이면 빠르다"]
b4 -.-> c2["화면 30장이어도 가볍다"]
그림7: WinForms는 화면에서 값을 직접 꺼내고, WPF는 Binding을 통해 ViewModel이 맡는다.
5. 각각, 어떤 일에 맞는지
5.1 WinForms
WinForms는 괜히 가볍게 보이기 쉽지만, 표준 컨트롤 중심의 업무 화면을 빨리 만든다는 한 점에서는 지금도 만만하지 않습니다.35
특히 맞는 것은, 예를 들어 이런 일입니다.
- 사내용 설정 도구
- 장치·계측기·감시 도구의 설정 화면
- 관리 화면, 검색 화면, 목록 + 명세
- 기존 WinForms 자산이 큰 일
- Windows Forms Designer 중심 개발 스타일이 강한 팀
WinForms의 강점은, 어려운 설계 철학을 끌어들이지 않아도 어느 정도 빨리 완성물에 가까운 화면이 나온다는 점입니다. 폼, 버튼, 레이블, 텍스트 상자, 데이터 그리드. 이 영역이 핵심이라면 상당히 싸울 수 있습니다.
다만 약한 곳도 분명합니다.
- 화면 전체의 모습을 크게 통일하고 싶다
- 스타일과 템플릿으로 UI를 제어하고 싶다
- 복잡한 상태 변화를 데이터 바인딩 주체로 다루고 싶다
- 화면 로직을 깔끔히 분리하고 싶다
이 부근은 WPF나 WinUI 쪽이 자연스럽습니다.
WinForms로 큰 앱을 만들면, 방심하면 이벤트 핸들러 정글이 되기 쉽습니다. 그래서 WinForms를 고른다면,
- 화면 책임을 작게 유지한다
- UserControl 단위로 나눈다
- Presenter / ViewModel에 해당하는 경계를 의식한다
- 화면 이벤트에 업무 로직을 덕지덕지 쓰지 않는다
정도는 처음부터 정해 두는 편이 나중에 덜 고생합니다.
flowchart TB
accTitle: 이벤트 핸들러 정글을 피한다
accDescr: WinForms로 큰 앱을 만들면 이벤트 핸들러 정글이 되기 쉬우므로, 화면 책임을 작게 유지하고, UserControl 단위로 나누며, Presenter나 ViewModel에 해당하는 경계를 의식하는 것을 처음부터 정해 둔다는 것을 나타내는 그림.
mo["큰 WinForms 앱"] --> ha["이벤트 핸들러 정글이 되기 쉽다"]
ha --> p1["화면 책임을 작게 유지한다"]
ha --> p2["UserControl 단위로 나눈다"]
ha --> p3["경계를 의식한다"]
p3 -.-> p4["화면 이벤트에 업무 로직을 쓰지 않는다"]
그림8: 큰 WinForms 앱은, 책임 분할 방식을 처음부터 정해 두면 나중에 덜 고생합니다.
그리고 실무에서 꽤 중요한 것은, Windows App SDK를 쓰고 싶다고 해서 WinForms를 버릴 필요는 없다는 점입니다. 공식에도 기존 WinForms 앱에 Windows App SDK 기능을 더하는 경로가 있습니다.910
즉 WinForms는
- UI는 그대로
- 필요한 Windows 기능만 현대화
라는 고르는 법이 가능합니다. 여기는 현실적인 타협점입니다.
flowchart TB
accTitle: WinForms 그대로 현대화하는 길
accDescr: Windows App SDK를 쓰고 싶다고 해서 WinForms를 버릴 필요는 없고, UI는 그대로 두고 필요한 Windows 기능만 현대화하는 현실적인 타협점이 있다는 것을 나타내는 그림.
g1["Windows App SDK를 쓰고 싶다"] --> g2["WinForms를 버릴 필요는 없다"]
g2 --> g3["UI는 그대로"]
g2 --> g4["필요한 기능만 현대화"]
g3 --> g5["현실적인 타협점"]
g4 --> g5
그림9: WinForms는 UI를 유지한 채, 필요한 Windows 기능만 현대화할 수 있다.
5.2 WPF
WPF는 Windows 데스크톱의 .NET UI로 보면, 균형이 가장 좋은 핵심입니다.4
강점은 분명합니다.
- XAML로 화면을 선언적으로 쓸 수 있다
- Data Binding이 강하다
- Style / Template을 쓸 수 있다
- Command를 쓸 수 있다
- View와 로직을 나누기 쉽다
- 중~대규모 화면을 정리하기 쉽다
WPF 공식 문서에서도 데이터 바인딩은 WPF의 중심 기능으로 설명되고, 커맨드도 입력과 실행 로직을 나누는 메커니즘으로 정리되어 있습니다.67
그래서 예를 들어 이런 일에 맞습니다.
- 화면 수가 많은 업무 앱
- 목록, 상세, 편집, 검색, 상태 표시가 많다
- 여러 사람이 길게 유지보수하는 Windows 앱
- View와 로직을 나누고 싶다
- 장래 수정에서 모습과 동작의 책임을 나눠 두고 싶다
- WinForms면 화면이 금방 무거워질 것 같다
신규 Windows 전용 업무 앱에서 망설일 때, WPF는 지금도 안전한 제1 후보입니다. 여기를 「WPF는 낡으니까 안 된다」고 잘라 내는 것은 조금 거칠습니다.
flowchart TB
accTitle: 신규 업무 앱의 안전한 제1 후보
accDescr: 화면 수가 많고, View와 로직을 나누고 싶고, 여러 사람이 길게 유지보수하는 중~대규모 Windows 업무 앱에서는 WPF가 지금도 안전한 제1 후보라는 것을 나타내는 그림.
j1["화면 수가 많은 업무 앱"] --> j4["WPF가 안전한 제1 후보"]
j2["View와 로직을 나누고 싶다"] --> j4
j3["여러 사람이 길게 유지보수한다"] --> j4
j4 -.-> j5["「낡으니까 안 된다」고 잘라 내는 것은 거칠다"]
그림10: 화면 수가 많고 길게 유지보수하는 신규 업무 앱에서는, WPF가 안전한 제1 후보가 된다.
오히려,
- 기존 WPF 자산이 있다
- 기존 XAML / MVVM 지식이 있다
- 그렇게까지 Fluent 최우선은 아니다
- 그래도 WinForms보다 UI를 깔끔히 설계하고 싶다
라면, WPF가 가장 잘 맞는 일은 흔합니다.
물론 WPF에도 버릇은 있습니다.
- XAML을 너무 공들이면 읽기 어려워진다
- 커스텀 컨트롤이나 템플릿을 너무 겹치면 유지보수가 무겁다
- 「뭐든지 Binding으로 해결한다」 방침에 너무 붙으면, 오히려 처리 흐름을 쫓기 어렵다
이 점은 분명 있지만, WPF가 나쁘다기보다 표현력 있는 도구는 거칠게 휘두르면 반동도 크다는 이야기입니다.
WPF에서도 Windows App SDK의 일부 기능을 추가할 수 있습니다. 즉 WPF 그대로 Windows 기능을 현대화하는 길이 있습니다.810
이 때문에,
- WPF를 전부 버리고 WinUI로 전면 이전
보다,
- WPF를 현행 .NET에 맞춘다
- 필요한 Windows 기능만 Windows App SDK로 더한다
- 신규의 큰 기능부터 구성을 정리한다
쪽이 실무에서는 유리한 장면이 많습니다.
flowchart TB
accTitle: WPF 전면 이전보다 점진
accDescr: WPF를 전부 버리고 WinUI로 전면 이전하기보다, WPF를 현행 .NET에 맞추고, 필요한 Windows 기능만 Windows App SDK로 더하며, 신규의 큰 기능부터 구성을 정리하는 쪽이 실무에서는 유리하다는 것을 나타내는 그림.
z1["WPF를 현행 .NET에 맞춘다"] --> z2["필요한 기능만 SDK로 더한다"]
z2 --> z3["신규의 큰 기능부터 정리한다"]
z3 -.-> z4["전면 이전보다 유리하다"]
그림11: WPF는 전면 이전보다, 현행 .NET에 맞춰 기능을 더하는 점진적 접근이 유리하다.
5.3 WinUI
WinUI는 신규 Windows 전용 앱을 만들 때의 모던한 유력 후보입니다.12
공식에서는,
- 최신 하드웨어와 입력에 맞춰 최적화
- 고 DPI
- 부드러운 애니메이션
- Windows App SDK의 일부
라는 위치입니다.1
그래서 이런 일에 맞습니다.
- Windows 전용 신규 제품
- UI의 인상이나 경험 그 자체가 중요하다
- Fluent를 자연스럽게 쓰고 싶다
- Windows 11의 현재 위치에 맞추고 싶다
- 새 윈도우 API나 최신 Windows 경험을 전제로 하고 싶다
WinUI를 고를 이유가 분명히 있는 일이란, 대개 「모습이 새롭다」가 아니라 「지금의 Windows 경험을 제품에 넣고 싶다」는 일입니다.
flowchart TB
accTitle: WinUI를 고르는 이유의 가려내는 법
accDescr: WinUI를 고를 이유가 분명히 있는 일은, 모습이 새로워서가 아니라 지금의 Windows 경험을 제품에 넣고 싶은 일이라는 것을 나타내는 그림.
y1["WinUI를 고를 이유가 있는 일"] --> y2["「모습이 새롭다」가 아니라"]
y2 --> y3["「지금의 Windows 경험을 제품에」"]
y3 -.-> y4["Windows 전용 신규 제품·UI 인상이 중요하다"]
그림12: WinUI 채택 이유는 「새로움」이 아니라 「지금의 Windows 경험을 넣는 것」에 있다.
한편 주의점도 있습니다.
5.3.1 WinUI는 「그저 새로운 WPF」가 아니다
XAML을 쓰니 가까워 보이지만,
- 기반 API
- 컨트롤 주변
- 프로젝트 구성
- 배포 / packaging 사고방식
- Windows App SDK와의 관계
가 다릅니다.
즉 WPF에서 가볍게 바꿔 끼울 대상으로 보면 조금 위험합니다.
flowchart TB
accTitle: WinUI는 그저 새로운 WPF가 아니다
accDescr: XAML을 쓰니 가까워 보이지만, 기반 API, 컨트롤 주변, 프로젝트 구성, 배포와 packaging 사고방식, Windows App SDK와의 관계가 달라서, WPF에서 가볍게 바꿔 끼울 대상으로 보면 위험하다는 것을 나타내는 그림.
u1["XAML을 쓰니 가까워 보인다"] --> u2["그래도 다른 곳이 많다"]
u2 --> u3["기반 API·컨트롤"]
u2 --> u4["구성·packaging"]
u2 --> u5["SDK와의 관계"]
u5 -.-> u6["가벼운 교체 대상으로 보면 위험하다"]
그림13: XAML이 같아도, WinUI는 WPF에서 가볍게 바꿔 끼울 대상이 아니다.
5.3.2 WinUI를 고르면, 배포 이야기가 앞으로 나온다
WinUI 3 앱은 packaged가 기본입니다. 한편 Windows App SDK 자체는 packaged / unpackaged 둘 다를 다룹니다.13142
여기서 중요한 것은,
- 어떻게 배포할지
- 런타임을 어떻게 넣을지
- package identity가 필요한지
- 사내 배포인지, Store인지, MSIX인지, 기존 EXE / MSI 방식인지
를 일찍 정하는 편이 좋다는 점입니다.
다만 「일찍 확인」이라고만 들으면 무엇을 보면 되는지 알기 어려우니, 확인 내용을 여기에 둡니다.
- packaging: 그 앱이 package identity를 갖는지
- runtime: Windows App SDK를 framework-dependent로 쓸지, self-contained로 같이 넣을지
flowchart TB
accTitle: 먼저 정하는 두 축
accDescr: WinUI 배포에서는 먼저, 앱이 package identity를 갖는지라는 packaging 축과, Windows App SDK를 framework-dependent로 쓸지 self-contained로 같이 넣을지라는 runtime 축 둘을 정한다는 것을 나타내는 그림.
h1["배포 설계"] --> h2["packaging 축"]
h1 --> h3["runtime 축"]
h2 -.-> h4["package identity를 갖는가"]
h3 -.-> h5["framework-dependent인가 같이 넣는가"]
그림14: 배포에서는 packaging과 runtime의 두 축을 먼저 정한다.
packaging 쪽 선택지는 세 가지입니다.13
| 모델 | package identity | 설치 프로그램 | 맞는 장면 |
|---|---|---|---|
| packaged (MSIX) | 있음 | MSIX가 설치 프로그램을 대체한다 | 신규 개발, Store 공개, Intune 등에서의 기업 배포 |
| 외부 위치를 가리키는 packaged (sparse package) | 있음 | 기존 설치 프로그램을 그대로 쓴다 | 자체 설치 프로그램을 가진 기존 Win32 / WPF / WinForms |
| unpackaged | 없음 | MSI / EXE / xcopy | 사내 도구, 널리 배포하는 종래형 Win32 |
다음으로, package identity가 필요한지를 기능 쪽에서 판단합니다. 공식이 「package identity가 없으면 동작하지 않는다」고 명시한 기능은 예를 들어 이 부근입니다.13
- 백그라운드 작업
- 푸시 알림 (WNS)
- 공유 대상
- 탐색기의 컨텍스트 메뉴 확장
- 파일 종류와 URI 스킴 연결
- 시작 작업
- App Service
- Windows AI API
확인 절차는 이 순서가 실무적입니다.
- 요건에서 끌어낸다. 위 목록에 해당하는 기능을 쓸 계획이 있는지. 하나라도 있으면 packaged 쪽이 필요합니다.
- 기존 설치 프로그램을 버릴 수 있는지 본다. 버리고 싶지 않다면 MSIX로의 전면 이전이 아니라 외부 위치를 가리키는 packaged가 답이 됩니다. 기존 바이너리 배치와 업데이트 방식도 그대로 두고, identity만 더할 수 있습니다.13
- 실행 시에 확인한다. 실행 중인 프로세스에 identity가 있는지는
GetCurrentPackageFullName으로 판정할 수 있습니다. identity가 없으면APPMODEL_ERROR_NO_PACKAGE가 반환됩니다. 반대로 Windows API를 호출해E_ILLEGAL_METHOD_CALL이나APPMODEL_ERROR_NO_PACKAGE가 나오면, 그것이 package identity 요건에 걸린 신호입니다.13 - 기기에서 확인한다. 들어 있는 패키지는 PowerShell의
Get-AppxPackage로 목록을 볼 수 있습니다. - 마지막으로 runtime을 정한다. xcopy나 zip으로 배포하고 싶다면 self-contained, Store에 낸다면 framework-dependent가 기본 방식입니다.15
WinForms / WPF에서도 배포는 중요하지만, WinUI는 여기가 전면에 나오기 쉽습니다. 신규 WinUI 3 앱은 기본이 packaged이므로, 아무것도 정하지 않으면 자동으로 MSIX 방식으로 갑니다.13 UI를 정한 줄 알았는데 실은 배포 전략을 정하고 있었다, 가 이 세계의 조금 까다로운 점입니다.
flowchart TB
accTitle: package identity 확인 절차
accDescr: 요건에서 package identity가 필요한 기능을 끌어내고, 기존 설치 프로그램을 버릴 수 있는지 보고, 실행 시와 기기에서 확인한 뒤 마지막으로 runtime을 정한다는 5단계 확인 절차를 나타내는 그림.
s1["1. 요건에서 끌어낸다"] --> s2["2. 설치 프로그램을 버릴 수 있는지 본다"]
s2 --> s3["3. 실행 시에 확인한다"]
s3 --> s4["4. 기기에서 확인한다"]
s4 --> s5["5. runtime을 정한다"]
s2 -.-> s6["버리고 싶지 않다면 외부 위치를 가리키는 packaged"]
s3 -.-> s7["GetCurrentPackageFullName으로 판정"]
그림15: package identity의 필요 여부는 요건·설치 프로그램·실행 시·기기 순으로 확인한다.
5.3.3 「기존 WPF / WinForms에 조금씩 WinUI를 섞는다」는, 먼저 실험한다
여기는 기대가 부풀기 쉬운 지점입니다. 다만 Microsoft FAQ에서도, UI 프레임워크를 완전히 이전할 준비가 되어 있지 않은 한 WinUI는 쓸 수 없는 경우가 많다는 취지가 적혀 있습니다. 나아가 XAML Islands 주변도, 공식 문서에서는 기존 데스크톱 앱에 심는 경로가 보이는 한편, Windows App SDK 1.4 릴리스 노트에서는 현재로서는 C++ 앱에서의 이용이 주로 테스트되어 있으며, WPF / WinForms용 편리한 래퍼 요소는 들어 있지 않다고 되어 있습니다.1011
즉,
- 「단계 이전이 될 것 같다」
- 「조금씩 심으면 될 것 같다」
는 구상으로서는 매력적이어도, 일의 주전략으로 삼기 전에 작게 검증하는 편이 좋습니다.
WinUI는,
- 신규로 시작한다
- Windows 전용 제품으로서 경험을 만든다
때 가장 잘 맞습니다. 반대로 기존 WPF / WinForms를 통째로 바꿔 넣는 대상으로는, 이유와 검증이 필요합니다.
flowchart TB
accTitle: 단계 이전은 주전략으로 삼기 전에 검증
accDescr: 조금씩 WinUI를 섞는 단계 이전은 구상으로서 매력적이어도, FAQ에서는 완전 이전 준비가 되어 있지 않은 한 쓸 수 없는 경우가 많다고 하고, XAML Islands도 WPF나 WinForms용 편리한 래퍼가 들어 있지 않으므로, 주전략으로 삼기 전에 작게 검증해야 한다는 것을 나타내는 그림.
v1["조금씩 WinUI를 섞고 싶다"] --> v2["구상으로서는 매력적"]
v2 --> v3["FAQ는 완전 이전이 전제인 취지"]
v3 --> v4["WPF / WinForms용 래퍼는 없다"]
v4 --> v5["주전략으로 삼기 전에 작게 검증"]
그림16: 「조금씩 WinUI를 섞는다」는, 주전략으로 삼기 전에 작게 검증한다.
6. 흔한 판단 실수
6.1 「최신이니까 WinUI」
이것은 알기 쉽지만, 꽤 위험합니다.
새 기술을 고르는 이유는 그 기술이 아니면 얻을 수 없는 가치가 있는지로 보는 편이 좋습니다.
- 모던 Windows 경험이 제품 가치인가
- Fluent를 자연스럽게 쓰고 싶은가
- 신규 제품인가
- 배포 / 운영 전제를 받아들일 수 있는가
여기가 yes라면 WinUI는 유력합니다. 반대로 단지 「장래성이 있을 것 같다」뿐이면, 비용 설명이 약합니다.
flowchart TB
accTitle: 「최신이니까」가 아니라 가치로 고른다
accDescr: 새 기술을 고르는 이유는 그 기술이 아니면 얻을 수 없는 가치가 있는지로 봐야 하며, 모던 경험이 제품 가치인가 등의 질문에 yes라면 WinUI는 유력하고, 장래성이 있을 것 같다뿐이면 비용 설명이 약하다는 것을 나타내는 그림.
q0["새 기술을 고르는 이유"] --> q1{"그 기술이 아니면 얻을 수 없는 가치가 있는가"}
q1 -->|"yes"| q2["WinUI는 유력"]
q1 -->|"「장래성이 있을 것 같다」뿐"| q3["비용 설명이 약하다"]
그림17: 「최신이니까」가 아니라, 그 기술이 아니면 얻을 수 없는 가치가 있는지로 고른다.
6.2 「Windows App SDK를 쓰고 싶으니까 WinUI로 해야 한다」
이것은 오해되기 쉽지만, 다릅니다.
Windows App SDK는 기존 WPF / WinForms에도 더할 수 있습니다. 공식 FAQ에서도 WPF / MFC / WinForms 앱은 WinUI와 무관한 Windows App SDK API를 쓸 수 있다고 정리되어 있습니다.1089
예를 들어,
- App Lifecycle
- Windowing
- Toast Notifications
같은 기능은 지금 UI를 유지하면서 가져올 수 있는 경우가 있습니다.10
6.3 「WPF / WinForms는 이미 끝났다」
여기도 거칠게 잘라 내지 않는 편이 좋습니다.
WinForms도 WPF도 현행 .NET 위에서 문서와 마이그레이션 경로가 이어지고 있으며, 공식에서도 현역 Windows 데스크톱 UI로 다룹니다.34
장기 유지보수의 판단 재료로는 「문서가 남아 있는지」보다 새 기능이 계속 들어가는지가 더 알기 쉬운 지표입니다. 이 관점으로 보면 셋 모두 상황은 다음과 같습니다.
| 최근 움직임 | 보는 법 | |
|---|---|---|
| WPF | .NET 9에서 Windows 11용 Fluent 테마가 추가되고, ThemeMode 속성으로 light / dark / system을 전환할 수 있게 되었습니다. Windows 액센트 컬러에도 대응합니다16 |
「모습이 낡으니까 WinUI」라는 이유는 예전보다 약해졌습니다 |
| WinForms | .NET 9에서 다크 모드의 잠정 지원이 들어가고, Application.SetColorMode로 전환할 수 있습니다. 다만 이것은 실험적 기능이며, 정식 대응은 .NET 10을 목표로 한다고 적혀 있습니다. 비동기 대응 API도 늘고 있습니다17 |
새 기능은 들어가지만, 실험적 플래그가 붙은 것이 섞입니다 |
| WinUI / Windows App SDK | .NET과 다른 자체 릴리스 주기로 업데이트가 이어집니다18 | 업데이트는 활발하지만, .NET 버전과 따로 따라가야 하는 만큼 유지보수 계획 항목이 하나 늘습니다 |
즉 장기 유지보수 관점에서는 다음과 같이 읽을 수 있습니다.
- WPF와 WinForms는 「동결되어 방치」가 아니라, 매년 .NET 릴리스에 올라타 기능이 들어갑니다. 다만 WinForms의 핵심 기능은 실험 단계인 것이 있으므로, 채택 시기는 확인이 필요합니다.
- WinUI를 고르면 .NET 지원 기한과 Windows App SDK 지원 기한을 따로 관리하게 됩니다. 장기 프로젝트에서는 여기가 은근히 먹힙니다.
- 무엇을 골라도 「10년 뒤에도 무수정으로 돌아간다」는 보장은 없으므로, 어느 버전까지 따라갈지를 먼저 정해 두는 편이 실무적입니다.
flowchart TB
accTitle: 장기 유지보수를 읽는 법
accDescr: WPF와 WinForms는 매년 .NET 릴리스에 올라타 기능이 들어가고, WinUI를 고르면 .NET과 Windows App SDK의 지원 기한을 따로 관리하게 되므로, 어느 버전까지 따라갈지를 먼저 정해 둔다는 것을 나타내는 그림.
m1["WPF / WinForms"] --> m2[".NET 릴리스에 올라타 기능이 들어간다"]
m3["WinUI"] --> m4["SDK 기한을 따로 관리한다"]
m2 --> m5["어디까지 따라갈지 먼저 정한다"]
m4 --> m5
그림18: 장기 유지보수에서는, 무엇에 올라타 업데이트가 오는지를 보고, 따라갈 방침을 먼저 정한다.
특히 업무 앱에서는,
- 기존 자산
- 서드파티 컨트롤
- 화면 수
- 장표나 인쇄
- 장치 연동
- 배포 절차
쪽이 UI 프레임워크의 새로움보다 무거운 일이 흔합니다.
6.4 「이왕이면 전면 재작성」
전면 재작성은 기술 선정이 아니라 사업 판단에 가깝습니다.
기존 앱이 있다면 먼저 봐야 할 것은 이 부근입니다.
- 무엇이 진짜로 곤란한지
- UI 문제인지, 아키텍처 문제인지
- 의존 DLL / COM / OCX / 장표 / 배포가 진짜 짐이 아닌지
- UI를 전부 바꾸지 않아도 곤란함이 풀리는지
UI 재작성은 화려하지만, 비용도 화려합니다. 게다가 모습은 새로워져도, 주변의 까다로움은 대개 남습니다.
flowchart TB
accTitle: 전면 재작성 전에 보는 네 질문
accDescr: 전면 재작성은 기술 선정이 아니라 사업 판단에 가깝고, 무엇이 진짜로 곤란한지, UI인지 아키텍처 문제인지, 의존이나 배포가 진짜 짐이 아닌지, UI를 전부 바꾸지 않아도 풀리는지를 먼저 본다는 것을 나타내는 그림.
r1["1. 무엇이 진짜로 곤란한가"] --> r2["2. UI인가 아키텍처인가"]
r2 --> r3["3. 의존이나 배포가 짐이 아닌가"]
r3 --> r4["4. UI를 바꾸지 않고 풀리는가"]
r4 -.-> r5["재작성은 비용도 화려하다"]
그림19: 전면 재작성을 정하기 전에, 곤란함의 정체를 네 질문으로 확인한다.
6.5 「나중에 XAML Islands로 어떻게든 된다」
이 기대는 이해할 수 있습니다. 그러나 처음부터 구명보트 취급하지 않는 편이 안전합니다.1011
단계 이전은,
- 심고 싶은 컨트롤은 무엇인지
- 포커스, 입력, DPI, 테마는 어떻게 되는지
- 실제로 그 호스트 구성이 안정되는지
를 먼저 작게 시험하는 편이 좋습니다.
flowchart TB
accTitle: XAML Islands는 먼저 작게 시험한다
accDescr: 단계 이전에서는 심고 싶은 컨트롤은 무엇인지, 포커스·입력·DPI·테마는 어떻게 되는지, 그 호스트 구성이 안정되는지를 먼저 작게 시험하고, 처음부터 구명보트 취급하지 않는다는 것을 나타내는 그림.
p0["「나중에 어떻게든 된다」는 기대"] --> p1["심고 싶은 컨트롤은 무엇인가"]
p0 --> p2["포커스·입력·DPI·테마"]
p0 --> p3["호스트 구성은 안정되는가"]
p1 --> p4["먼저 작게 시험한다"]
p2 --> p4
p3 --> p4
그림20: XAML Islands는 구명보트 취급하지 않고, 세 점을 먼저 작게 시험한다.
7. 기존 앱을 전제로 할 때의 보는 법
여기는 신규보다 기존이 더 중요합니다.
7.1 기존 WinForms가 있다면
먼저, 갑자기 WinUI로 날아가기 전에 여기를 확인합니다.
- 현행 .NET에 맞출 수 있는지
- 64bit화가 필요한지
- async / await, 예외 처리, 설정, 로그를 정리할 수 있는지
- 화면 분할이나 UserControl로 나눠 유지보수성을 올릴 수 있는지
- 필요한 Windows 기능만 Windows App SDK로 더할 수 있는지
WinForms 문제로 보이지만 실제로는
- 화면과 로직이 섞여 있다
- 스레드 경계가 거칠다
- 설정 / 파일 / COM / DB 책임이 꽉 차 있다
뿐인 일이 드물지 않습니다.
그 경우 WinUI로 옮겨도, 문제가 이름만 바꿔 남을 뿐입니다.
flowchart TB
accTitle: 문제가 이름만 바꿔 남는다
accDescr: WinForms 문제로 보이지만 실제로는 화면과 로직의 혼재, 거친 스레드 경계, 책임의 밀어 넣기가 원인인 일이 드물지 않고, 그 경우 WinUI로 옮겨도 문제가 이름만 바꿔 남을 뿐이라는 것을 나타내는 그림.
e1["WinForms 문제로 보인다"] --> e2["실은 구조 문제"]
e2 --> e3["화면과 로직의 혼재"]
e2 --> e4["거친 스레드 경계"]
e2 --> e5["책임의 밀어 넣기"]
e4 --> e6["WinUI로 옮겨도 이름만 바꿔 남는다"]
그림21: UI 문제로 보이는 구조 문제는, 프레임워크를 바꿔도 남는다.
7.2 기존 WPF가 있다면
WPF는 기존 자산을 살리기 쉽습니다.
- XAML 자산
- Binding
- Style / Template
- Command
- MVVM
이 부근을 버릴 이유는 꽤 분명해야 합니다.
예를 들어,
- 제품 UI를 전면 쇄신하고 싶다
- Fluent를 주축으로 하고 싶다
- 신규 모듈을 별도 제품으로 잘라 낸다
- Windows 전용 제품으로서 새 경험에 맞추고 싶다
라면 WinUI 검토 이유가 됩니다. 그러나 단지 「WPF는 낡으니까」라면 약합니다.
7.3 진짜 무거운 것은 UI 밖인 경우가 많다
실무에서 힘든 것은 의외로 이 부근입니다.
- ActiveX / OCX
- COM interop
- 자체 장표
- 인쇄
- Excel / Office 연동
- 네이티브 DLL
- 32bit / 64bit의 비틀림
- 설치 프로그램, 권한, 업데이트, 서명
여기를 가볍게 보면, UI만 깔끔해져도 일 전체는 가벼워지지 않습니다.
그래서 기존 앱 이전에서는 UI 프레임워크만 보지 말고, 의존 경계마다 점검·목록화하는 편이 먼저입니다.
flowchart TB
accTitle: 의존 경계마다 점검·목록화한다
accDescr: 실무에서 무거운 것은 ActiveX나 COM, 장표나 인쇄, 네이티브 DLL, 설치 프로그램이나 업데이트 등 UI 밖인 경우가 많고, UI 프레임워크만 보지 말고 의존 경계마다 점검·목록화하는 편이 먼저라는 것을 나타내는 그림.
d1["ActiveX / COM interop"] --> d4["진짜 무거운 것은 UI 밖"]
d2["장표·인쇄·Office 연동"] --> d4
d3["설치 프로그램·권한·업데이트·서명"] --> d4
d4 --> d5["의존 경계마다 점검·목록화가 먼저"]
d5 -.-> d6["UI만 깔끔해져도 가벼워지지 않는다"]
그림22: 이전에서 진짜 무거운 것은 UI 밖의 의존이며, 점검·목록화를 먼저 한다.
8. 망설일 때 마지막으로 보는 5가지 질문
최종적으로 망설이면, 이 다섯 질문을 순서대로 적용합니다.
8.1 기존 자산은 큰가
- 크다 → 기존 계열을 기본 유지
- 작다 / 없다 → 신규 선정으로
8.2 그 앱에서 「Windows다운 모던 경험」은 필수인가
- 필수 → WinUI가 유력
- 그렇게까지는 아니다 → WPF / WinForms로 충분한지 확인
8.3 화면은 표준 폼 중심인가, XAML 수준의 표현력이 필요한가
- 표준 폼 중심 → WinForms
- 스타일 / 템플릿 / Binding / MVVM이 중요하다 → WPF
8.4 원하는 것은 UI 전면 쇄신인가, Windows 기능 추가인가
- UI 전면 쇄신 → WinUI 검토
- 기능 추가만 → 현행 WPF / WinForms + Windows App SDK를 먼저 검토
8.5 배포 / 업데이트 / 운영을 어떻게 할지, 먼저 설명할 수 있는가
- 아직 모호하다 → WinUI는 일찍 packaging / deployment를 구체화한다
- 기존 운영에 강하게 태우고 싶다 → WPF / WinForms 쪽이 마찰이 적은 경우가 많다
flowchart TB
accTitle: 마지막으로 보는 5가지 질문의 흐름
accDescr: 기존 자산은 큰가, 모던 경험은 필수인가, 표준 폼 중심인가 표현력이 필요한가, 배포·업데이트·운영을 설명할 수 있는가라는 질문을 순서대로 적용해 선택지를 좁히는 흐름을 나타내는 그림.
f1{"기존 자산은 큰가"} -->|"크다"| f2["기존 계열을 기본 유지"]
f1 -->|"작다·없다"| f3{"모던 경험은 필수인가"}
f3 -->|"필수"| f4["WinUI가 유력"]
f3 -->|"그렇게까지는 아니다"| f5{"표준 폼 중심인가"}
f5 -->|"예"| f6["WinForms"]
f5 -->|"표현력이 중요하다"| f7["WPF"]
f2 -.-> f8["기능 추가뿐이라면 SDK를 먼저 검토"]
f4 -.-> f9["packaging과 배포를 일찍 구체화한다"]
그림23: 망설이면, 기존 자산·경험·화면의 성격 순으로 질문을 적용해 좁힌다.
이 다섯 질문으로 꽤 좁혀집니다. 마지막으로 거칠게 정리하면 이런 느낌입니다.
- 빨리 만드는 사내 폼 → WinForms
- 길게 자랄 Windows 업무 앱 → WPF
- 신규 모던 Windows 제품 UI → WinUI
- 기존을 살리면서 Windows 기능만 현대화 → 현행 프레임워크 + Windows App SDK
9. 정리
WinForms, WPF, WinUI 선정은 새로운 순으로 늘어놓고 맨 오른쪽을 취하는 게임이 아닙니다.
먼저 봐야 할 것은 이 넷입니다.
- 기존 자산이 어디에 있는지
- 화면이 폼 중심인지, 표현력 중심인지
- Windows다운 모던 UI가 제품 요건인지
- 배포 / 업데이트 / 운영을 어떻게 돌릴지
이 넷이 보이면, 방침은 대개 정해집니다.
flowchart TB
accTitle: 정리의 네 질문
accDescr: 기존 자산이 어디에 있는지, 화면이 폼 중심인지 표현력 중심인지, 모던 UI가 제품 요건인지, 배포·업데이트·운영을 어떻게 돌릴지 넷이 보이면 방침은 대개 정해진다는 것을 나타내는 그림.
n1["기존 자산"] --> n5["방침이 대개 정해진다"]
n2["화면의 성격"] --> n5
n3["모던 UI 요건"] --> n5
n4["배포와 운영"] --> n5
그림24: 네 질문이 보이면, 프레임워크 방침은 대개 정해진다.
- 기존 WinForms를 크게 가지고 있다면, 먼저 WinForms 유지
- 기존 WPF를 크게 가지고 있다면, 먼저 WPF 유지
- 신규로 표준 폼 중심이면 WinForms
- 신규로 중~대규모 Windows 업무 앱이면 WPF
- 신규로 모던 Windows 경험 그 자체가 요건이면 WinUI
- Windows App SDK를 쓰고 싶을 뿐이라면, 갑자기 전부 WinUI로 하지 않는다
가장 피하고 싶은 것은,
- 낡으니까 버린다
- 새로우니까 고른다
- 중간에 어떻게든 되겠지로 시작한다
셋입니다.
Windows 데스크톱은 모습보다 자산, 배포, 운영, 의존 관계 쪽이 무거운 세계입니다. 그래서 새로움보다, 기존 자산·배포·운영과의 마찰이 적은 선택을 중시하는 편이 실무적입니다.
10. 참고 자료
-
Microsoft Learn, “WinUI 3 - Windows apps” / Microsoft Learn, “Modernize your desktop apps for Windows” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, “Windows 폼이란 - Windows Forms” ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, “Windows Presentation Foundation이란 - WPF” ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, “What is Windows Forms Designer?” ↩ ↩2
-
Microsoft Learn, “Data binding overview - WPF” ↩ ↩2 ↩3
-
Microsoft Learn, “Commanding Overview - WPF” ↩ ↩2 ↩3
-
Microsoft Learn, “WPF 앱에서 Windows App SDK를 사용한다” ↩ ↩2 ↩3
-
Microsoft Learn, “Use the Windows App SDK in a Windows Forms (WinForms) app” ↩ ↩2 ↩3
-
Microsoft Learn, “Windows 개발자용 FAQ” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, “Windows App SDK 1.4 release notes” / Microsoft Learn, “Windows App SDK” ↩ ↩2 ↩3
-
Microsoft Learn, “Windows data binding and MVVM” ↩
-
Microsoft Learn, “Packaging overview - Windows apps” / Microsoft Learn, “Grant package identity by packaging with external location” ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, “Quick start: Set up your environment and create a WinUI 3 project” ↩
-
Microsoft Learn, “Package and deploy Windows apps overview” ↩ ↩2
-
Microsoft Learn, “What’s new in WPF for .NET 9” ↩
-
Microsoft Learn, “What’s new in WinForms for .NET 9” ↩
-
Microsoft Learn, “Windows App SDK release channels” ↩
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
Windows 앱 외주·수탁 개발을 의뢰하기 전에 정리할 점
Windows 앱 외주·수탁 개발을 의뢰하기 전에, 기존 소프트웨어 수정, 장치 연동, COM/ActiveX, 배포·업데이트, 유지보수를 정리하는 포인트를 설명합니다.
「응답 없음」의 정체 ── Windows가 앱을 「멈췄다」고 판단하는 구조와, 멈추지 않는 설계
Windows의 「응답 없음」은 창이 5초 동안 메시지를 꺼내지 않으면 OS가 판단해 고스트 창으로 교체하는 구조입니다. 판단의 내부 동작부터 멈추는 전형적인 원인, UI 스레드에서 무거운 처리를 빼내는 설계, hang 조사 절차까지 설명합니다.
WinForms / WPF 앱의 CI/CD 실전 ── GitHub Actions로 빌드부터 서명·배포까지 자동화하기
WinForms / WPF 앱의 CI/CD를 GitHub Actions로 구성하는 실무 가이드입니다. windows-latest에서 빌드+테스트를 돌리는 최소 YAML, 태그 기반 버전 부여, signtool 서명 연동, MSI/MSIX/Clic...
Windows 앱의 작업 트레이 상주와 토스트 알림 ── NotifyIcon의 함정과 AppNotification 고르는 법
업무용 Windows 앱의 작업 트레이 상주와 토스트 알림 구현을 정리합니다. NotifyIcon의 올바른 사용법, Explorer 재시작 시 재등록, 토스트 API 3종의 선정 판단표, 알림이 도착하지 않는 경우까지 설명합니다.
.NET Generic Host와 BackgroundService를 데스크톱 앱에서 쓰는 이유
Windows 도구나 상주 앱에서 시작, 주기 처리, 종료 처리, 로그, 설정, DI를 정리하기 위해 Generic Host와 BackgroundService를 어떻게 쓰는지 정리합니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
UI 스레드 & 타이머
WPF / WinForms UI 스레드, async 흐름, Dispatcher 사용, 타이머 판단을 정리한 토픽 페이지입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
WinForms, WPF, WinUI 선정은 Windows 데스크톱 앱의 신규 개발이나 기존 자산의 수명 연장 방침에 직결되는 주제입니다.
기술 상담 & 설계 리뷰
기존 자산, Windows App SDK, 배포 설계, UI 표현, MVVM 문화까지 포함해, 어떤 선택이 마찰이 가장 적은지를 정리하는 단계에 맞습니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- WinUI 3와 WPF의 차이는 무엇인가요?
- 둘 다 XAML을 쓰지만, WinUI는 「그저 새로운 WPF」가 아닙니다. 기반 API, 컨트롤 주변, 프로젝트 구성, 배포 / packaging 사고방식, Windows App SDK와의 관계가 다릅니다. WPF는 해상도 독립의 벡터 기반 그리기, 데이터 바인딩, 스타일 / 템플릿, 커맨드를 갖춘 중~대규모 업무 앱용 UI 프레임워크이고, WinUI는 Windows App SDK의 일부로서 Fluent나 고 DPI, 최신 Windows 경험을 전제로 한 모던 UI 프레임워크입니다. WPF에서 가볍게 바꿔 끼울 대상으로 보면 위험합니다.
- 신규 개발에서는 WinForms·WPF·WinUI 중 무엇을 골라야 하나요?
- 화면의 성격과 제품 요건으로 갈립니다. 표준 컨트롤 중심·입력 폼 중심의 소~중규모 사내 도구를 빨리 만든다면 WinForms가 아직 상당히 강합니다. 화면 수가 많고 데이터 바인딩, 스타일, 템플릿, MVVM을 제대로 쓰고 싶은 중~대규모 업무 앱이라면 WPF가 가장 무난한 경우가 많습니다. Windows 전용 신규 제품에서 Fluent나 모던 Windows 경험이 제품 가치에 직결된다면 WinUI가 유력합니다. 기존 자산이 크다면 먼저 그 계열의 유지를 기본으로 봅니다.
- WPF나 WinForms는 이제 낡은 기술인가요?
- 거칠게 잘라 내지 않는 편이 좋습니다. WinForms도 WPF도 현행 .NET 위에서 문서와 마이그레이션 경로가 이어지고 있으며, 공식에서도 현역 Windows 데스크톱 UI로 다룹니다. 특히 업무 앱에서는 기존 자산, 서드파티 컨트롤, 장표나 인쇄, 장치 연동, 배포 절차 쪽이 UI 프레임워크의 새로움보다 무거운 일이 흔합니다. 신규라도 WinForms나 WPF가 마찰이 가장 적은 선택이 되는 장면은 드물지 않습니다.
- 최신 Windows 기능을 쓰려면 WinUI로 이전해야 하나요?
- 아닙니다. Windows App SDK와 WinUI는 같지 않고, WinUI는 Windows App SDK의 UI 프레임워크 부분입니다. Windows App SDK 자체는 WPF / WinForms / Win32의 기존 앱에도 추가할 수 있고, App Lifecycle, Windowing, Toast Notifications 같은 기능은 지금 UI를 유지하면서 가져올 수 있는 경우가 있습니다. 즉 기존 WPF / WinForms 그대로 필요한 Windows 기능만 현대화하는 길이 있으며, UI 전면 이전은 필수가 아닙니다.