본문 바로가기
WPF

WPF ComboBox와 MSSQL 연동 완벽 가이드

by 개발하는 늑대 2025. 3. 7.
728x90

 

 

 

WPF ComboBox와
MSSQL 연동 완벽 가이드

이 포스트에서는 WPF ComboBox를 활용해 로컬 MSSQL 데이터베이스와 연동하는 방법을 다룹니다. XAMLC# 소스 코드를 제공하며, C# 코드에는 상세 주석을 추가했습니다. 데이터 로드, 추가, 수정 기능과 ObservableCollection 사용법을 초보자도 이해할 수 있도록 설명합니다.

주요 키워드: WPF, ComboBox, MSSQL, 데이터 바인딩, ObservableCollection, C#, XAML, Windows 인증

1. 준비 단계: MSSQL 설정

WPF에서 MSSQL 데이터를 사용하려면 데이터베이스를 준비해야 합니다. 로컬 MSSQL에 People 테이블을 생성합니다.

테이블 생성 SQL

CREATE DATABASE TestDB;
USE TestDB;
CREATE TABLE People (
    Id INT PRIMARY KEY IDENTITY(1,1),
    Name NVARCHAR(100) NOT NULL
);
INSERT INTO People (Name) VALUES ('John Doe'), ('Jane Smith'), ('Bob Johnson');

설명: TestDB 데이터베이스를 만들고, Id(자동 증가 기본 키)와 Name(최대 100자 문자열) 열을 정의합니다. 초기 데이터를 삽입해 테스트를 준비합니다.

  • Server: localhost - 로컬 MSSQL 서버.
  • 인증: Trusted_Connection=True로 Windows 계정 사용.

참고: MSSQL이 설치되어 있지 않다면 SQL Server Express를 설치하세요.

2. WPF ComboBox 샘플 소스

WPF ComboBox를 통해 MSSQL 데이터를 표시하고, 추가 및 수정 기능을 구현합니다. XAML과 C# 코드를 모두 제공합니다.

XAML 코드 (MainWindow.xaml)

<Window x:Class="WpfComboBoxSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF ComboBox with MSSQL" Height="400" Width="500">
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="이름 선택:" FontWeight="Bold" Margin="0,0,0,5"/>
        <ComboBox x:Name="dataBoundComboBox" Grid.Row="1" Width="200" HorizontalAlignment="Left" 
                  DisplayMemberPath="Name" SelectedValuePath="Id" 
                  SelectionChanged="DataBoundComboBox_SelectionChanged" Margin="0,0,0,10"/>
        <TextBlock Grid.Row="2" Text="선택된 항목:" FontWeight="Bold" Margin="0,0,0,5"/>
        <StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0,0,0,10">
            <TextBox x:Name="editNameTextBox" Width="150" Margin="0,0,10,0"/>
            <Button Content="수정" Width="60" Click="UpdateButton_Click"/>
        </StackPanel>
        <StackPanel Grid.Row="4" Orientation="Horizontal">
            <TextBox x:Name="newNameTextBox" Width="150" Margin="0,0,10,0"/>
            <Button Content="추가" Width="60" Click="AddButton_Click"/>
        </StackPanel>
    </Grid>
</Window>

설명: ComboBox로 데이터 선택 UI를 구성하고, TextBox와 버튼으로 추가/수정 인터페이스를 제공합니다. DisplayMemberPath는 표시할 속성, SelectedValuePath는 값으로 사용할 속성을 지정합니다.

C# 코드 (MainWindow.xaml.cs) - 상세 주석 포함

using System; // 기본 클래스와 예외 처리 사용
using System.Collections.ObjectModel; // ObservableCollection 클래스 사용
using System.Data.SqlClient; // MSSQL 데이터베이스 연결
using System.Windows; // WPF 창 및 기본 기능
using System.Windows.Controls; // UI 컨트롤(ComboBox, Button 등)

