C# WinForms 대시보드 폼 구축
C# App From Start to Finish 시리즈의 Lesson 21에서는 Tim Corey가 WinForms 애플리케이션에서 토너먼트 대시보드 폼을 연결하는 데 중점을 둡니다. 이 폼은 애플리케이션의 시작 화면으로 작동하며 사용자가 기존 토너먼트를 로드하거나 새로 만들 수 있는 진입점 역할을 합니다. WinForms 대시보드는 사용자의 행동에 따라 코드로 처리되는 특정 이벤트를 트리거하는 Windows Forms의 이벤트 중심 기능을 활용하는 프로그램입니다.
Tim은 이 교훈이 복잡한 UI 작업에 관한 것이 아니라 데이터를 연결하고, 모델을 구성하고, 저장 절차와 폼을 깔끔하고 일관성 있게 연결하는 것이라고 설명합니다. 참고: WinForms는 특히 재고 관리, CRM 시스템, 회계 도구와 같은 회사 내부 소프트웨어에 적합합니다. WinForms 대시보드가 실제 애플리케이션에서 어떻게 작동하는지 진정으로 이해하기 위해, Tim은 토너먼트를 로드하고, 모델을 수화시키고, 데이터베이스 연결을 처리하고, UI 컨트롤을 연결하는 과정을 단계별로 안내합니다.
이 기사에서는 Tim의 동영상 설명을 정확하게 따라가면서, 쉬운 참조를 위해 타임스탬프가 포함된 섹션별로 대시보드 폼을 더 깊이 살펴보겠습니다. WinForms 애플리케이션은 일반적으로 가벼우며 뛰어난 성능을 제공하여 오래되거나 성능이 낮은 하드웨어에 이상적입니다.
대시보드 폼 소개
맨 처음에 Tim은 Lesson 21을 소개하고 목표를 설명합니다: 애플리케이션이 시작할 때 처음 실행되는 폼인 토너먼트 대시보드 폼을 연결하는 것입니다.
Tim은 이 폼이 의도적으로 간단하다고 지적합니다. 이 폼은 몇 가지 기능만 수행합니다:
기존 토너먼트 목록 로드
사용자가 토너먼트를 선택하고 로드할 수 있도록 허용
- 사용자가 새로운 토너먼트를 만들 수 있도록 허용
그는 이 수업이 길거나 너무 복잡하지 않을 것이지만, 시스템의 많은 중요한 부분을 다룰 것이라고 시청자에게 안심시킵니다.
대시보드 폼의 책임
Tim은 대시보드 폼이 두 가지 주요 책임을 가지고 있다고 설명합니다:
기존 토너먼트를 드롭다운으로 로드
- 사용자 행동에 따라 다른 폼 열기
이미 토너먼트가 존재하는 경우, 사용자는 이를 선택하고 "Load Tournament" 버튼을 클릭할 수 있으며, 이는 나중에 연결될 것입니다. 사용자가 새로운 토너먼트를 만들고 싶다면, "Create Tournament" 버튼을 클릭하면 프로젝트에 이미 존재하는 폼이 열립니다.
이 시점에서 Tim은 "Load Tournament" 버튼이 아직 연결되지 않았고 나중에 레슨에서 다루어질 것이라고 명확히합니다.
드롭다운 토너먼트 목록 생성
C# 프로젝트 템플릿을 선택한 후, Visual Studio는 사용자 인터페이스를 디자인할 수 있는 폼을 엽니다.
Tim은 폼의 코드 비하인드로 전환하여 드롭다운에 백킹 리스트가 필요하다고 설명합니다. 디자이너에서 폼이 UI 커스터마이징을 위해 준비된 상태로 나타나는 것을 확인합니다. 드롭다운은 토너먼트를 표시하기 위해 설계되었으므로, 백킹 리스트는 List
그는 tournaments라는 이름의 개인 리스트를 만들고 수동으로 새로운 리스트를 생성하는 대신 데이터는 SQL이나 텍스트 파일 등 데이터 소스를 추상화하는 GlobalConfig 연결에서 가져와야 한다고 설명합니다.
그런 다음 Tim은 GetTournament_All이라는 메서드를 호출하려고 시도하고 그것이 아직 존재하지 않음을 인식하며, 이 메서드가 데이터 접근 계층에 추가되어야 한다고 설명합니다.
데이터 계층에 GetTournament_All 추가
Tim은 SQL 커넥터로 이동하여 누락된 GetTournament_All 메서드를 구현합니다. 그는 이 메서드가 TournamentModel 객체의 리스트를 반환할 것이라고 설명합니다.
그는 프로젝트 다른 곳에서 사용된 기존 패턴을 복사하여 토너먼트에 맞게 수정합니다. 주요 차이점은 이 메서드가 다음과 같은 저장 절차를 호출한다는 것입니다:
spTournaments_GetAllTim은 이 저장 절차가 기본 토너먼트 데이터만 검색한다고 설명합니다:
ID
토너먼트 이름
참가비
- 활성 상태
그는 TournamentModel이 훨씬 더 많은 속성을 포함하고 있지만, 이것은 단지 첫 번째 단계일 뿐이라고 주석을 답니다.
부분 모델 수화 이해하기
Tim은 중요한 개념인 부분 수화를 설명하기 위해 멈춥니다.
토너먼트 모델이 팀, 상, 라운드를 포함하고 있지만, 이러한 속성들은 아직 채워지지 않았습니다. 이 단계에서는:
팀은 비어 있습니다
상은 비어 있습니다
- 라운드는 비어 있습니다
기본 토너먼트 속성만 채워진 상태이며, 팀, 상 및 라운드와 같은 관련 엔티티는 추가 로딩이 이루어질 때까지 비어 있어야 하는 것이 기대됩니다.
Tim은 이것이 의도적이며 이러한 관련 엔티티는 기본 토너먼트 레코드가 로드된 후에 채워져야 한다고 강조합니다.
각 토너먼트에 대한 상 채우기
Tim은 데이터베이스에서 반환된 모든 토너먼트를 반복하는 foreach 루프를 소개합니다.
상에 대해, 그는 과정이 간단하다고 설명합니다:
토너먼트 ID별로 상을 검색하는 저장 절차 호출
- 결과를 T.Prizes에 할당
그는 spPrizes_GetByTournament 저장 절차를 참조하며, 이는 주어진 토너먼트에 연결된 모든 상을 반환한다고 설명합니다.
이 패턴—기본 데이터를 로드한 다음 ID로 자식 데이터를 로드하는 것—은 Tim이 애플리케이션 전체에서 반복되는 것으로 강조합니다.
팀 및 팀원 로딩하기
다음으로, Tim은 입력된 팀으로 넘어갑니다.
그는 팀을 로드하는 것이 두 단계 과정이라고 설명합니다:
토너먼트와 관련된 팀 로드
- 각 팀에 대해 팀원 로드
그는 현재 토너먼트와 관련된 팀만 검색하기 위해 spTeams_GetByTournament라는 저장 절차를 사용합니다.
그런 다음, 각 팀에 대해 팀 ID로 팀원을 로드하기 위해 기존 메서드를 재사용합니다. 그는 이 코드가 시리즈 초반에 쓴 코드와 거의 동일하다고 지적하지만, 토너먼트 관련 데이터를 위해 수정된 것이라고 설명합니다.
라운드의 복잡성 소개
Tim은 토너먼트 모델에서 라운드가 가장 복잡한 부분임을 설명합니다.
라운드는 다음과 같이 저장됩니다:
List<List<MatchupModel>>이를 채우기 위해, Tim은 다음을 해야 합니다:
토너먼트에 대한 모든 맞대결 로드
각 맞대결에 대한 맞대결 항목 로드
- 부모 맞대결 및 우승자와 같은 관계 해결
그는 저장 절차를 검토하기 시작합니다:
spMatchups_GetByTournament
- spMatchupEntries_GetByMatchup
우승자 ID와 중첩 모델 처리하기
Tim은 데이터베이스 작업 시 일반적인 문제를 지적합니다: SQL은 ID를 반환하지만 애플리케이션은 객체를 기대합니다.
Winner 속성은 TeamModel이며, 데이터베이스는 WinnerId만 반환합니다. Tim은 SQL에서 직접 중첩 객체를 수화할 수 없음을 설명합니다.
이 문제를 해결하기 위해, 그는 데이터 로딩 도중에만 사용되는 임시 WinnerId 속성을 모델에 추가합니다. 모든 팀이 로드되면, 그는 ID를 사용하여 Winner 속성에 올바른 TeamModel을 할당합니다.
맞대결 항목 및 부모 맞대결 채우기
각 맞대결에 대해, Tim은:
맞대결 ID로 맞대결 항목 로드
유효한 팀 ID 확인
- 모든 팀의 캐시된 목록을 사용하여 관계 해결
그는 값이 없을 때 ID가 기본적으로 0이 되는 이유와 > 0 검사가 중요한 이유를 설명합니다.
Tim은 또한 맞대결이 라운드 순서로 정렬되어 있기 때문에 이미 로드된 맞대결을 참조하여 부모 맞대결이 해결되는 방법을 설명합니다.
라운드 구조 구축하기
모든 맞대결이 완전히 채워진 후, Tim은 라운드가 어떻게 구성되는지를 설명합니다.
그는 다음을 소개합니다:
currentRound 변수
- currentRow 리스트
그가 맞대결을 루프할 때:
라운드 번호가 변경되면, 이전 라운드는 T.Rounds에 추가됩니다
새 라운드 목록 생성
- 맞대결을 적절하게 그룹화
Tim은 논리의 명확성을 보장하기 위해 전체 예제를 지나가고, 루프를 분리하면 코드가 더 이해하기 쉬워진다고 강조합니다.
대시보드 드롭다운 연결
Visual Studio의 도구 상자에서 드래그하여 라벨, 텍스트 박스, 드롭다운과 같은 일반적인 컨트롤을 폼에 추가할 수 있습니다.
대시보드 폼으로 돌아가서, Tim은 WireUpLists() 메서드를 생성합니다.
그는 다음을 할당합니다:
DataSource를 tournaments 리스트에 할당
- DisplayMember를 TournamentName에 할당
라벨은 드롭다운의 목적을 설명하기 위해 자주 사용되며, 텍스트 박스는 폼에서 사용자 입력을 위해 사용할 수 있습니다. 사용자 상호작용을 처리하기 위해, 디자이너에서 버튼을 더블 클릭하여 Form1.cs 파일에 자동으로 Click 이벤트 핸들러를 생성할 수 있습니다.
그는 이것이 객체 참조 대신 사람이 읽을 수 있는 이름을 드롭다운에 표시하도록 만드는 이유라고 설명합니다.
SQL 및 텍스트 파일 연결 테스트
Tim은 두 데이터 소스를 사용하여 애플리케이션을 실행합니다:
텍스트 파일 연결은 즉시 작동함
- SQL 연결은 오류를 발생시킴
Visual Studio에서 '시작' 버튼을 선택하거나 F5를 눌러 애플리케이션을 실행할 수 있습니다.
그는 오류 메시지를 설명하고, 이 버그가 누락된 매개변수로 인해 발생했음을 확인한 후, 여러 데이터 소스를 통합할 때 이러한 버그는 일반적이라고 언급합니다. 이 버그는 토너먼트 ID를 저장 절차에 올바르게 전달함으로써 수정되었습니다.
상과 팀 모두를 수정한 후, Tim은 두 데이터 소스가 이제 정상적으로 작동한다고 확인합니다. 버그를 식별하고 수정하는 것은 개발 과정의 정상적인 부분이며, 특히 여러 데이터 소스를 통합할 때 그렇습니다.
Create Tournament 버튼 연결
마지막으로, Tim은 Create Tournament 버튼의 이벤트, 특히 Click 이벤트를 처리하여 연결합니다.
그는 버튼의 이벤트 처리 코드는 Form1.cs 파일에 작성되며, 이는 UI 코드를 자동으로 생성하는 Form1.Designer.cs 파일을 수동으로 수정해서는 안 된다고 설명합니다.
버튼은 단순히:
Create Tournament 폼의 새 인스턴스 생성
- Show() 호출
그는 사용자가 토너먼트를 만든 후 어디로 가야 할 것인지에 대한 디자인 결정을 논의하고, 토너먼트 뷰어로 직접 이동하는 것이 가장 논리적이라고 설명합니다.
결론 및 향후 계획
Tim은 수행한 작업을 정리하며 결론을 내립니다:
대시보드는 토너먼트를 로드합니다
드롭다운은 올바르게 채워집니다
- Create Tournament 폼이 성공적으로 열립니다
그는 토너먼트 생성 후 목록을 새로 고칠 것은 나중에 처리될 것이라고 언급합니다.
다음 강좌에서는 Tim은 토너먼트 시스템을 활성화하여, 라운드, 맞대결, 점수 계산 및 진행이 구현될 Tournament Viewer Form을 미리 보기로 시연합니다. 앞으로 나온 레슨의 버전에서는 WinForms와 .NET의 새로운 버전 릴리스와 관련된 업데이트를 포함하여 추가 기능 및 개선 사항을 다룰 것입니다.
이 강좌는 WinForms 대시보드가 단순한 UI가 아니라 모델, 데이터 접근, 네비게이션의 조정 포인트임을 보여주며, Tim이 단계별로 신중하게 데모합니다.
WinForms는 안정성, 빠른 개발 속도 및 Windows 운영 체제와의 깊은 통합 덕분에 여전히 높은 관련성을 가지고 있습니다.