namespace WpfComboBoxSample
{
    public partial class MainWindow : Window
    {
        // MSSQL 연결 문자열: 로컬 서버 접속, TestDB 사용, Windows 인증
        private readonly string connectionString = "Server=localhost;Database=TestDB;Trusted_Connection=True;";
        
        // ObservableCollection: 동적 데이터 바인딩을 위한 Person 객체 리스트
        private ObservableCollection<Person> people;

        // 생성자: UI 초기화 및 데이터 로드
        public MainWindow()
        {
            InitializeComponent(); // XAML에서 정의된 UI 요소 초기화
            people = new ObservableCollection<Person>(); // 동적 컬렉션 객체 생성
            dataBoundComboBox.ItemsSource = people; // ComboBox에 데이터 소스 연결
            LoadData(); // 프로그램 시작 시 MSSQL 데이터 로드
        }

        // MSSQL에서 데이터를 읽어오는 메서드
        private void LoadData()
        {
            people.Clear(); // 기존 데이터 제거
            try
            {
                using (SqlConnection conn = new SqlConnection(connectionString)) // DB 연결 객체 생성 및 자동 해제
                {
                    conn.Open(); // 데이터베이스 연결 열기
                    string query = "SELECT Id, Name FROM People"; // People 테이블에서 데이터 조회 쿼리
                    using (SqlCommand cmd = new SqlCommand(query, conn)) // 쿼리 실행 명령 객체
                    {
                        using (SqlDataReader reader = cmd.ExecuteReader()) // 쿼리 결과 읽기
                        {
                            while (reader.Read()) // 결과 행을 하나씩 순회
                            {
                                // Person 객체 생성 후 ObservableCollection에 추가
                                people.Add(new Person 
                                { 
                                    Id = reader.GetInt32(0), // Id 열 읽기 (정수형)
                                    Name = reader.GetString(1) // Name 열 읽기 (문자열)
                                });
                            }
                        }
                    }
                }
                // 데이터가 있으면 첫 번째 항목 선택, 없으면 선택 해제
                dataBoundComboBox.SelectedIndex = people.Count > 0 ? 0 : -1;
            }
            catch (Exception ex) // 연결 실패, 쿼리 오류 등 예외 처리
            {
                MessageBox.Show($"데이터 로드 실패: {ex.Message}"); // 사용자에게 오류 메시지 표시
            }
        }

        // ComboBox 선택 변경 이벤트: 선택된 항목을 TextBox에 표시
        private void DataBoundComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (dataBoundComboBox.SelectedItem is Person selectedPerson) // 선택된 항목이 Person 객체인지 확인
                editNameTextBox.Text = selectedPerson.Name; // 선택된 이름 TextBox에 표시
            else
                editNameTextBox.Text = string.Empty; // 선택 해제 시 TextBox 비우기
        }

        // "추가" 버튼 클릭 이벤트: 새 항목을 MSSQL에 삽입
        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            string newName = newNameTextBox.Text.Trim(); // 입력된 이름 (공백 제거)
            if (string.IsNullOrEmpty(newName)) // 입력값이 비어 있는지 확인
            { 
                MessageBox.Show("이름을 입력하세요."); 
                return; // 비어 있으면 메서드 종료
            }
            try
            {
                using (SqlConnection conn = new SqlConnection(connectionString)) // DB 연결
                {
                    conn.Open(); // 데이터베이스 연결 열기
                    // 새 항목 삽입 후 생성된 ID 반환 쿼리
                    string query = "INSERT INTO People (Name) VALUES (@Name); SELECT SCOPE_IDENTITY();";
                    using (SqlCommand cmd = new SqlCommand(query, conn)) // 쿼리 실행 명령
                    {
                        cmd.Parameters.AddWithValue("@Name", newName); // 쿼리 파라미터로 이름 추가
                        int newId = Convert.ToInt32(cmd.ExecuteScalar()); // 삽입된 ID 반환
                        people.Add(new Person { Id = newId, Name = newName }); // UI에 새 항목 추가
                    }
                }
                newNameTextBox.Text = string.Empty; // 입력란 초기화
                MessageBox.Show("항목이 추가되었습니다."); // 성공 메시지 표시
            }
            catch (Exception ex) // 삽입 실패 시 예외 처리
            {
                MessageBox.Show($"추가 실패: {ex.Message}"); // 오류 메시지 표시
            }
        }

        // "수정" 버튼 클릭 이벤트: 선택된 항목을 MSSQL에서 업데이트
        private void UpdateButton_Click(object sender, RoutedEventArgs e)
        {
            if (dataBoundComboBox.SelectedItem is Person selectedPerson) // 선택된 항목 확인
            {
                string updatedName = editNameTextBox.Text.Trim(); // 수정된 이름 (공백 제거)
                if (string.IsNullOrEmpty(updatedName)) // 입력값이 비어 있는지 확인
                { 
                    MessageBox.Show("수정할 이름을 입력하세요."); 
                    return; // 비어 있으면 메서드 종료
                }
                try
                {
                    using (SqlConnection conn = new SqlConnection(connectionString)) // DB 연결
                    {
                        conn.Open(); // 데이터베이스 연결 열기
                        string query = "UPDATE People SET Name = @Name WHERE Id = @Id"; // 업데이트 쿼리
                        using (SqlCommand cmd = new SqlCommand(query, conn)) // 쿼리 실행 명령
                        {
                            cmd.Parameters.AddWithValue("@Name", updatedName); // 새 이름 파라미터
                            cmd.Parameters.AddWithValue("@Id", selectedPerson.Id); // 조건 ID 파라미터
                            cmd.ExecuteNonQuery(); // 쿼리 실행 (업데이트)
                        }
                    }
                    selectedPerson.Name = updatedName; // UI 객체 속성 업데이트
                    dataBoundComboBox.Items.Refresh(); // ComboBox UI 새로고침
                    MessageBox.Show("항목이 수정되었습니다."); // 성공 메시지 표시
                }
                catch (Exception ex) // 수정 실패 시 예외 처리
                {
                    MessageBox.Show($"수정 실패: {ex.Message}"); // 오류 메시지 표시
                }
            }
            else 
            { 
                MessageBox.Show("수정할 항목을 선택하세요."); // 선택된 항목 없음 경고
            }
        }
    }

    // Person 클래스: MSSQL 데이터와 매핑되는 데이터 모델
    public class Person
    {
        public int Id { get; set; } // 고유 식별자 (MSSQL의 Id 열과 매핑)
        public string Name { get; set; } // 사람 이름 (MSSQL의 Name 열과 매핑)
    }
}

설명: XAML은 UI를 정의하고, C#는 MSSQL과의 데이터 처리를 담당합니다. 주석은 각 줄의 역할과 동작을 명확히 설명합니다.

3. ObservableCollection이란?

ObservableCollection은 WPF에서 동적 데이터 바인딩에 사용되는 컬렉션 클래스입니다. List와 달리 INotifyCollectionChanged를 구현해 컬렉션 변경 시 UI를 자동 갱신합니다.

  • 주요 특징: 항목 추가/삭제 시 UI 실시간 반영.
  • 사용 목적: ComboBox.ItemsSource에 연결해 데이터 동기화.
  • 샘플 동작: people.Add()로 새 항목 추가 시 ComboBox에 즉시 표시.
  • 제한점: 속성 변경(예: Name)은 반영되지 않음. INotifyPropertyChanged 필요.

코드 분석: ObservableCollection을 사용해 MSSQL 데이터를 채우고, UI를 동적으로 업데이트합니다.

4. 결론

이 가이드에서는 WPF ComboBoxMSSQL 연동을 다뤘습니다. XAML로 UI를 구성하고, 상세 주석이 포함된 C# 코드로 데이터를 처리했습니다. ObservableCollection으로 동적 데이터 관리를 배웠습니다.

728x90